設(shè)計(jì)及封裝無限層級的樹狀結(jié)構(gòu)

設(shè)計(jì)及封裝無限層級的樹狀結(jié)構(gòu)

需求:電商項(xiàng)目中,在商品的品類管理模塊抄囚,會(huì)涉及到遞歸調(diào)用出該節(jié)點(diǎn)的所有子節(jié)點(diǎn)的操作绍撞。

數(shù)據(jù)表設(shè)計(jì):

category表.jpg

Category:

public class Category {
    private Integer id;

    private Integer parentId;

    private String name;

    private Boolean status;

    private Integer sortOrder;

    private Date createTime;

    private Date updateTime;

    @Override
    public boolean equals(Object o){
        if(this == o){
            return true;
        }
        if(o == null || getClass() != o.getClass()){
            return false;
        }
        Category category = (Category) o;
        return !(id!=null?!id.equals(category.id):category.id!=null);
    }

    @Override
    public int hashCode(){
        return id!=null?id.hashCode():0;
    }
}

Controller:

/**
 * 根據(jù)傳的categoryId獲取當(dāng)前categoryId下邊節(jié)點(diǎn)的category信息(平級,無遞歸)
 * @param session
 * @param categoryId
 * @return
 */
@RequestMapping("get_category.do")
@ResponseBody
public ServerResponse getChildrenParallelCategory(HttpSession session,
                                                  @RequestParam(value = "categoryId",defaultValue = "0") Integer categoryId){
    User user = (User)session.getAttribute(Const.CURRENT_USER);
    if(user == null){
        return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),"用戶未登錄拣展,請先登錄");
    }
    if(iUserService.checkAdminRole(user).isSuccess()){
        //查詢子節(jié)點(diǎn)的category信息坡垫,并且不遞歸梭灿,保持平級
        return iCategoryService.getChildrenParallelCategory(categoryId);
    }else {
        return ServerResponse.createByErrorMessage("無權(quán)限操作,需要管理員權(quán)限");
    }
}


/**
 * 獲取當(dāng)前的categoryId并且遞歸查詢它的子節(jié)點(diǎn)的categoryId
 * @param session
 * @param categoryId
 * @return
 */
@RequestMapping("get_deep_category.do")
@ResponseBody
public ServerResponse getCategoryAndDeepChildrenCategory(HttpSession session,
                                                  @RequestParam(value = "categoryId",defaultValue = "0") Integer categoryId){

    User user = (User)session.getAttribute(Const.CURRENT_USER);
    if(user == null){
        return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),"用戶未登錄冰悠,請先登錄");
    }
    if(iUserService.checkAdminRole(user).isSuccess()){
        //查詢當(dāng)前節(jié)點(diǎn)的id和遞歸子節(jié)點(diǎn)的id
        return iCategoryService.selectCategoryAndChildrenById(categoryId);
    }else {
        return ServerResponse.createByErrorMessage("無權(quán)限操作堡妒,需要管理員權(quán)限");
    }
}

ServiceImpl:

@Override
public ServerResponse<List<Category>> getChildrenParallelCategory(Integer categoryId){
    List<Category> categoryList = categoryMapper.selectCategoryChildrenParentId(categoryId);
    if(CollectionUtils.isEmpty(categoryList)){
        logger.info("未找到當(dāng)前分類的子分類");
    }
    return ServerResponse.createBySuccess(categoryList);
}

/**
 * 遞歸查詢本節(jié)點(diǎn)的id及其子孫節(jié)點(diǎn)的id:獲取當(dāng)前categoryId下的子節(jié)點(diǎn),還要繼續(xù)查找子節(jié)點(diǎn)是否還有子節(jié)點(diǎn)屿脐,及所有子孫節(jié)點(diǎn)
 * 0-->10-->100
 * 如果傳0涕蚤,會(huì)返回10和100
 * 如果傳10,會(huì)返回100
 * @param categoryId
 * @return
 */
@Override
public ServerResponse<List<Integer>> selectCategoryAndChildrenById(Integer categoryId){
    HashSet<Category> categorySet = Sets.newHashSet();
    findChildCategory(categorySet,categoryId);

    List<Integer> categoryIdList = Lists.newArrayList();
    if(categoryId!=null){
        for(Category categoryItem : categorySet){
            categoryIdList.add(categoryItem.getId());
        }
    }
    return ServerResponse.createBySuccess(categoryIdList);
}

遞歸算法:

/**
 * 為了使使用set集合不重復(fù)的诵,需要重寫hashcode和equals方法
 * 遞歸算法:算出子節(jié)點(diǎn)
 * @param categorySet
 * @param categoryId
 * @return
 */
private Set<Category> findChildCategory(Set<Category> categorySet,Integer categoryId){
    Category category = categoryMapper.selectByPrimaryKey(categoryId);
    if(category!=null){
        categorySet.add(category);
    }
    //查找子節(jié)點(diǎn)万栅,遞歸算法一定要有一個(gè)退出的條件
    List<Category> categoryList = categoryMapper.selectCategoryChildrenParentId(categoryId);
    for(Category categoryItem:categoryList){
        findChildCategory(categorySet,categoryItem.getId());
    }
    return categorySet;
}

