前言:在我们日常的开发项目过程中我们会遇到很多这种情况,就是把通过外键关联的数据库表用多级菜单的形式给展示给前台,这种数据展示形式又表述为树状展示模式;
比喻:有一个兄弟<小马>在A酒吧上班同时也在B酒吧兼职<这就是外键>,现在A酒吧来了一个抠脚大汉,这个抠脚大汉需要通过小马去B酒吧给他订台,然后小马得到抠脚大汉的指示去B酒吧高兴的订了一个台并且把发票给了抠脚大汉,抠脚大汉并没有去B酒吧而是通过小马去执行的,是不是就有了一个层级关系,
抠脚大汉(条件)-->A酒吧小马-->B酒吧(小马就属于外键)
1.效果展示:
2.实现:
2.1.添加数据库表
以年级和学生的关系创建数据库表
CREATE TABLE `grade` (
`gradeid` int NOT NULL AUTO_INCREMENT COMMENT '年级ID',
`gradename` varchar(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeid`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb3;
CREATE TABLE `student` (
`studentid` int NOT NULL COMMENT '学号',
`studentname` varchar(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`sex` tinyint(1) DEFAULT '1' COMMENT '性别',
`gradeid` int DEFAULT NULL COMMENT '年级',
`phoneNum` varchar(50) NOT NULL COMMENT '手机',
`address` varchar(255) DEFAULT NULL COMMENT '地址',
`borndate` datetime DEFAULT NULL COMMENT '生日',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`idCard` varchar(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`studentid`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
注意事项:在这两张表中 我用的是年级id作为的外键,外键的数据添加规则!!!
外键添加数据规则:遵循主从策略,先添加主表数据后,从表的外键才能正常添加数据,在这两表中,先添加年级的id<主表> 然后在学生表添加年级id才能成功,不然就会报错
2.2创建springboot项目并连接数据库与基础配置:
这两步不会的小伙伴参考我的这两篇博客:
创建springboot项目:
idea创建Springboot项目_@小杨爱偷懒的博客-CSDN博客
项目集成MySQL:
Springboot 集成 MySQL<详细过程>_@小杨爱偷懒的博客-CSDN博客_springboot与mysql集成
不想写框架的话,就看这篇博客吧:
mybatis-plus代码生成器实现规则《超详细》_@小杨爱偷懒的博客-CSDN博客
2.3最后的展示的框架就是这样:
2.4.添加VO实体类:
这点就有很多小伙伴不理解为什么需要vo实体类了:解释一下:在企业具体开发中我们设计数据库表的时候,基本上是帮所有与之相关的字段都会设计到一张数据库表中,这样就有一个问题,我展示数据表信息的时候,有些字段信息我并不想展示给别人,我只想展示部分信息给前台,但是我又不能改动数据表删减字段,这个时候我们就可以使用java代码来实现这一操作,我们就会创建一个VO实体类<也有叫do,po没区别的>,创建一个VO实体类后我想给前台返回什么数据就返回什么数据,保证了数据的安全性和减轻数据库的压力。
2.4.1:因为年纪表只要两个字段可以不用创建VO类,但是为了小伙伴们以后的具体实例一般很少只要两个字段的数据库表,我这点也模拟创建一个年纪vo类:
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class GradeVo {
private Integer gradeid;
private String gradename;
/**
*创建一个集合来接收学生信息表的信息
*/
private List<StudentVos> children = new ArrayList<>();
}
2.4.2:学生信息表vo类:
@Data
public class StudentVo {
private Integer studentid;
private Integer gradeid;
private String studentname;
private String address;
private Date borndate;
}
2.4.3:结构展示:
3.现在的需求是这样的:
需要通过年级表中的年级id<gradeid>查询学生信息并通过多级菜单的形式给展示出来:
展示效果就是文章的前言部分;
3.1:那我们就开始撸代码吧
首先我们需要前台给我们传递一个年纪id<gradeid>:对应的controller层编写;
@RestController
@RequestMapping("/grade")
public class GradeController {
@Autowired
private GradeService gradeService;
/**
*通过前台给我们传递一个年纪id,最后返回的数据时我们创建的GradeVo
*/
@GetMapping("/gradeId/{gradeid}")
public R grdeId(@PathVariable("gradeid")Integer gradeid){
List<GradeVo> gradeVos = gradeService.gradeById(gradeid);
return R.ok().data("gradeVos",gradeVos);
}
}
接下来就是GradeServicer层:
public interface GradeService extends IService<Grade> {
/**
* 根据年级id多级菜单查询学生信息
* @param gradeid
* @return
*/
List<GradeVo> gradeById(Integer gradeid);
}
然后在GradeServiceImpl层实现我们写的方法:
@Service
public class GradeServiceImpl extends ServiceImpl<GradeMapper, Grade> implements GradeService {
@Autowired
private GradeMapper gradeMapper;
@Autowired
private StudentMapper studentMapper;
@Override
public List<GradeVo> gradeById(Integer gradeid) {
//先通过年级表对比数据查询出来相应数据
QueryWrapper<Grade> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("gradeid",gradeid);
List<Grade> grades = baseMapper.selectList(queryWrapper);
//这时候就展现出外键的作用了,同样通过传递年级id查询对应的学生信息
QueryWrapper<Student> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("gradeid",gradeid);
List<Student> students = studentMapper.selectList(queryWrapper1);
//创建一个集合接收我们要返回给前台的数据 List<T> T就是我们需要返回的数据类型
List<GradeVo> findList= new ArrayList<>();
//再创建一个集合来接收学生信息表的数据
List<StudentVo> findList2 = new ArrayList<>();
//帮查询出来的数据遍历 注:遍历的方式有很多种这只是其中一种
for (int i = 0; i <grades.size() ; i++) {
//帮数据遍历给grade对象
Grade grade = grades.get(i);
GradeVo gradeVo = new GradeVo();
//然后在帮grade的数据通过BeanUtils.copyProperties()方法复制给gradeVo
BeanUtils.copyProperties(grade,gradeVo);
//因为我们查询的是多条数据,所以返回的是集合而不是对象
//帮gradeVo对象的数据给findList集合里面
findList.add(gradeVo);
//同样的学生表一样的遍历方法,最后把数据放到findList2集合中
for (int j = 0; j < students.size(); j++) {
Student student = students.get(j);
StudentVo studentVo = new StudentVo();
BeanUtils.copyProperties(student,studentVo);
findList2.add(studentVo);
}
/**
* 现在我们是不是就有了两个集合 一个是年级数据的集合 另一个是学生信息数据的集合
* 问题:数据有了我们怎么帮学生数据给年级呢,而且展示的是多级菜单形式
* 解决办法:看看我们GradeVo里面是不是有一个集合:没错就是通过这个集合来实现多级菜单显示
*/
//帮包含学生信息数据的集合findList2通过GradeVo里面的结合Children给拼接出来
gradeVo.setChildren(findList2);
}
//最后返回的数据就是我们包含年级数据和学生数据的集合findList
return findList;
}
}
最后就通过postman来测试一下吧:
我的请求api接口:http://localhost:8989/grade/gradeId/2