springmvc+mybatis 無極限樹形結構 Mapperxml 對映方法
阿新 • • 發佈:2018-12-25
專案中我們可能經常有這樣的需求,需要返回二級或三級的選單,返回一個樹形結構,面試中也可能經常被問到。
最近的專案中就用到了,這裡整理分享一下。
應用場景:
地區樹,國家,省,市,區縣共4級。
表結構:
建表語句:
返回JSON結果示例:SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `base_area` -- ---------------------------- DROP TABLE IF EXISTS `base_area`; CREATE TABLE `base_area` ( `ID` bigint(20) NOT NULL AUTO_INCREMENT, `AREA_NAME` varchar(255) DEFAULT NULL COMMENT '地區名稱', `AREA_CODE` varchar(255) DEFAULT NULL COMMENT '地區編碼', `PARENT_ID` bigint(20) DEFAULT NULL, `PLAT_MARK` bigint(20) DEFAULT NULL COMMENT '區域標識,也就是平臺標識', `LEVEL` tinyint(4) DEFAULT '1' COMMENT '層', `STATUS` tinyint(4) DEFAULT '1' COMMENT '是否可用、是否顯示', `EXPAND` tinyint(4) DEFAULT '0' COMMENT '是否展開子節點,非0為展開。', PRIMARY KEY (`ID`), KEY `index2` (`PLAT_MARK`) ) ENGINE=InnoDB AUTO_INCREMENT=3514 DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS = 1;
資料比較多,這裡只展示一部分,有需要完整表資料的小夥伴,稍後提供下載地址。
{"result":[{"createTimeString":"","updateTimeString":"","level":3,"platMark":100001001000000,"parentId":1,"areaCode":"110000","expand":0,"areaName":"北京市","id":2,"childrenList":[{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001001000,"parentId":2,"areaCode":"110101","expand":0,"areaName":"東城區","id":4,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001002000,"parentId":2,"areaCode":"110102","expand":0,"areaName":"西城區","id":5,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001003000,"parentId":2,"areaCode":"110105","expand":0,"areaName":"朝陽區","id":6,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001004000,"parentId":2,"areaCode":"110106","expand":0,"areaName":"豐臺區","id":7,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001005000,"parentId":2,"areaCode":"110107","expand":0,"areaName":"石景山區","id":8,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001006000,"parentId":2,"areaCode":"110108","expand":0,"areaName":"海淀區","id":9,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001007000,"parentId":2,"areaCode":"110109","expand":0,"areaName":"門頭溝區","id":10,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001008000,"parentId":2,"areaCode":"110111","expand":0,"areaName":"房山區","id":11,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001009000,"parentId":2,"areaCode":"110112","expand":0,"areaName":"通州區","id":12,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001010000,"parentId":2,"areaCode":"110113","expand":0,"areaName":"順義區","id":13,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001011000,"parentId":2,"areaCode":"110114","expand":0,"areaName":"昌平區","id":14,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001012000,"parentId":2,"areaCode":"110115","expand":0,"areaName":"大興區","id":15,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001013000,"parentId":2,"areaCode":"110116","expand":0,"areaName":"懷柔區","id":16,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001014000,"parentId":2,"areaCode":"110117","expand":0,"areaName":"平谷區","id":17,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001015000,"parentId":2,"areaCode":"110228","expand":0,"areaName":"密雲縣","id":18,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100001001016000,"parentId":2,"areaCode":"110229","expand":0,"areaName":"延慶縣","id":19,"childrenList":[]}]},{"createTimeString":"","updateTimeString":"","level":3,"platMark":100002001000000,"parentId":1,"areaCode":"120000","expand":0,"areaName":"天津市","id":20,"childrenList":[{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001001000,"parentId":20,"areaCode":"120101","expand":0,"areaName":"和平區","id":22,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001002000,"parentId":20,"areaCode":"120102","expand":0,"areaName":"河東區","id":23,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001003000,"parentId":20,"areaCode":"120103","expand":0,"areaName":"河西區","id":24,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001004000,"parentId":20,"areaCode":"120104","expand":0,"areaName":"南開區","id":25,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001005000,"parentId":20,"areaCode":"120105","expand":0,"areaName":"河北區","id":26,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001006000,"parentId":20,"areaCode":"120106","expand":0,"areaName":"紅橋區","id":27,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001007000,"parentId":20,"areaCode":"120110","expand":0,"areaName":"東麗區","id":28,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001008000,"parentId":20,"areaCode":"120111","expand":0,"areaName":"西青區","id":29,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001009000,"parentId":20,"areaCode":"120112","expand":0,"areaName":"津南區","id":30,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001010000,"parentId":20,"areaCode":"120113","expand":0,"areaName":"北辰區","id":31,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001011000,"parentId":20,"areaCode":"120114","expand":0,"areaName":"武清區","id":32,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001012000,"parentId":20,"areaCode":"120115","expand":0,"areaName":"寶坻區","id":33,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001013000,"parentId":20,"areaCode":"120116","expand":0,"areaName":"濱海新區","id":34,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001014000,"parentId":20,"areaCode":"120221","expand":0,"areaName":"寧河縣","id":35,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001015000,"parentId":20,"areaCode":"120223","expand":0,"areaName":"靜海縣","id":36,"childrenList":[]},{"createTimeString":"","updateTimeString":"","level":4,"platMark":100002001016000,"parentId":20,"areaCode":"120225","expand":0,"areaName":"薊縣","id":37,"childrenList":[]}]}]}
實體類:
/** * 表名:base_area * 備註:BaseArea */ @SuppressWarnings("serial") public class BaseArea { //date formats //columns START //id private Long id; //地區名稱 private String areaName; //地區編碼 private String areaCode; //parentId private Long parentId; //區域標識,也就是平臺標識 private Long platMark; //層 private Byte level; //是否可用、是否顯示 private Integer status; //是否展開子節點,非0為展開。 private Byte expand; //columns END //extend columns START //子節點列表 List<BaseArea> childrenList; //extend columns END public List<BaseArea> getChildrenList() { return childrenList; } public void setChildrenList(List<BaseArea> childrenList) { this.childrenList = childrenList; } public BaseArea(){ } public BaseArea(Long id){ this.id = id; } /** * id * @return */ public Long getId() { return this.id; } /** * id * @param value */ public void setId(Long value) { this.id = value; } /** * 地區名稱 * @return */ public String getAreaName() { return this.areaName; } /** * 地區名稱 * @param value */ public void setAreaName(String value) { this.areaName = value; } /** * 地區編碼 * @return */ public String getAreaCode() { return this.areaCode; } /** * 地區編碼 * @param value */ public void setAreaCode(String value) { this.areaCode = value; } /** * parentId * @return */ public Long getParentId() { return this.parentId; } /** * parentId * @param value */ public void setParentId(Long value) { this.parentId = value; } /** * 區域標識,也就是平臺標識 * @return */ public Long getPlatMark() { return this.platMark; } /** * 區域標識,也就是平臺標識 * @param value */ public void setPlatMark(Long value) { this.platMark = value; } /** * 層 * @return */ public Byte getLevel() { return this.level; } /** * 層 * @param value */ public void setLevel(Byte value) { this.level = value; } /** * 是否可用、是否顯示 * @return */ public Integer getStatus() { return this.status; } /** * 是否可用、是否顯示 * @param value */ public void setStatus(Integer value) { this.status = value; } /** * 是否展開子節點,非0為展開。 * @return */ public Byte getExpand() { return this.expand; } /** * 是否展開子節點,非0為展開。 * @param value */ public void setExpand(Byte value) { this.expand = value; } }
Mapperxml 對映方法
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
<!-- 不使用namespace的話sql搜尋定位會比較方便 -->
<!-- BaseArea -->
<mapper namespace="BaseArea">
<resultMap id="baseAreaResult" type="com.wanyu.smarthome.model.BaseArea">
<id property="id" column="ID"/>
<result property="areaName" column="AREA_NAME"/>
<result property="areaCode" column="AREA_CODE"/>
<result property="parentId" column="PARENT_ID"/>
<result property="platMark" column="PLAT_MARK"/>
<result property="level" column="LEVEL"/>
<result property="status" column="STATUS"/>
<result property="expand" column="EXPAND"/>
<collection property="childrenList" javaType="java.util.ArrayList" column="id"
ofType="com.wanyu.smarthome.model.BaseArea" select="childrenSelect"></collection>
</resultMap>
<resultMap id="childrenResult" type="com.wanyu.smarthome.model.BaseArea">
<id property="id" column="ID"/>
<result property="areaName" column="AREA_NAME"/>
<result property="areaCode" column="AREA_CODE"/>
<result property="parentId" column="PARENT_ID"/>
<result property="platMark" column="PLAT_MARK"/>
<result property="level" column="LEVEL"/>
<result property="status" column="STATUS"/>
<result property="expand" column="EXPAND"/>
<collection property="childrenList" javaType="java.util.ArrayList" column="id"
ofType="com.wanyu.smarthome.model.BaseArea" select="childrenSelect"></collection>
</resultMap>
<!-- 用於select查詢公用抽取的列 -->
<sql id="commonColumns">
<![CDATA[
ID,
AREA_NAME,
AREA_CODE,
PARENT_ID,
PLAT_MARK,
LEVEL,
STATUS,
EXPAND
]]>
</sql>
<sql id="commonAliasColumns">
<![CDATA[
x.ID,
x.AREA_NAME,
x.AREA_CODE,
x.PARENT_ID,
x.PLAT_MARK,
x.LEVEL,
x.STATUS,
x.EXPAND
]]>
</sql>
<!-- useGeneratedKeys="true" keyProperty="xxx" for sqlserver and mysql -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id" parameterType="com.wanyu.smarthome.model.BaseArea">
<![CDATA[
INSERT INTO base_area (
ID,
AREA_NAME,
AREA_CODE,
PARENT_ID,
PLAT_MARK,
LEVEL,
STATUS,
EXPAND
) VALUES (
#{id},
#{areaName},
#{areaCode},
#{parentId},
#{platMark},
#{level},
#{status},
#{expand}
)
]]>
</insert>
<update id="update" parameterType="com.wanyu.smarthome.model.BaseArea">
<![CDATA[
UPDATE base_area SET
AREA_NAME = #{areaName},
AREA_CODE = #{areaCode},
PARENT_ID = #{parentId},
PLAT_MARK = #{platMark},
LEVEL = #{level},
STATUS = #{status},
EXPAND = #{expand}
WHERE
ID = #{id}
]]>
</update>
<delete id="delete" parameterType="map">
<![CDATA[
delete from base_area
]]>
<include refid="dynamicWhere"/>
</delete>
<delete id="batchDelete" parameterType="list">
delete from base_area where ID IN
<foreach collection="list" item="ids" open="(" separator="," close=")">
#{ids} </foreach>
</delete>
<delete id="batchDeleteByLocalId" parameterType="list">
delete from base_area where LOCAL_ID in
<foreach collection="list" item="ids" open="(" separator="," close=")">
#{ids} </foreach>
</delete>
<select id="getById" resultMap="baseAreaResult">
SELECT <include refid="commonColumns" />
<![CDATA[
FROM base_area
WHERE
ID = #{id}
]]>
</select>
<select id="getByIds" resultMap="baseAreaResult">
SELECT <include refid="commonColumns" />
FROM base_area WHERE ID IN
<foreach collection="list" item="ids" open="(" separator="," close=")">
#{ids} </foreach>
</select>
<sql id="dynamicWhere">
<!-- ognl訪問靜態方法的表示式 為@[email protected](args),以下為呼叫rapid中的Ognl.isNotEmpty()方法,還有其它方法如isNotBlank()可以使用,具體請檢視Ognl類 -->
<where>
<if test="@[email protected](id)">
AND ID = #{id}
</if>
<if test="@[email protected](areaName)">
AND AREA_NAME = #{areaName}
</if>
<if test="@[email protected](areaCode)">
AND AREA_CODE = #{areaCode}
</if>
<if test="@[email protected](parentId)">
AND PARENT_ID = #{parentId}
</if>
<if test="@[email protected](platMark)">
AND PLAT_MARK = #{platMark}
</if>
<if test="@[email protected](level)">
AND LEVEL = #{level}
</if>
<if test="@[email protected](status)">
AND STATUS = #{status}
</if>
<if test="@[email protected](expand)">
AND EXPAND = #{expand}
</if>
</where>
</sql>
<select id="count" resultType="long">
SELECT count(*) FROM base_area
<include refid="dynamicWhere"/>
</select>
<!--
分頁查詢已經使用Dialect進行分頁,也可以不使用Dialect直接編寫分頁
因為分頁查詢將傳 offset,pageSize,lastRows 三個引數,不同的資料庫可以根於此三個引數屬性應用不同的分頁實現
-->
<select id="pageSelect" resultMap="baseAreaResult">
SELECT <include refid="commonColumns" />
FROM base_area
<include refid="dynamicWhere"/>
<if test="@[email protected](sortColumns)">
ORDER BY ${sortColumns}
</if>
</select>
<select id="childrenSelect" resultMap="childrenResult">
SELECT <include refid="commonColumns" />
FROM base_area
WHERE PARENT_ID = #{id}
ORDER BY ID ASC
</select>
</mapper>
Mapperxml 解析
1、主查詢語句為: pageSelect
2、結果對映 resultMap id="baseAreaResult"
這裡的關鍵在於:
<id property="id" column="ID"/>
<collection property="childrenList" javaType="java.util.ArrayList" column="id"
ofType="com.wanyu.smarthome.model.BaseArea" select="childrenSelect"></collection>
collection 標籤中定義屬性名稱為 childrenList,對應實體類中的:childrenList
屬性型別為:java.util.ArrayList
column="id" 將 id 列的值做為引數傳遞給子查詢
ofType 定義List 中儲存的資料型別
select 定義子查詢
3、注意子查詢 childrenSelect 對應的結果對映 childrenResult ,又包含了 collection 標籤,形成了迴圈遞迴呼叫
小結
不知道我有沒有描述清楚,有不明白的地方請留言。
強烈不推薦這種迴圈遞迴呼叫的寫法,因為效能非常差。
最好是有幾級就寫幾級,也就是寫幾個 resultMap。
本粟中是演示同一個表相同實體類的實現方式,同樣也可以不同的表不同的實體類,只要把子節點型別修改一下就可以了。
為了效能,這種查詢最好配合快取使用。
======================文件資訊======================
署名(BY) :testcs_dn(微wx笑)
文章出處:[無知人生,記錄點滴](http://blog.csdn.NET/testcs_dn)
==============本文首發於個人微信訂閱號(微wx笑)============