第4章-第3节
一、知识点
Mybatis-Plus、mapstruct
二、目标
-
理解为什么要过滤敏感字段
-
如何使用查询过滤
-
Mybatis-Plus如何使用联表分页查询
-
如何实现字段的自动填充
三、内容分析
-
重点
-
掌握几种过滤敏感字段的方式
-
掌握Mybatis-Plus的联表分页查询方式
-
掌握字段自动填充的实现
-
-
难点
-
掌握几种过滤敏感字段的方式
-
掌握Mybatis-Plus的联表分页查询方式
-
掌握字段自动填充的实现
-
四、内容
1、过滤敏感字段
有的时候有一些敏感数据不方便发给前端,比如用户的密码信息、一些不需要的字段、不能给前端看的数据字段,这个时候这种字段就需要过滤一下
1.1 创建一个要返回给前端的数据实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentVo {
private Long id;
private String name;
private Integer sex;
private Integer age;
private Long classId;
// 在这边 我们认为下面的几个字段是不需要给前端的,将其取消掉
// 代码中不用写,这边只是为了突出不要的是这几个字段
// private Date createTime;
// private String createBy;
// private Date updateTime;
// private String updateBy;
// private Integer delFlag;
}
1.2 传统方法
@GetMapping("/list")
public List<StudentVo> queryList() {
Page<Student> studentPage = new Page<>(1, 5);
Page<Student> page = service.page(studentPage);
List<Student> students = page.getRecords();
List<StudentVo> studentVos = new ArrayList<>();
// 循环对象集合,对需要保存的字段进行赋值加入集合
for (Student s : students) {
StudentVo s2 = new StudentVo();
s2.setName(s.getName());
s2.setClassId(s.getClassId());
s2.setSex(s.getSex());
// 可以发现,如果字段很多那么这个操作很繁琐
studentVos.add(s2);
}
return studentVos;
}
1.2 使用BeanUtils
@GetMapping("/list")
public List<StudentVo> queryList() {
Page<Student> studentPage = new Page<>(1, 5);
Page<Student> page = service.page(studentPage);
List<Student> students = page.getRecords();
List<StudentVo> studentVos = new ArrayList<>();
// 循环对象集合,对需要保存的字段进行赋值加入集合
for (Student s : students) {
StudentVo s2 = new StudentVo();
// 简化操作,但是效率比较低
BeanUtils.copyProperties(s,s2);
studentVos.add(s2);
}
return studentVos;
}
1.3 使用插件 mapstruct
1.3.1 导入依赖
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.2.Final</version>
</dependency>
1.3.2 建一个专门用于映射的文件夹mapping
@Mapper
public interface StudentMapping {
StudentMapping INSTANCE = Mappers.getMapper(StudentMapping.class);
StudentVo toStudentVo(Student student);
}
1.3.3 使用
@GetMapping("/list")
public List<StudentVo> queryList() {
Page<Student> studentPage = new Page<>(1, 5);
Page<Student> page = service.page(studentPage);
List<Student> students = page.getRecords();
List<StudentVo> studentVos = new ArrayList<>();
// 循环对象集合,对需要保存的字段进行赋值加入集合
for (Student s : students) {
StudentVo s2 = StudentMapping.INSTANCE.toStudentVo(s);
studentVos.add(s2);
}
return studentVos;
}
1.3.4 也可以直接处理list
@Mapper
public interface StudentMapping {
StudentMapping INSTANCE = Mappers.getMapper(StudentMapping.class);
StudentVo toStudentVo(Student student);
List<StudentVo> toStudentVoList(List<Student> studentList);
}
@GetMapping("/list")
public List<StudentVo> queryList() {
Page<Student> studentPage = new Page<>(1, 5);
Page<Student> page = service.page(studentPage);
List<Student> students = page.getRecords();
List<StudentVo> studentVos = StudentMapping.INSTANCE.toStudentVoList(students);
return studentVos;
}
1.3.5 通过配置自动生成的方法来映射字段
@Mappings({
@Mapping(source = "money", target = "studentMoney")
})
MsStudentVo msStudentToMsStudentVo(MsStudent msStudent);
2、联表分页查询
查询每个班级的学生 -> 查询每个班级,以及这个班级的学生数量
2.1 创建要返回的数据的实体类
@Data
public class ClassStudentVo {
private Long id;
private String name;
private List<Student> studentList;
}
2.2 创建ClassMapper
@Repository
public interface ClassMapper extends BaseMapper<ClassStudentVo> {
// 由于Mybatis本身没有联表查询的操作,所以我们要自己手写一个方法来实现
Page<ClassStudentVo> queryClassAndStudent(@Param("page") Page<ClassStudentVo> page,@Param(Constants.WRAPPER) Wrapper<ClassStudentVo> wrapper);
}
2.3 接口中创建方法
public interface IClassService extends IService<ClassStudentVo> {
Page<ClassStudentVo> queryClassAndStudent(Page<ClassStudentVo> page, Wrapper<ClassStudentVo> wrapper);
}
2.4 实现类重写方法
@Service
public class ClassService extends ServiceImpl<ClassMapper, ClassStudentVo> implements IClassService {
@Autowired
private ClassMapper mapper;
@Override
public Page<ClassStudentVo> queryClassAndStudent(Page<ClassStudentVo> page, Wrapper<ClassStudentVo> wrapper) {
return mapper.queryClassAndStudent(page, wrapper);
}
}
2.5 两种实现方式
-
集中式
ClassController.java
@GetMapping("/queryClassAndStudent") public List<ClassStudentVo> queryAll(ClassStudentVo classStudentVo) { Page<ClassStudentVo> classPage = new Page<>(1, 5); QueryWrapper<ClassStudentVo> wrapper = new QueryWrapper<>(); wrapper.eq(StringUtils.isNotEmpty(classStudentVo.getId()), "c.id", classStudentVo.getId()); Page<ClassStudentVo> page = service.queryClassAndStudent(classPage, wrapper); System.out.println(page.getTotal()); return page.getRecords(); }
classMapper.xml
<!-- 配置关联 --> <resultMap id="classStudentVoRes" type="com.example.demo.entity.vo.ClassStudentVo"> <id property="id" column="id"/> <result property="name" column="name"/> <collection property="studentList" ofType="com.example.demo.entity.Student" autoMapping="true"> <id property="id" column="studentId"/> <result property="name" column="studentName"/> <result property="age" column="age"/> </collection> </resultMap> <!-- 查询语句 --> <select id="queryClassAndStudent" resultMap="classStudentVoRes"> SELECT c.id, c.name, s.id studentId, s.name studentName, s.sex, s.age, s.class_id FROM class c LEFT JOIN student s on c.id = s.class_id <!-- ${ew.customSqlSegment}这个是固定写法一定要加,不然条件就无效了 --> ${ew.customSqlSegment} </select>
-
分布式
ClassController.java
@GetMapping("/queryClassAndStudent2") public List<ClassStudentVo> queryAll2(ClassStudentVo classStudentVo) { Page<ClassStudentVo> classPage = new Page<>(1, 5); QueryWrapper<ClassStudentVo> wrapper = new QueryWrapper<>(); wrapper.eq(StringUtils.isNotEmpty(classStudentVo.getId()), "id", classStudentVo.getId()); Page<ClassStudentVo> page = service.queryClassAndStudent(classPage, wrapper); System.out.println(page.getTotal()); return page.getRecords(); }
classMapper.xml
<!-- 配置关联 --> <resultMap id="classStudentVoRes" type="com.example.demo.entity.vo.ClassStudentVo"> <id property="id" column="id"/> <!-- <result property="name" column="name"/>--> <collection property="studentList" ofType="com.example.demo.entity.Student" select="getStudentsByClassId" column="{classId=id}"/> </resultMap> <!-- 班级的查询 --> <select id="queryClassAndStudent" resultMap="classStudentVoRes"> SELECT id,name FROM class <!-- ${ew.customSqlSegment}这个是固定写法一定要加,不然条件就无效了 --> ${ew.customSqlSegment} </select> <!-- 内部的子查询 --> <select id="getStudentsByClassId" resultType="com.example.demo.entity.Student"> SELECT id, name, sex, age, class_id FROM student WHERE class_id = #{classId} </select>
3、字段自动填充
3.1 字段注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
3.2 封装一个填充类
@Component
public class FieldHandler implements MetaObjectHandler {
/**
* 插入时的填充策略
*
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
/**
* 更新时的填充策略
*
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
3.3 执行对应的语句即可
4、小结
本章节中我们学习了Mybatis-Plus的联表分页查询、字段的自动填充和敏感字段的过滤,对Mybatis-Plus的操作更加得心应手,课后再通过练习进行巩固彻底掌握Mybatis-Plus的使用。
下一节中我们将会学到项目中会用到的插件-jwt,了解什么是CSRF攻击手段,学习如何防范、掌握真实项目中的登录流程。