mapper:

public interface CategoryMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Category record);

    int insertSelective(Category record);

    Category selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Category record);

    int updateByPrimaryKey(Category record);

    /**
     * 根據(jù)categoryId獲取孩子節(jié)點(diǎn)的category信息
     * @param parentId
     * @return
     */
    List<Category> selectCategoryChildrenParentId(Integer parentId);
}

xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hcxmall.dao.CategoryMapper" >
  <resultMap id="BaseResultMap" type="com.hcxmall.pojo.Category" >
    <constructor>
      <idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="parent_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="name" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="status" jdbcType="BIT" javaType="java.lang.Boolean" />
      <arg column="sort_order" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
      <arg column="update_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
    </constructor>
  </resultMap>
  <sql id="Base_Column_List" >
    id, parent_id, name, status, sort_order, create_time, update_time
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from mmall_category
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from mmall_category
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.hcxmall.pojo.Category" >
    insert into mmall_category (id, parent_id, name, 
      status, sort_order, create_time, 
      update_time)
    values (#{id,jdbcType=INTEGER}, #{parentId,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, 
      #{status,jdbcType=BIT}, #{sortOrder,jdbcType=INTEGER},now(),
      now())
  </insert>
  <insert id="insertSelective" parameterType="com.hcxmall.pojo.Category" >
    insert into mmall_category
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="parentId != null" >
        parent_id,
      </if>
      <if test="name != null" >
        name,
      </if>
      <if test="status != null" >
        status,
      </if>
      <if test="sortOrder != null" >
        sort_order,
      </if>
      <if test="createTime != null" >
        create_time,
      </if>
      <if test="updateTime != null" >
        update_time,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="parentId != null" >
        #{parentId,jdbcType=INTEGER},
      </if>
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="status != null" >
        #{status,jdbcType=BIT},
      </if>
      <if test="sortOrder != null" >
        #{sortOrder,jdbcType=INTEGER},
      </if>
      <if test="createTime != null" >
        now(),
      </if>
      <if test="updateTime != null" >
        now(),
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.hcxmall.pojo.Category" >
    update mmall_category
    <set >
      <if test="parentId != null" >
        parent_id = #{parentId,jdbcType=INTEGER},
      </if>
      <if test="name != null" >
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="status != null" >
        status = #{status,jdbcType=BIT},
      </if>
      <if test="sortOrder != null" >
        sort_order = #{sortOrder,jdbcType=INTEGER},
      </if>
      <if test="createTime != null" >
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateTime != null" >
        update_time = now(),
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.hcxmall.pojo.Category" >
    update mmall_category
    set parent_id = #{parentId,jdbcType=INTEGER},
      name = #{name,jdbcType=VARCHAR},
      status = #{status,jdbcType=BIT},
      sort_order = #{sortOrder,jdbcType=INTEGER},
      create_time = #{createTime,jdbcType=TIMESTAMP},
      update_time = now()
    where id = #{id,jdbcType=INTEGER}
  </update>

  <select id="selectCategoryChildrenParentId" resultMap="BaseResultMap" parameterType="int">
    SELECT <include refid="Base_Column_List"/>
    FROM mmall_category
    WHERE parent_id = #{parentId}
  </select>
</mapper>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市西疤,隨后出現(xiàn)的幾起案子烦粒,更是在濱河造成了極大的恐慌,老刑警劉巖代赁,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扰她,死亡現(xiàn)場離奇詭異,居然都是意外死亡芭碍,警方通過查閱死者的電腦和手機(jī)徒役,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窖壕,“玉大人忧勿,你說我怎么就攤上這事≌胺恚” “怎么了鸳吸?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長速勇。 經(jīng)常有香客問我晌砾,道長羽历,這世上最難降的妖魔是什么偷拔? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮涵妥,結(jié)果婚禮上个初,老公的妹妹穿的比我還像新娘乖寒。我一直安慰自己,他們只是感情好院溺,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布楣嘁。 她就那樣靜靜地躺著,像睡著了一般珍逸。 火紅的嫁衣襯著肌膚如雪逐虚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天谆膳,我揣著相機(jī)與錄音叭爱,去河邊找鬼。 笑死漱病,一個(gè)胖子當(dāng)著我的面吹牛买雾,可吹牛的內(nèi)容都是我干的把曼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼漓穿,長吁一口氣:“原來是場噩夢啊……” “哼嗤军!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起晃危,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤叙赚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后僚饭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體震叮,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年鳍鸵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苇瓣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,435評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡权纤,死狀恐怖钓简,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情汹想,我是刑警寧澤外邓,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站古掏,受9級特大地震影響损话,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜槽唾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一丧枪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧庞萍,春花似錦拧烦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至私恬,卻和暖如春债沮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背本鸣。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工疫衩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荣德。 一個(gè)月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓闷煤,卻偏偏與公主長得像童芹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子鲤拿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容