该案例是实际开发中运用,java递归查询分类及分类下所有子分类。
代码走起:
1.jsp页面布局样式这里不再介绍,js业务逻辑展示分类树形结构如下:
/**
* 商品分类操作
*/
/**
* 初始化
*/
$(function(){
//加载树
reloadTree();
});
});
/**
* 加载树
*/
function reloadTree(){
//加载列表树
initGoodsCateTree(1);
//加载添加分类弹框树
initGoodsCateTree(2);
//加载编辑分类弹框树
initGoodsCateTree(3);
}
/**
* 初始化商品分类树
* type:1列表树2弹框树
*/
function initGoodsCateTree(type){
$.ajax({
type:"post",
url: "queryAllCate.htm",
async:false, //同步
cache:false, //清除缓存
dataType:"json",
success: function(data){
if(type==1){
//加载列表树
$("#cat_tree").html("");
}else if(type==2){
//加载添加分类弹框树
$("#parentCate_add .tree").html("");
}else if(type==3){
//加载编辑分类弹框树
$("#parentCate_edit .tree").html("");
}
loadGoodsCateTree(data,0,type);
//加载分类树样式
initGoodsCateTreeCss();
}
});
}
/**
* 递归树
* datas:商品分类数据
* parendId:父节点默认为0
* type:1列表树2弹框树
*/
function loadGoodsCateTree (datas,parentId,type){
if(datas!=null){
if(parentId==0){
for(var i=0;i<datas.length;i++){
var data=datas[i];
if(type==1){
//拼接列表树
$("#cat_tree").append(goodsCateHtml(data));
}else if(type==2){
//拼接添加分类弹框树
$("#parentCate_add .tree").append(selectGoodsCateHtml(data,"cateAdd"));
}else if(type==3){
//拼接编辑分类弹框树
$("#parentCate_edit .tree").append(selectGoodsCateHtml(data,"cateEdit"));
}
//递归所有子节点
for(var j=0;j<data.cateVos.length;j++){
var dataCate=data.cateVos[j];
loadGoodsCateTree(dataCate,dataCate.catId,type);
}
}
}else{//非父节点
var data=datas;
if(type==1){
//拼接列表树
$("#cat_tree").append(goodsCateHtml(data));
}else if(type==2){
//拼接添加分类弹框树
$("#parentCate_add .tree").append(selectGoodsCateHtml(data,"cateAdd"));
}else if(type==3){
//拼接编辑分类弹框树
$("#parentCate_edit .tree").append(selectGoodsCateHtml(data,"cateEdit"));
}
//递归所有子节点
for(var j=0;j<data.cateVos.length;j++){
var dataCate=data.cateVos[j];
loadGoodsCateTree(dataCate,dataCate.catId,type);
}
}
}
}
/**
* 拼接商品分类列表树
* data:商品分类数据
*/
var goodsCateHtml=function (data) {
var html="";
//默认只展示父节点
if(data.catGrade==1){
html= '<div depath="'+data.catGrade+'" class="clear_cat row" cid="'+data.catId+'" pid="'+data.catParentId+'" >'
}else{
html= '<div depath="'+data.catGrade+'" class="clear_cat row" style="display:none;" cid="'+data.catId+'" pid="'+data.catParentId+'" >'
}
html= html+
'<table>'+
'<tbody>'+
'<tr>'+
'<td class="td1">'+
'<div >'+
'<span class="handle-icon">'+
'<img src="images/cticon2.png" alt="收起子分类" title="收起子分类" class="handle-hide" app="desktop" style="display: none;">'+
'<img src="images/cticon1.png" alt="展开子分类" title="展开子分类" class="handle-show" app="desktop">'+
'</span>'+
'<a >'+data.catName+'</a>'+
'</div>'+
'</td>'+
'<td class="td2"><span class="quiet">['+data.typeName+']</span></td>'+
'<td class="td3"><b>'+data.catSort+'</b></td>'+
'<td class="td4">'+
'<a href="javascript:void(0);" class="addSubNote" οnclick="addSubCate('+data.catId+','+data.catGrade+',\''+data.catName+'\')">增加子类</a>'+
'<a href="javascript:void(0);" οnclick="editGoodsCate('+data.catId+')">编辑</a>'+
'<a href="javascript:void(0);" οnclick="deleteGoodsCate('+data.catId+')">删除</a>'+
'</td>'+
'<td class="td5">'+
'<input type="hidden" value="'+data.catIsFinal+'"/>'+
'</td>'+
'</tr>'+
'</tbody>'+
'</table>'+
'</div>';
return html;
}
/**
* 加载商品分类树样式
*/
function initGoodsCateTreeCss(){
$(".clear_cat").each(function(){
//判断是否是末级
var isM = $(this).find(".td5 input").val();
if(isM == 1){
//末级节点不展示图标
$(this).find(".handle-icon").remove();
//不显示添加子类
$(this).find(".addSubNote").remove();
}else {
//非末级节点不显示类型名称
$(this).find(".quiet").html(" ");
}
//子节点添加样式
var depath = $(this).attr("depath");
$(this).find(" .td1>div").css("padding-left",20*depath+"px");
});
}
/**
* 拼接商品分类弹框树
* data:商品分类数据
*/
var selectGoodsCateHtml=function (data,divId){
var html="";
//默认只展示父节点
if(data.catGrade==1){
html= '<div depath="'+data.catGrade+'" class="clear_cat row" cid="'+data.catId+'" pid="'+data.catParentId+'" >'
}else{
html= '<div depath="'+data.catGrade+'" class="clear_cat row" style="display:none;" cid="'+data.catId+'" pid="'+data.catParentId+'" >'
}
html= html+
'<table>'+
'<tbody>'+
'<tr>'+
'<td class="td1">'+
'<div >'+
'<span class="handle-icon">'+
'<img src="images/cticon2.png" alt="收起子分类" title="收起子分类" class="handle-hide" app="desktop" style="display: none;">'+
'<img src="images/cticon1.png" alt="展开子分类" title="展开子分类" class="handle-show" app="desktop">'+
'</span>'+
'<a href="javascript:void(0);" οnclick="selectParentCate('+data.catId+','+data.catGrade+',\''+data.catName+'\',\''+divId+'\')" >'+data.catName+'</a>'+
'</div>'+
'</td>'+
'<td class="td5">'+
'<input type="hidden" value="'+data.catIsFinal+'"/>'+
'</td>'+
'</tr>'+
'</tbody>'+
'</table>'+
'</div>';
return html;
}
/**
* 点击上级分类显示弹框树
*/
function showParentCate(){
if($(".cateTree").css("display")=="none"){
$(".cateTree").show();
}else{
$(".cateTree").hide();
}
}
/**
*点击上级分类显示弹框树,选择任意一个上级分类名称赋值至文件框
* parentId:父节点id
* parentGrade:父节点层级
* parentName:父节点名称
* divId:div标识判断是添加分类弹窗还是编辑分类弹窗
*/
function selectParentCate(parentId,parentGrade,parentName,divId){
//alert("parentId:"+parentId);alert("parentGrade:"+parentGrade);alert("parentName:"+parentName);alert("divId:"+divId);
if(divId=="cateAdd"){
$("#catParentName_add").val(parentName);
$("#catParentId_add").val(parentId);
$("#catGrade_add").val(parentGrade);
}else if(divId=="cateEdit"){
$("#catParentName_edit").val(parentName);
$("#catParentId_edit").val(parentId);
$("#catGrade_edit").val(parentGrade);
}
//隐藏弹框树
$(".cateTree").hide();
}
备注:
1.注意用了代码重构的思想,如添加分类,编辑分类都要显示谈框树,则用type来区分是添加显示还是编辑显示
2.js执行顺序是从上到下,代码顺序很重要,在实际开发中因为代码放的位置不对,导致展示数据异常,这里就明显体现了。
3.从后台递归查询了数据,前台没有用任何框架,纯js+css展示,这里用js递归方法展示,本人是第一次写,觉得非常好,留着纪念
后台代码:
controlle层:
/**
* 递归查询商品分类
* @return
*/
@RequestMapping("/queryAllCate")
@ResponseBody
public List<GoodsCateVo> queryGoodsCateVo(HttpServletRequest request) {
//获取参数(all查询所有)
String queryType = request.getParameter("queryType");
Date date=new Date();
List<GoodsCateVo> list=new ArrayList<GoodsCateVo>();
HashMap<String, Object> paramMap=new HashMap<String, Object>();
try {
//根据父节点递归查询子节点
if(!"all".equals(queryType)){
paramMap.put("catParentId", 0);
}
list=goodsCateService.findAllGoodsCate(paramMap);
System.out.println("查询耗时:"+(new Date().getTime()-date.getTime()));
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("递归查询商品分类失败"+e.getMessage(),e);
}
return list;
}
注意这里查询是所有父分类即catParentId=0,然后根据父分类递归查询所有子分类
serverImpl业务层:
/**
* @descript:根据父节点递归查询子节点
* @param:
* @return:
*/
@Transactional(readOnly=true)
public List<GoodsCateVo> findAllGoodsCate(Map<String, Object> paramMap){
//封装返回结果
List<GoodsCateVo> list=new ArrayList<GoodsCateVo>();
try {
//查询所有父商品分类
List<GoodsCateVo> goodsParentCateList=goodsCateMapper.queryAllParentGoosCate(paramMap);
if(goodsParentCateList!=null && !goodsParentCateList.isEmpty()){
for(GoodsCateVo cateVo:goodsParentCateList){
// 初始化变量申明
GoodsCateVo vo=new GoodsCateVo();
vo.setCatId(cateVo.getCatId());
vo.setCatName(cateVo.getCatName());
vo.setCatParentId(cateVo.getCatParentId());
vo.setCatGrade(cateVo.getCatGrade());
vo.setCatSort(cateVo.getCatSort());
vo.setCatRate(cateVo.getCatRate());
vo.setCatIsFinal(cateVo.getCatIsFinal());
vo.setTypeId(cateVo.getTypeId());
vo.setTypeName(cateVo.getTypeName());
//子分类参数
Map<String, Object> dataMap=new HashMap<String, Object>();
dataMap.put("catParentId", cateVo.getCatId());
//通过父分类递归子分类,最后一级不递归,商品分类是否是末级0否1是
if("0".equals(cateVo.getCatIsFinal())){
vo.setCateVos(findAllGoodsCate(dataMap));
}
list.add(vo);
}
}
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("查询商品分类失败"+e.getMessage(),e);
}
return list;
}
mybatis查询:
<!-- 根据父节点递归查询子节点 -->
<select id="queryAllParentGoosCate" parameterType="java.util.Map" resultMap="goodsCateVo">
select
<include refid="goodsCateVo_Colimn_list" />
from t_goods_category c
left join t_goods_type t on c.type_id=t.type_id and t.type_delflag='0'
where
c.cat_delflag='0'
<if test="catParentId != null" >
and c.cat_parent_id=#{catParentId}
</if>
order by c.cat_sort,c.cat_id
</select>
实体类:
package com.qianjiang.goods.vo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 商品分类VO
*/
public class GoodsCateVo implements Serializable{
/**
* 序列化
*/
private static final long serialVersionUID = -1362577335137261590L;
/*
*分类ID
*/
private Long catId;
/*
*分类名称
*/
private String catName;
/*
*父级分类ID
*/
private Long catParentId;
/*
*商品类型ID
*/
private Long typeId;
/*
*类型排序
*/
private Integer catSort;
/*
*层级
*/
private Integer catGrade;
/*
*类型名称
*/
private String typeName;
/*
*子级的CateVo集合,默认为空(这样定义是因为在js递归子分类出现异常故这样定义给个默认值)
*/
private List<GoodsCateVo> cateVos=new ArrayList<GoodsCateVo>(0);
/*
*类目扣率
*/
private BigDecimal catRate;
/*
*商品分类是否是末级0否1是
*/
private String catIsFinal;
public BigDecimal getCatRate() {
return catRate;
}
public void setCatRate(BigDecimal catRate) {
this.catRate = catRate;
}
public Long getCatId() {
return catId;
}
public void setCatId(Long catId) {
this.catId = catId;
}
public String getCatName() {
return catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
public Long getCatParentId() {
return catParentId;
}
public void setCatParentId(Long catParentId) {
this.catParentId = catParentId;
}
public Long getTypeId() {
return typeId;
}
public void setTypeId(Long typeId) {
this.typeId = typeId;
}
public Integer getCatSort() {
return catSort;
}
public void setCatSort(Integer catSort) {
this.catSort = catSort;
}
public Integer getCatGrade() {
return catGrade;
}
public void setCatGrade(Integer catGrade) {
this.catGrade = catGrade;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public List<GoodsCateVo> getCateVos() {
return cateVos;
}
public void setCateVos(List<GoodsCateVo> cateVos) {
this.cateVos = cateVos;
}
public String getCatIsFinal() {
return catIsFinal;
}
public void setCatIsFinal(String catIsFinal) {
this.catIsFinal = catIsFinal;
}
}
补充:
这里用到一个方法:Select下拉框onchange事件获取option的value值
jsp:
<div class="form-group">
<label class="col-sm-5 control-label"> <span class="text-danger">*</span>是否末级:</label>
<div class="col-sm-14">
<select class="form-control w100 required" data-live-search="false" name="catIsFinal" οnchange="changeSelect(this.options[this.options.selectedIndex].value,'cateRate_add');">
<option value="">请选择</option>
<option value="0">否</option>
<option value="1" >是</option>
</select>
</div>
<div class="col-sm-4"></div>
</div>
js方法:
/**
* select change事件
* 判断是否末级,若是显示分类扣率否则不显示
* catIsFinal 0否1是
* @param obj select选中的值
* @param divId 分类扣率divId
*/
function changeSelect(obj,divId){
//alert("select value:"+obj); alert("divId:"+divId);
var catIsFinal=obj;
if(catIsFinal=="1"){
//添加验证
$("#"+divId).find("select").addClass("required");
$("#"+divId).find("input").addClass("required");
//显示分类扣率
$("#"+divId).show();
}else{
//移除验证
$("#"+divId).find("select").removeClass("required");
$("#"+divId).find("input").removeClass("required");
//隐藏分类扣率
$("#"+divId).hide();
}
}
案例中放开alert,obj就是下拉框选中的值