使用Mybatis封装返回多层级数据

本文介绍了如何在Java开发中使用Mybatis进行数据查询并封装成前端所需的多层级结构。通过实例展示了如何在mapper文件中使用<resultMap>标签,结合DTO类,将数据库查询结果转换为复杂的对象结构,提高开发效率。

前言

实际开发中,我们从数据库查询返回得到的数据可能需要二次封装成前端想要处理的数据,而不只是简单的返回 pojo/entity 类。

例如,有如下一张简单的表:分类表

字段含义
id分类 id
name分类名称
parent_id父类 id,第一级分类 parent_id 为 0

如表格所示,这张表用来存储大学专业分类数据、或者商品分类、图书分类等,这些分类往往是多级结构的。

例如,我们可能需要这样的数据展示:

一级分类二级分类
经济学经济学类
财政学类
金融学类
法学法学类
政治学类
社会学类
理学数学类
物理学类
化学类
天文学类
工学力学类
机械类

我们可以在查询到数据后,直接在 pojo 类上进行封装成前端所需要的数据结构返回,但是我们可以利用 MyBatis 帮我们完成封装过程,提高开发效率。

代码实现

我们只需使用 MyBatis 提供的 resultMap 标签指明查询数据的数据结构即可。

关于 resultMap 标签,它的属性有:

  • id:唯一标识自己,与 select 标签中的 resultMap 属性绑定
  • type: 指明数据封装使用的

它的子标签有:

  • id :表示数据库中的主键
  • result:基本数据类型所对应的列
  • collection:映射对象集合
  • association:映射单个对象
  • discriminator:条件分支,根据结果决定映射

详细可以查看说明:XML 映射器_MyBatis中文网

这里使用上文讲述的大学专业分类展示

数据准备

分类表结构category 以及数据

CREATE TABLE `category` (
  `id` int(11) NOT NULL COMMENT 'id 主键',
  `parent_id` int(11) DEFAULT NULL COMMENT '上级 Id, 一级分类的 parent_id 为 0',
  `name` varchar(20) DEFAULT NULL COMMENT '分类名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `category` VALUES (1, 0, '经济学');
INSERT INTO `category` VALUES (2, 0, '法学');
INSERT INTO `category` VALUES (3, 0, '理学');
INSERT INTO `category` VALUES (4, 0, '工学');
INSERT INTO `category` VALUES (11, 1, '经济学类');
INSERT INTO `category` VALUES (12, 1, '财政学类');
INSERT INTO `category` VALUES (13, 1, '金融学类');
INSERT INTO `category` VALUES (21, 2, '法学类');
INSERT INTO `category` VALUES (22, 2, '政治学类');
INSERT INTO `category` VALUES (23, 2, '社会学类');
INSERT INTO `category` VALUES (31, 3, '数学类');
INSERT INTO `category` VALUES (32, 3, '物理学类');
INSERT INTO `category` VALUES (33, 3, '化学类');
INSERT INTO `category` VALUES (34, 3, '天文学类');
INSERT INTO `category` VALUES (41, 4, '力学类');
INSERT INTO `category` VALUES (42, 4, '机械类');

代码展示

为了演示效果,这里并未编写对应的数据库实体类 pojo——Category

项目结构为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-si9eX9N7-1660403603398)(image-20220726163218420.png)]

mapper 文件:
<mapper namespace="com.example.leveldemo.mapper.CategoryMapper">
   
    <!-- 使用 resultMap 指示数据结构 -->
    <resultMap id="category" type="com.example.leveldemo.dto.OneCategoryLevel">
        <result column="one_id" property="id"/>
        <result column="one_category" property="name"/>
        <collection property="children" ofType="com.example.leveldemo.dto.TwoCategoryLevel">
            <result column="two_id" property="id"/>
            <result column="two_category" property="name"/>
        </collection>
    </resultMap>
    
    <select id="selectCategories" resultMap="category">
        SELECT
            t1.id AS one_id,
            t1.`name` AS one_category,
            t2.id AS two_id,
            t2.`name` AS two_category
        FROM
            `category` AS t1,
            `category` AS t2
        WHERE
            t1.id = t2.parent_id;
    </select>
</mapper>

DTO 类:

@Data
public class OneCategoryLevel {
    private Integer id;
    private String name;
    private List<TwoCategoryLevel> children;
}

@Data
public class TwoCategoryLevel {
    private Integer id;
    private String name;
}

其他代码:

//================== Controller 
@RestController
public class CategoryController {

    @Autowired
    private CategoryService categoryService;

    @GetMapping("/categories")
    public List<OneCategoryLevel> getCategories() {
        return categoryService.getCategories();
    }

}
//================== Service
@Service
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;

    @Override
    public List<OneCategoryLevel> getCategories() {
        return categoryMapper.selectCategories();
    }
}
//================== Mapper
@Mapper
public interface CategoryMapper {
    List<OneCategoryLevel> selectCategories();
}

测试

调用请求接口,得到返回数据,可以看到 MyBatis 已经帮我们封装好了:

[
    {
        "id":1,
        "name":"经济学",
        "children":[
            {
                "id":11,
                "name":"经济学类"
            },
            {
                "id":12,
                "name":"财政学类"
            },
            {
                "id":13,
                "name":"金融学类"
            }
        ]
    },
    {
        "id":2,
        "name":"法学",
        "children":[
            {
                "id":21,
                "name":"法学类"
            },
            {
                "id":22,
                "name":"政治学类"
            },
            {
                "id":23,
                "name":"社会学类"
            }
        ]
    },
    {
        "id":3,
        "name":"理学",
        "children":[
            {
                "id":31,
                "name":"数学类"
            },
            {
                "id":32,
                "name":"物理学类"
            },
            {
                "id":33,
                "name":"化学类"
            },
            {
                "id":34,
                "name":"天文学类"
            }
        ]
    },
    {
        "id":4,
        "name":"工学",
        "children":[
            {
                "id":41,
                "name":"力学类"
            },
            {
                "id":42,
                "name":"机械类"
            }
        ]
    }
]

总结

当需要对查询结果进行封装时,即查询结果的数据结构较为复杂时,我们可以使用 resultMap 标签对返回结果的数据结构进行映射,例如需要查询的结果数据结构是多层级的时候。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值