下边根据内容管理模块的业务流程,下一步要实现新增课程,在新增课程界面,有三处信息需要选择,如下图:
课程等级、课程类型来源于数据字典表,此部分的信息前端已从系统管理服务读取。
课程分类信息没有在数据字典表中存储,而是由单独一张课程分类表,存储在内容管理数据库中。
下边看下course_category课程分类表的结构
这张表是一个树型结构,通过父结点id将各元素组成一个树。
现在的需求是需要在内容管理服务中编写一个接口读取该课程分类表的数据,组成一个树型结构返回给前端。
如果没有此po类则需要生成的此表的po类拷贝到内容管理模块的model工程中,将mapper拷贝到内容管理模块的service工程中。
http://localhost:8601/api/content/course-category/tree-nodes 该地址正是前端获取课程分类的接口地址。
通过上图界面的内容可以看出该接口的协议为:HTTP GET
请求参数为空。
通过查阅接口文档,此接口要返回全部课程分类,以树型结构返回,如下所示。
JSON |
上边的数据格式是一个数组结构,数组的元素即为分类信息,分类信息设计两级分类,第一级的分类信息示例如下:
JSON |
第二级的分类是第一级分类中childrenTreeNodes属性,它是一个数组结构:
JSON |
所以,定义一个DTO类表示分类信息的模型类,如下:
Java |
接口定义如下:
Java
* * @author itcast */ @Slf4j @RestController public class CourseCategoryController { @GetMapping("/course-category/tree-nodes") public List return null; } } |
课程分类表是一个树型结构,其中parentid字段为父结点ID,它是树型结构的标志字段。
如果树的层级固定可以使用表的自链接去查询,比如:我们只查询两级课程分类,可以用下边的SQL
Java |
如果树的层级不确定,此时可以使用MySQL递归实现,使用with语法,如下:
Java |
cte_name :公共表达式的名称,可以理解为表名,用来表示as后面跟着的子查询
col_name :公共表达式包含的列名,可以写也可以不写
下边是一个递归的简单例子:
Java |
说明:
t1 相当于一个表名
select 1 相当于这个表的初始值,这里使用UNION ALL 将初始值加入到表中。
n<5为递归执行的条件,当n>=5时结束递归调用。
下边我们使用递归实现课程分类的查询
Java |
t1表中初始的数据是id等于1的记录,即根结点。
通过inner join t1 t2 on t2.id = t.parentid 找到id='1'的下级节点 。
通过这种方法就找到了id='1'的所有下级节点,下级节点包括了所有层级的节点。
上边这种方法是向下递归,即找到初始节点的所有下级节点。
如何向上递归?
下边的sql实现了向上递归:
Java |
初始节点为1-1-1,通过递归找到它的父级节点,父级节点包括所有级别的节点。
以上是我们研究了树型表的查询方法,通过递归的方式查询课程分类比较灵活,因为它可以不限制层级。
mysql为了避免无限递归默认递归次数为1000,可以通过设置cte_max_recursion_depth参数增加递归深度,还可以通过max_execution_time限制执行时间,超过此时间也会终止递归操作。
mysql递归相当于在存储过程中执行若干次sql语句,java程序仅与数据库建立一次链接执行递归操作,所以只要控制好递归深度,控制好数据量性能就没有问题。
思考:如果java程序在递归操作中连接数据库去查询数据组装数据,这个性能高吗?
下边我们可自定义mapper方法查询课程分类,最终将查询结果映射到List
生成课程分类表的mapper文件并拷贝至内容管理模块 的service工程中。
1、下边 定义一个mapper方法,并定义sql语句。
Java |
2、找到对应 的mapper.xml文件,编写sql语句。
Java |
定义service接口,调用mapper查询课程分类,遍历数据按照接口要求对数据进行封装
Java |
编写service接口实现
Java |
4.3.4 单元测试
定义单元测试类对service接口进行测试
Java |
完善controller方法,注入service调用业务层方法查询课程分类。
Java
* * @author itcast */ @Slf4j @RestController public class CourseCategoryController { @Autowired CourseCategoryService courseCategoryService; @GetMapping("/course-category/tree-nodes") public List return courseCategoryService.queryTreeNodes("1"); } } |
使用httpclient测试:
运行测试。
完成前后端连调:
打开前端工程,进入新增课程页面。