菩提本无树

        前阵子空闲的时候写了一个关于全国省市区树形结构相关的项目,由于技术文中途难产了,因此直接贴代码吧(该博主很懒,什么都没留下)

        树形泛型父类,子类可以继承该父类,一般一个树形结构的面向对象建模是这样的:id,parentId(hibernate等持久化框架有规定id是要实现可序列化接口),childs(自身引用)。

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

public abstract class Treebean<PK extends Serializable,T extends Treebean<PK,?>> implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1878885497744083173L;
    
    protected PK id;
    protected PK parentId;
    
    protected LinkedList<T> childs = new LinkedList<T>();

    public PK getId() {
        return id;
    }

    public void setId(PK id) {
        this.id = id;
    }

    public PK getParentId() {
        return parentId;
    }

    public void setParentId(PK parentId) {
        this.parentId = parentId;
    }
    
    protected Treebean<PK,T> addChild(T child) {
        this.childs.add(child);
        return this;
    }
    
    protected void buildTree(List<Treebean<PK,T>> sourceList, List<Treebean<PK,T>> childs,
            PK parentId) {
        for (Treebean<PK,T> tree : sourceList) {
            if (checkParent(tree, parentId)) {
                childs.add(tree);
                buildTree(sourceList, (List<Treebean<PK, T>>) tree.childs,tree.id);
            }
        }
    }
    
    public LinkedList<T> getChilds() {
        return childs;
    }

    protected abstract boolean checkParent(Treebean<PK,T> tree, PK parentId);
    
    protected boolean hasChild() {
        return !this.childs.isEmpty();
    }
    
    

}

        相关的表数据如下,一般的树形表设计,博主是建议要有root节点的,类似省市区这种结构,根节点可以是中国。

204354_PLTt_1427420.png

        相关的实体类如下:

public class Province extends Treebean<Integer,Province> {
    
    /**
     * 
     */
    private static final long serialVersionUID = 8505185101020732530L;
    
    private String name;
    
    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }

    
    
    public static Province getRoot(){
        Province root = new Province();
        root.setId(1);
        root.setName("中国");
        return root;
    }

    @Override
    public String toString() {
        return "Province [name=" + name + ", id=" + id + ", parentId="
                + parentId + "]";
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Province other = (Province) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }


    @Override
    protected boolean checkParent(Treebean<Integer, Province> tree, Integer parentId) {
           Integer pId = tree.parentId;
           return pId != null && parentId.intValue() == pId;
    }
    
    
}

外部调用,首先是dao,使用的jdbctemplate,把地区表的数据查出(这里使用了groovy):

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.tcsoft.treedata.bean.Province;
@Repository
class ProvinceDao extends AbstractJdbcTemplateDao {
    
    public List<Province> getAllList() {
        String sql = "select * from tbl_province";
        return this.jdbcTemplate.query(sql, new ProvinceRowMapper());
    }

private class ProvinceRowMapper implements RowMapper<Province> {

    @Override
    public Province mapRow(ResultSet rs, int rowNum) throws SQLException {
        // TODO Auto-generated method stub
        Province provice = new Province(
            id:rs.getInt("id"),
            name:rs.getString("name"),
            parentId:rs.getInt("parent_id")
        );
        return provice;
    }
    
}

}

业务类,主要用于构造所必须的树形结构(备注,像省市区这种基本不会变动的数据,一般都需要加入缓存,目前缓存框架使用的是ehcache)

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service

import com.tcsoft.treedata.bean.Province
import com.tcsoft.treedata.dao.ProvinceDao
@Service
class ProvinceServiceImpl implements ProvinceService {
    
    @Autowired
    private ProvinceDao provinceDao;
    
    @Cacheable("PROVINCE_Cache")
    public Province getAllProvinceTree() {
        Province root = Province.getRoot();
        List<Province> sourceList = this.provinceDao.getAllList();
        root.buildTree(sourceList, root.getChilds(), 1);
        return root;
    }
    
}

ehcache配置:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false"
    monitoring="autodetect" dynamicConfig="true">
    
    <diskStore path="java.io.tmpdir"/>
    
    <defaultCache maxElementsInMemory="10000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU" />
    
    <!-- DEFAULT CACHE -->
    <cache name="DEFAULT_CACHE" maxElementsInMemory="10000" maxElementsOnDisk="10000"
        eternal="false" timeToIdleSeconds="60" timeToLiveSeconds="60"
        memoryStoreEvictionPolicy="LFU">
    </cache>
    
    
    <cache name="PROVINCE_Cache" maxElementsInMemory="1000" maxElementsOnDisk="0"
        eternal="false" timeToIdleSeconds="120000" timeToLiveSeconds="120000"
        memoryStoreEvictionPolicy="LFU">
    </cache>
    
    <!--terracottaConfig url="localhost:9510"/ -->
</ehcache>

后台递归展示测试类:

import java.util.Collection;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.tcsoft.treedata.bean.Province;
import com.tcsoft.treedata.service.ProvinceService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class TreeTest {
    
    @Autowired
    private ProvinceService provinceService;
    
    @Test
    public void testGetAllList() {
        Province root = this.provinceService.getAllProvinceTree();
        showTreeList_2(root.getChilds(),  "┣");
    }
    
    private void showTreeList_2(Collection<Province> topList, String prefix) {
        for(Province top : topList){
            // 顶点
            System.out.println( prefix  + top.getName());
            // 子树
            showTreeList_2(top.getChilds(), " " + prefix);
        }
    }
}

前台使用ztree展示数型结构(相当强大的树形控件)

<script type="text/javascript">
$(function(){
    var setting = {
        data: {key: {children: "childs"}}
    };
    $.post("http://127.0.0.1:8080/treedata/tree",function(data){
        $.fn.zTree.init($("#provinceTree"), setting, data);
    },"json");
    
});
</script>

后台使用spring mvc responsebody返回:

@RequestMapping("/tree")
    @ResponseBody
    public Province getTree(){
        return this.provinceService.getAllProvinceTree();
    }


转载于:https://my.oschina.net/u/1427420/blog/369914

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值