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 [email protected] * @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 [email protected] * @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、运行后效果图