需求是需要做一个国家信息的树形结构图,那么就避免不了使用树状结构的插件,而用的比较多的插件就是Ztree和Jstree,个人在这里强烈推荐Ztree,
原因如下:1、Ztree的插件文档全中文解释,毕竟是国产插件,所以对于英语不太好的同学来说,会减少很多麻烦,而Jstree全英文
2、Ztree的demo比Jstree更加详细,更能够去理解插件中各种事件,属性的使用
下面直接放图:
一、JS页面;需要引用的ztree的包我就不累赘了,不过推荐一个网站 http://www.bootcdn.cn/ 不用下载包,直接复制链接就可以
1)首先是异步逐级加载数据,即点击一个节点加载一层数据,不点击就不会去查询该节点下的子节点,优点:后台代码逻辑简单,只需要将节点ID作为parentId去查即可,缺点就是对于后面的模糊搜索来说,如果你的某个节点下的数据没有打开也就是说没有去后台查,那模糊搜索是搜索不到该节点下的数据信息的,比如你没有打开湖南省这个节点,湖南省节点下有长沙市这个节点信息,但是因为你没有打开所以不会去后台查询,那么你模糊搜索长,是不会显示出湖南省下长沙市的节点信息的。
<script type="text/javascript">
(function () { //下面的参数如果有不懂的,可以结合文档查询,很详细
var setting = {
async: {
enable: true, //是否异步
url: "geographic/getAllInfo",
autoParam: ["id"], //传的参数
},
view: {
expandSpeed: "",
addHoverDom: addHoverDom,
removeHoverDom: removeHoverDom,
selectedMulti: false,
showIcon: true,
showLine: true,
fontCss:getFontCss
},
edit: {
enable: true
},
callback: {
onClick: zTreeOnOnClick,
beforeRemove: beforeRemove,
beforeRename: beforeRename
},
data: {
simpleData: {
enable: true,
idKey: "id",
pIdKey: "pId",
rootPId: 0
}
}
};
$(function () {
$.ajax({
type: "POST",
url: "geographic/getAllInfo",
dataType: "json",
success: function (data) {
$.fn.zTree.init($("#geographicInfoTree"), setting, data.data);
}
})
key = $("#key");
key.bind("focus", focusKey)
.bind("blur", blurKey)
.bind("propertychange", searchNode)
.bind("input", searchNode);
});
function zTreeOnOnClick(even, treeId, treeNode) {
var treeObj = $.fn.zTree.getZTreeObj(treeId);
var node = treeObj.getNodeByTId(treeNode.tId);
if (!node.children) {
$.ajax({
type: "POST",
url: "geographic/getAllInfo",
data: {
id: treeNode.id
},
dataType: "json",
success: function (data) {
if (data) {
newNode = treeObj.addNodes(node, data);
}
},
error: function () {
layer.msg('Operation failed!', {icon: 2, time: 2000});
}
});
}
}
2)实现鼠标放到节点上,就会出现增加,删除,修改的图标(用到事件),其中删除修改按钮是Ztree自带的,增加的话需要我们手动去写按钮代码
function beforeRemove(treeId, treeNode) {
$.ajax({
type: "POST",
url: "geographic/deleteNode",
data: {
id: treeNode.id
},
dataType: "json",
success: function (data) {
if (data === 'success') {
window.parent.layer.close(window.parent.layer.index);
layer.msg('Delete successful!', {icon: 1, time: 1000});
} else {
layer.msg('Delete failed!', {icon: 2, time: 2000});
}
}
})
}
function beforeRename(treeId, treeNode, newName) {
if (!newName) {
layer.msg('The name can not be empty!', {icon: 2, time: 2000});
return false;
}
$.ajax({
type: "post",
url: "geographic/updateInfo",
data: {
id: treeNode.id,
name: newName
},
dataType: "json",
success: function (data) {
if (data == 'success') {
window.parent.layer.close(window.parent.layer.index);
layer.msg('Update successful!', {icon: 1, time: 1000});
} else {
layer.msg('Update failed!', {icon: 2, time: 2000});
}
}
});
}
var newCount = 1;
function addHoverDom(treeId, treeNode) {
var sObj = $("#" + treeNode.tId + "_span");
if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0) {
return;
}
var addStr = "<span class='button add' id='addBtn_" + treeNode.tId
+ "' title='add node' οnfοcus='this.blur();'></span>";
sObj.after(addStr);
var btn = $("#addBtn_" + treeNode.tId);
var id;
if (btn) {
btn.bind("click", function () {
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
var name = "new name" + (newCount++);
$.post(
"geographic/addInfo",
{
id: treeNode.id,
name: name,
},
function(data){
id = data; //需要从后台返回增加的节点的ID
zTree.addNodes(treeNode, { //增加一个节点后需要将树刷新,需用到此方法,数据只需要满足 zTree 的节点数据必需的属性即可,具体请参考API
id:id,
pId: treeNode.id,
name: name
});
}
);
});
return false;
} else {
return false;
}
};
function removeHoverDom(treeId, treeNode) {
$("#addBtn_" + treeNode.tId).unbind().remove();
};
3)模糊搜索(此处为楼主借鉴http://blog.csdn.net/wangjingna/article/details/50488921)点击打开链接
var lastValue = "", nodeList = [], fontCss = {};
function callNumber(){
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
if(nodeList.length){
zTree.selectNode(nodeList[0],false );
document.getElementById("key").focus();
}else if(nodeList.length === 0){
zTree.cancelSelectedNode();
}
if(document.getElementById("key").value ===""){
zTree.cancelSelectedNode();
}
}
function focusKey(e) {
if (key.hasClass("empty")) {
key.removeClass("empty");
}
}
function blurKey(e) {
if (key.get(0).value === "") {
key.addClass("empty");
}
}
function searchNode(e) {
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
var value = $.trim(key.get(0).value);
var keyType = "name";
if (key.hasClass("empty")) {
value = "";
}
if (lastValue === value) {return;}
lastValue = value;
if (value === ""){
updateNodes(false);
return;
}
updateNodes(false);
nodeList = zTree.getNodesByParamFuzzy(keyType, value);
updateNodes(true); }
unction updateNodes(highlight){
var zTree = $.fn.zTree.getZTreeObj("geographicInfoTree");
for( var i=0, l=nodeList.length; i<l; i++) {
nodeList[i].highlight = highlight;
zTree.expandNode(nodeList[i].getParentNode(), true, false, false);
zTree.updateNode(nodeList[i]);
}
}
function getFontCss(treeId, treeNode) {
return (!!treeNode.highlight) ? {color:"#A60000", "font-weight":"bold"} : {color:"#333", "font-weight":"normal"};
}})();
二、controller层
@Controller @RequestMapping("/geographic") public class GeographicInfoController extends BaseController { @Autowired private GeographicInfoService geographicInfoService; @RequestMapping("/addInfo") @ResponseBody public String addInfo(@RequestParam(value = "id", defaultValue = "0") String id,String name) { String str = geographicInfoService.addInfo(name, id); return str; } @RequestMapping("/updateInfo") @ResponseBody public String updateInfo(GeographicInfoDO geographicInfoDO) { boolean flag = geographicInfoService.updateInfo(geographicInfoDO); return flag ? "success" : "false"; } @RequestMapping(value = "/getAllInfo") @ResponseBody public List getNodeInfo(@RequestParam(value = "id", defaultValue = "0") String id) { List<Map<String, Object>> list = geographicInfoService.getChildrenInfo(id); return list; } @RequestMapping(value = "/deleteNode") @ResponseBody public String deleteNodeInfo(String id){ boolean flag =geographicInfoService.deleteNodeInfo(id); return flag ? "success" : "false"; } @RequestMapping(value = "/getListPage") public String getListPage(){ return "geographicInfo/geographicInfoList"; } }三、service层
@Service public class GrographicServiceImpl implements GeographicInfoService { @Autowired private GrographicInfoDAO grographicInfoDAO; @Override public String addInfo(String name, String parent_id) { GeographicInfoDO geographicInfoDO = new GeographicInfoDO(); geographicInfoDO.setId(DataBaseUtil.getTimeUUID()); //楼主采用手动添加ID而不是自增加,因为前台需要返回一个增加节点的ID,这样很方便,当然还有其他的返回ID方法,可以自行百度
geographicInfoDO.setParentId(parent_id); geographicInfoDO.setName(name); geographicInfoDO.setStatus("1"); grographicInfoDAO.save(geographicInfoDO); return geographicInfoDO.getId(); } @Override public boolean updateInfo(GeographicInfoDO geographicInfoDO) { int acount = grographicInfoDAO.update(geographicInfoDO); if(acount > 0){ return true; } return false; } @Override public List<Map<String,Object>> getChildrenInfo(String id) { return grographicInfoDAO.findGeographicChildrenByParentId(id); } @Override public boolean deleteNodeInfo(String id) { int acount = grographicInfoDAO.delete(id); if(acount > 0){ return true; } return false; } }四、DO层
public class GeographicInfoDO extends BaseDo<String, String> { private String parentId; private String name; private String status; public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public String getParentId() { return parentId; } public void setParentId(String parentId) { this.parentId = parentId; } public String getName() { return name; } public void setName(String name) { this.name = name; } }五、时区
public class DataBaseUtil { private static final Logger logger = LoggerFactory.getLogger(DataBaseUtil.class); private static final String DATABASE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; private static final String DATABASE_DATE_NOTTIME_FORMAT = "yyyy-MM-dd"; private static final String DATABASE_SHORT_UUID_FORMAT = "yyMMddHHmmss"; public DataBaseUtil() { } public static String getUUID() { return StringUtil.replace(UUID.randomUUID().toString(), "-", ""); } public static String getTimeUUID() { return "K" + (new SimpleDateFormat("yyMMddHHmmss")).format(new Date()) + getStringRandom(7); } public static Date getDateByString(String date) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (date != null && date.length() >= "yyyy-MM-dd HH:mm:ss".length()) { try { return dateFormat.parse(date); } catch (Exception var3) { logger.warn("[databaseUtil] converter to Data error,", var3); return null; } } else { return null; } } public static String getDateStrByDate(Date date) { return date != null && !StringUtil.isBlank("yyyy-MM-dd HH:mm:ss") ? (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.SIMPLIFIED_CHINESE)).format(date) : ""; } public static String getDateStrByNow() { return getDateStrByDate(new Date()); } public static Date getDateByStringNotTime(String date) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); if (date != null && date.length() >= "yyyy-MM-dd".length()) { try { return dateFormat.parse(date); } catch (Exception var3) { logger.warn("[databaseUtil] converter to Data error,", var3); return null; } } else { return null; } } public static String getDateStrNotTimeByDate(Date date) { return date != null && !StringUtil.isBlank("yyyy-MM-dd") ? (new SimpleDateFormat("yyyy-MM-dd", Locale.SIMPLIFIED_CHINESE)).format(date) : ""; } public static String getDateStrNotTimeByNow() { return getDateStrNotTimeByDate(new Date()); } public static String getStringRandom(int length) { String val = ""; Random random = new Random(); for(int i = 0; i < length; ++i) { val = val + String.valueOf(random.nextInt(10)); } return val; } public static void main(String[] args) { System.out.println(getTimeUUID()); } }