1、准备条件
(1)下载ztree,官网:http://www.ztree.me/
(2)下载datatable,官网:http://www.datatables.net/
2、开发
(1)引入js和css代码
<%--树形插件 --%>
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/zTree_v3/css/demo.css" type="text/css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/zTree_v3/css/zTreeStyle/zTreeStyle.css" type="text/css">
<%-- bootstarp tree Table插件 --%>
<link href="${pageContext.request.contextPath}/static/admin/bootstarp/bower_components/datatables-plugins/dataTables.bootstrap.css" rel="stylesheet" />
<script type="text/javascript" src="${pageContext.request.contextPath}/static/admin/bootstarp/bower_components/jquery/dist/jquery.min.js"></script>
<%--树形插件 --%>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/zTree_v3/js/jquery.ztree.core-3.5.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/zTree_v3/js/jquery.ztree.excheck-3.5.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/zTree_v3/js/jquery.ztree.exedit-3.5.js"></script>
<%-- bootstarp tree Table插件 --%>
<script src="${pageContext.request.contextPath}/static/admin/bootstarp/bower_components/datatables-plugins/jquery.dataTables.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/static/admin/bootstarp/bower_components/datatables-plugins/dataTables.bootstrap.js" type="text/javascript"></script>
(2)html代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>管理员列表</title>
<style type="text/css">
.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position:-144px 0; vertical-align:top; *vertical-align:middle}
</style>
</head>
<body style="background-color:#fff;">
<form action="" id="tab" name="tab">
<div >
<div>
<h3>商品类型</h3>
<div class="form-group form-inline well">
<div style="height:700px;">
<!-- 显示属性插件 -->
<div style="height:700px;">
<ul id="treeDemo" style="height:700px;"></ul>
</div>
<div>
<!-- 引入tableData数据 -->
<table id="tableData" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>类型名称</th>
<th>上级类型</th>
<th>排序</th>
<th>状态</th>
<th width="250px">操作</th>
</tr>
</thead>
<tbody>
<!-- <tr>
<th>商品类型</th>
<th>上级类型</th>
<th>排序</th>
<th>状态</th>
<th>删除 修改</th>
</tr> -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- 添加商品类型 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div>
<div>
<div>
<button type="button" data-dismiss="modal"
aria-hidden="true">×
</button>
<h4 id="myModalLabel">添加商品类型</h4>
</div>
<div>
<div>
<label for="name">上级商品类型:</label>
<input type="text" class="form-control disabled" id="disabledTextInput" readonly="readonly">
<input type="hidden" name="parentId" class="form-control disabled" id="pid" readonly="readonly">
</div>
<div>
<label for="name">类型名称:</label>
<input type="text" id="goodsTypeName" name="goodsTypeName" placeholder="请输入商品类型名称">
</div>
<div>
<label for="name">序号:</label>
<input type="text" id="sort" name="sort" placeholder="请输入排序序号">
</div>
<div>
<label>
<input type="radio" name="status" id="optionsRadios3" value="1" checked="checked"> 启用
</label>
<label>
<input type="radio" name="status" id="optionsRadios4" value="0"> 禁用
</label>
</div>
</div>
<div>
<button id="saveBtn" type="button" class="btn btn-primary">提交更改</button>
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
</form>
</body>
<script type="text/javascript">
var setting = {
edit: {
enable: true
},
data: {
simpleData: {
enable: true
}
},
callback: {
beforeDrag: beforeDrag,
beforeRemove: beforeRemove,
onRemove: onRemove,
/*onRename: onRename,*/
onClick: onClick
}
};
var zNodes =[
{ id:1, pId:0, name:"父节点 1", open:true},
{ id:11, pId:1, name:"叶子节点 1-1"},
{ id:12, pId:1, name:"叶子节点 1-2"},
{ id:13, pId:1, name:"叶子节点 1-3"},
{ id:2, pId:0, name:"父节点 2", open:true},
{ id:21, pId:2, name:"叶子节点 2-1"},
{ id:22, pId:2, name:"叶子节点 2-2"},
{ id:23, pId:2, name:"叶子节点 2-3"},
{ id:3, pId:0, name:"父节点 3", open:true},
{ id:31, pId:3, name:"叶子节点 3-1"},
{ id:32, pId:3, name:"叶子节点 3-2"},
{ id:33, pId:3, name:"叶子节点 3-3"}
];
setting.edit.showRenameBtn = false;
function beforeDrag(treeId, treeNodes) {
return true;
}
function showCode(str) {
var code = $("#code");
code.empty();
for (var i=0, l=str.length; i<l; i++) {
code.append("<li>"+str[i]+"</li>");
}
}
/*回调函数*/
/*添加*/
function onClick(e, treeId, treeNode) {
$("#disabledTextInput").val(treeNode.name);
$("#pid").val(treeNode.id);
$('input[name="goodsTypeName"]').val("");
$('input[name="sort"]').val("");
//弹窗口开发
$('#myModal').modal({
keyboard: true
});
}
/*添加方法*/
$("#saveBtn").click(function(){
var pid = $('input[name="parentId"]').val();
var pName = $('input[name="goodsTypeName"]').val();
var sort = $('input[name="sort"]').val();
var status = $('input[name="status"]:checked').val();
var path = "${path}/admin/goods/saveGoodsType";
$.ajax({
type:"POST",
url:path,
dataType:"json",
contentType: "application/json; charset=utf-8",
beforeSend:function(xhr) {
xhr.setRequestHeader("If-Modified-Since","0");
xhr.setRequestHeader("Cache-Control","no-cache");
},
data:JSON.stringify({"parentId":pid,"typeName":pName,"sort":sort,"status":status}), //接送格式
beforeSend:function(xhr) {
xhr.setRequestHeader("If-Modified-Since","0");
xhr.setRequestHeader("Cache-Control","no-cache");
},
success:function(result) {
if(result.status == "success"){
genGoodsTypes();
/*div隐藏*/
$('#myModal').modal('hide')
}
}
});
});
/*移除回调函数*/
function beforeRemove(treeId, treeNode) {
return confirm("确认删除 " + treeNode.name + "吗?");
}
function onRemove(e, treeId, treeNode) {
//树状Id treeNode.id
var path = "${path}/admin/goods/deleteGoodsType/"+treeNode.id;
deleteGoodsType(path);
}
/*拖拽事件*/
function onDrag(e, treeId, treeNodes){
alert(treeNodes);
}
/*生成表格数据*/
function genTableDatas(result){
$('#tableData').dataTable().fnClearTable();
$('#tableData').dataTable().fnDestroy();
var trs = "";
$.each(result, function(index,n) {
trs = trs + "<tr><td class='cs_test edit'>" + n.name + "</td><td>" + n.pname + "</td><td>" + n.sort + "</td><td>";
if(n.status == 1){
trs = trs + "<span class='label label-success'>启用</span></td>";
}else if(n.status == 0){
trs = trs + "<span class='btn btn-danger btn-xs'>禁用</span>";
}
trs = trs + "</td><td>"+
"<a onclick='javascript:editGoodsType(this.name);' class='btn btn-info btn-xs' name='${path}/admin/goods/updateGoodsType/"+n.id+"'><i class='fa fa-pencil'></i> 修改</a> "+
"<a onclick='javascript:deleteGoodsType(this.name);' class='btn btn-danger btn-xs' name='${path}/admin/goods/deleteGoodsType/"+ n.id +"'><i class='fa fa-trash'></i> 删除</a>"+
"</td></tr>";
});
$("#tableData tbody").html(trs);
/*生成表格列表*/
$("#tableData").dataTable({
retrieve: true,
paging: true, //分页
ordering: true, //是否启用排序
searching: true, //搜索
pageLength: 15, //首次加载的数据条数
bLengthChange: false,//屏蔽tables的一页展示多少条记录的下拉列表
language: {
search: '<button type="button" class="btn btn-success btn-sm"><i class="fa fa-search"></i> 搜索:</button>',//右上角的搜索文本,可以写html标签
paginate: {//分页的样式内容。
previous: "<<",
next: ">>",
first: "首页",
last: "尾页"
},
zeroRecords: "<font color='red'>没有记录...</font>",//table tbody内容为空时,tbody的内容。
//下面三者构成了总体的左下角的内容。
info: "总共_PAGES_ 页",//左下角的信息显示,大写的词为关键字。
infoEmpty: "0条记录",//筛选为空时左下角的显示。
infoFiltered: ""//筛选之后的左下角筛选提示,
},
paging: true,
pagingType: "full_numbers",//分页样式的类型
});
}
/*生成所有树*/
function genGoodsTypes(){
var url = "${path}/admin/goods/showGoodsTypes"
$.ajax({
type:"POST",
url:url,
dataType:"json",
beforeSend:function(xhr) {
xhr.setRequestHeader("If-Modified-Since","0");
xhr.setRequestHeader("Cache-Control","no-cache");
},
success:function(result) {
if(result.data.length != 0){
/*初始化树*/
$.fn.zTree.init($("#treeDemo"), setting, result.data);
/*生成表格数据*/
genTableDatas(result.data);
}
}
});
}
/*修改商品类型*/
function editGoodsType(path){
$("#tab").attr("action",path);
$("#tab").submit();
}
/*删除商品类型*/
function deleteGoodsType(path){
$.ajax({
type:"POST",
url:path,
dataType:"json",
beforeSend:function(xhr) {
xhr.setRequestHeader("If-Modified-Since","0");
xhr.setRequestHeader("Cache-Control","no-cache");
},
success:function(result) {
if(result.status == "success"){
genGoodsTypes();
}
}
});
}
$(document).ready(function(){
genGoodsTypes();
});
</script>
</html>
(3)部分java代码
controller层代码
package com.xtxq.controller.goods;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xtxq.common.SystemConstants;
import com.xtxq.controller.base.BaseController;
import com.xtxq.domain.goods.GoodsProperty;
import com.xtxq.domain.goods.GoodsType;
import com.xtxq.domain.goods.GoodsTypeProperty;
import com.xtxq.service.goods.GoodsInfoService;
import com.xtxq.service.goods.GoodsPropertyService;
import com.xtxq.service.goods.GoodsTypePropertyService;
import com.xtxq.service.goods.GoodsTypeService;
/**
*
* @ClassName: GoodsTypeController
* @Description: TODO(商品分类)
* @author zwcheng 1054900400@qq.com
* @date 2016年1月7日 下午8:47:36
*
*/
@Controller
@RequestMapping("/admin/goods/")
public class GoodsTypeController extends BaseController<GoodsType>{
private Logger logger = Logger.getLogger(GoodsTypeController.class);
@Autowired
private GoodsInfoService goodsInfoService ;
@Autowired
private GoodsPropertyService goodsPropertyService ;
@Autowired
private GoodsTypeService goodsTypeService ;
@Autowired
private GoodsTypePropertyService goodsTypePropertyService ;
/**
* 重定向路径
*/
private static String REDIRECT_PATH = "redirect:/admin/goods/goodsTypeList";
/**
* 获取子分类
* @param id
* @param response
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="goodsInfo/getChildGoodsType/{id}",produces = "text/html;charset=UTF-8")
public String getChildGoodsType(@PathVariable String id,HttpServletResponse response) throws Exception{
System.out.println(id);
List<GoodsType> list = goodsTypeService.getChildrens(id) ;
String msg = JSON.toJSONString(list) ;
return msg ;
}
/**
* 通过商品子类别查看该子类下面的所有公共属性
* @param typeId
* @param response
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="goodsInfo/getPropertyByTypeId/{typeId}",produces = "text/html;charset=UTF-8")
public String getPropertyByTypeId(@PathVariable String typeId,HttpServletResponse response) throws Exception {
List<GoodsTypeProperty> list = goodsTypePropertyService.getPropertyByTypeId(typeId);
List<GoodsProperty> goodsProperties = new ArrayList<GoodsProperty>();
for(GoodsTypeProperty goodsTypeProperty:list) {
GoodsProperty property = new GoodsProperty() ;
String src= goodsTypeProperty.getPropertySrc() ;
String[] values = goodsInfoService.splitPath(src) ;
property = goodsTypeProperty.getGoodsProperty() ;
goodsProperties.add(property) ;
for(String value:values) {
goodsProperties.add(goodsPropertyService.getById(value)) ;
}
}
String msg = JSON.toJSONString(goodsProperties) ;
System.out.println(msg);
return msg ;
}
@RequestMapping(value="goodsTypeList")
public String listGoodsType()throws Exception{
return genGoodsTypePath("goodsTypeList");
}
/**
* 显示所有商品
* @return
* @throws Exception
*/
@RequestMapping(value="showGoodsTypes",method=RequestMethod.POST)
@ResponseBody
public String showGoodsTypes() throws Exception {
JSONObject json = new JSONObject();
JSONArray jsons = new JSONArray();
try {
this.goodsTypeService.getAllChildsGoodsTypes("0", jsons); //顶级商品类型
json.put("data", jsons);
} catch (Exception e) {
this.logger.error("范问商品类型发生异常。。。");
}
return json.toJSONString();
}
/**
* 删除
*/
@RequestMapping(value="deleteGoodsType/{id}",method=RequestMethod.POST)
@ResponseBody
public String deleteGoodsType(@PathVariable String id) throws Exception{
Map<String,Object> maps = new HashMap<String, Object>();
try {
goodsTypeService.deleteGoodsType(id);
maps = ajaxJsonMessage("success","删除商品类型成功!");
} catch (Exception e) {
logger.error("删除发生错误!");
e.printStackTrace();
maps = ajaxJsonMessage("fail","删除商品失败!");
}
return JSONObject.toJSONString(maps);
}
/**
* 保存商品类型
* @param goodsType
* @return
* @throws Exception
*/
@RequestMapping(value="saveGoodsType",method=RequestMethod.POST)
@ResponseBody
public String saveGoodsType(@RequestBody GoodsType goodsType) throws Exception{
Map<String,Object> maps = new HashMap<String, Object>();
try {
goodsTypeService.add(goodsType);
maps = ajaxJsonMessage("success","添加商品类型成功!");
} catch (Exception e) {
logger.error("添加商品类型发生错误!");
e.printStackTrace();
maps = ajaxJsonMessage("fail","添加商品失败!");
}
return JSONObject.toJSONString(maps);
}
/**
* 修改商品类型页面
*/
@RequestMapping(value="updateGoodsType/{id}",method=RequestMethod.GET)
public String editGoodsType(@PathVariable String id,Model model) throws Exception{
GoodsType goodsType = goodsTypeService.getById(id);
GoodsType pgoodsType = goodsTypeService.getById(goodsType.getParentId());
goodsType.setPname(pgoodsType.getTypeName());
model.addAttribute("goodsType", goodsType);
return genGoodsTypePath("editGoodsType");
}
@RequestMapping(value="updateGoodsType",method=RequestMethod.POST)
public String editGoodsType(GoodsType goodsType) throws Exception{
GoodsType goodsType_db = goodsTypeService.getById(goodsType.getId());
goodsType_db.setStatus(goodsType.getStatus());
goodsType_db.setSort(goodsType.getSort());
goodsType_db.setTypeName(goodsType.getTypeName());
goodsTypeService.update(goodsType_db);
return REDIRECT_PATH;
}
/**
* 生成商品类型路径
* @param path
* @return
*/
private String genGoodsTypePath(String path){
return SystemConstants.GoodsTypeConstant.GOODS_TYPE_ROOT_PATH + path;
}
}
service层代码(涉及到递归方法)
package com.xtxq.service.impl.goods;
import java.util.List;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xtxq.basic.SystemException;
import com.xtxq.basic.SystemPager;
import com.xtxq.dao.goods.GoodsTypeMapper;
import com.xtxq.domain.goods.GoodsType;
import com.xtxq.domain.goods.GoodsTypeExample;
import com.xtxq.service.goods.GoodsTypeService;
import com.xtxq.utils.UUIDUtils;
/**
* @ClassName: GoodsTypeServiceImpl
* @Description: TODO(商品分类的业务逻辑实现)
* @author zwcheng 1054900400@qq.com
* @date 2016年1月7日 下午8:50:03
*/
@Service
public class GoodsTypeServiceImpl implements GoodsTypeService{
@Autowired
private GoodsTypeMapper goodsTypeDao;
/**
* 储存商品大类
*/
public void add(GoodsType t) throws Exception {
GoodsType goodsType2 = getByName(t.getTypeName());
if(null != goodsType2){
throw new SystemException("这个商品的类型名称已经存在!");
}
t.setId(UUIDUtils.genUUID()); //生成主键
goodsTypeDao.insert(t);
}
/**
* 删除商品大类
*/
public void deleteById(String id) throws Exception {
goodsTypeDao.deleteByPrimaryKey(id);
}
/**
* 更新商品大类
*/
public void update(GoodsType t) throws Exception {
goodsTypeDao.updateByPrimaryKey(t) ;
}
/**
* 按照商品类别的id查询
*/
public GoodsType getById(String id) throws Exception {
if(id!="" && id != null) {
return goodsTypeDao.selectByPrimaryKey(id);
} else {
return null ;
}
}
/**
* 按照商品大类的姓名去查询
*/
public GoodsType getByName(String name) throws Exception {
//按照名称查找
GoodsTypeExample example = new GoodsTypeExample();
GoodsTypeExample.Criteria criteria = example.createCriteria();
criteria.andTypeNameEqualTo(name);
List<GoodsType> goodsTypeList = goodsTypeDao.selectByExample(example);
if(null != goodsTypeList && !goodsTypeList.isEmpty()){
return goodsTypeList.get(0);
}
return null;
}
/**
*获取所有的分类
*/
public List<GoodsType> list() throws Exception {
GoodsTypeExample example = new GoodsTypeExample() ;
return goodsTypeDao.selectByExample(example);
}
/**
* 分页获取所有的商品类型
*/
public List<GoodsType> findNotices(int currentpage)
throws Exception {
GoodsTypeExample goodsTypeExample = new GoodsTypeExample() ;
goodsTypeExample.setLimitStart(currentpage-1);
goodsTypeExample.setLimitEnd(SystemPager.getPagesize());
List<GoodsType> list = goodsTypeDao.selectByExample(goodsTypeExample) ;
return list;
}
/**
* 获取所有类型的计数
*/
public int getCount() throws Exception {
GoodsTypeExample example = new GoodsTypeExample() ;
return goodsTypeDao.countByExample(example) ;
}
/**
* 判断是否有子节点
*/
public boolean hasChildren(String id) throws Exception {
int count = goodsTypeDao.hasChildren(id) ;
if(count>0) {
return true ;
}else {
return false ;
}
}
/**
* 获取所有的大类
*/
public List<GoodsType> getGoodsTypes() throws Exception{
return goodsTypeDao.getGoodsTypes() ;
}
/**
* 获得某一个大类下面的所有子类
*/
public List<GoodsType> getChildrens(String id) throws Exception{
GoodsTypeExample example = new GoodsTypeExample();
GoodsTypeExample.Criteria criteria = example.createCriteria();
System.out.println(id);
criteria.andParentIdEqualTo(id);
List<GoodsType> goodsTypeList = goodsTypeDao.selectByExample(example);
if(goodsTypeList!=null) {
return goodsTypeList;
} else {
return null ;
}
}
/**
* 通过父亲Id获取商品类型
* @param pid 父亲Id
* @return
* @throws Exception
*/
public List<GoodsType> getChildsGoodsTypes(String pid) throws Exception{
GoodsTypeExample goodsTypeExample = new GoodsTypeExample();
GoodsTypeExample.Criteria criteria = goodsTypeExample.createCriteria();
criteria.andParentIdEqualTo(pid);
return this.goodsTypeDao.selectByExample(goodsTypeExample);
}
public JSONArray getChildsGoodsTypes(String pid, JSONArray jsons) throws Exception {
List<GoodsType> childs = getChildsGoodsTypes(pid);
GoodsType pgoodsType = getById(pid);
for (GoodsType goodsType : childs) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", goodsType.getId());
jsonObject.put("pId", pid);
jsonObject.put("name", goodsType.getTypeName());
jsonObject.put("pname", pgoodsType.getTypeName());
jsonObject.put("sort", goodsType.getSort());
jsonObject.put("status", goodsType.getStatus());
jsonObject.put("open", Boolean.valueOf(true));
jsons.add(jsonObject);
}
return jsons;
}
/**
* 获取所有商品类型
* @param pid
* @param jsons
* @return
* @throws Exception
*/
public JSONArray getAllChildsGoodsTypes(String pid, JSONArray jsons) throws Exception{
List<GoodsType> childs = getChildsGoodsTypes(pid);
if ((childs != null) && (!childs.isEmpty()))
for (GoodsType goodsType : childs) {
jsons = getChildsGoodsTypes(goodsType.getId(), jsons);
getAllChildsGoodsTypes(goodsType.getId(), jsons);
}
else {
jsons = getChildsGoodsTypes(pid, jsons);
}
return jsons;
}
/**
* 通过Id删除所有商品(递归删除)
* @param id 主键
* @throws Exception
*/
public void deleteGoodsType(String id) throws Exception{
//TODO 查询所有与商品类型关联表
//递归删除所有子节点
List<GoodsType> coodsTypes = getChildsGoodsTypes(id);
if(null != coodsTypes && !coodsTypes.isEmpty()){
for(GoodsType goodsType : coodsTypes){
deleteGoodsType(goodsType.getId());
deleteById(goodsType.getId());
}
}else{
deleteById(id);
}
deleteById(id); //删除
}
}
3、运行后效果图