springboot集成mybatis-plus全过程
作者:zhuang先森
本文详细介绍了如何在SpringBoot环境下集成MyBatis-Plus,包括配置maven依赖、application.yaml文件、创建数据库和Java实体类、Mapper层、Service层和Controller层的设置,同时,还涵盖了时间自动填充、分页查询、多对一和一对多的数据库映射关系设置
springboot集成mybatis-plus
环境:
- jdk 1.8
- springboot: 2.5.14
一、配置
1、maven依赖
<dependencies> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> </dependencies> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependencies> <dependencyManagement> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.5.14</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2、配置文件application.yaml
#数据源配置 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://1.13.152.218:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: zhuang123 #数据库名称 project: database: mysql #mybatis-plus配置 mybatis-plus: configuration: #sql日志打印 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启驼峰命名匹配 map-underscore-to-camel-case: true #mapper文件 mapper-locations: classpath:mapper/${project.database}/**/*.xml,classpath:mapper/*.xml #数据库实体类的包全路径,方便在mapper.xml中不许使用实体类的全路径,写类名就行(不区分大小写) type-aliases-package: com.zhuang.mp.entity global-config: db-config: #逻辑删除 logic-delete-value: 0 logic-not-delete-value: 1 logic-delete-field: deleted
二、创建过程
1.创建数据库与java实体类
新建user表:
java实体类:
package com.zhuang.mp.entity; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Builder; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import java.util.Date; @Data @Builder @TableName(value = "user") public class User { @TableId(type = IdType.AUTO) private Long id; @JsonAlias("user_name") private String name; @JsonAlias("user_age") private Integer age; @JsonAlias("user_email") private String email = "862627527@qq.com"; @TableField(value = "create_time", fill = FieldFill.INSERT) //后端传给前端的时间格式 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") //前端传给后端的时间格式 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonAlias("create_time") private Date createTime; @JsonAlias("update_time") @TableField(value = "update_time" ,fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; }
2.mapper或dao层
UserMapper接口:继承BaseMapper<T>
, T为实体类User,需要加上@Mappe
r注解,如果不加注解需要在启动类上加@MapperScan
注解
package com.zhuang.mp.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.zhuang.mp.entity.User; import com.zhuang.mp.entity.UserVo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; @Mapper public interface UserMapper extends BaseMapper<User> { List<User> searchByAges(@Param("ages") List<Long> ages); List<UserVo> selectBynames(@Param("names") List<String> names); }
3.mapper.xml文件
一般放在类路径下:src/main/resources/mapper/
设置命名空间 namespace
namespace
=“com.zhuang.mp.mapper.UserMapper
”
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zhuang.mp.mapper.UserMapper"> <resultMap id="userResultMap" type="User"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="email" column="email"/> <result property="createTime" column="create_time"/> <result property="updateTime" column="update_time"/> </resultMap> <select id="searchByAges" resultType="com.zhuang.mp.entity.User"> select * from user where age in <foreach collection="ages" item="age" open="(" close=")" separator=","> #{age} </foreach> </select> <select id="selectBynames" resultType="UserVo"> select name from user where <foreach collection="names" item="name" separator="or"> name like "%"#{name}"%" </foreach> </select> </mapper>
4.service层
UserService接口:需要继承IService<T>
, T 为实体类User
package com.zhuang.mp.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.zhuang.mp.entity.User; import com.zhuang.mp.entity.UserVo; import java.util.List; /** * @program: mp * @description: * @author: mrzhuang * @create: 2022-12-15 00:48 **/ public interface UserService extends IService<User> { int addUser(User user); int updateUser(User user); Page<User> searchPage(Page<User> page); List<User> searchByAges(List<Long> ages); List<UserVo> selectBynames(List<String> names); }
UsrServiceIpml实现类:需要继承ServiceImpl<M extends BaseMapper, T>, M为接口UserMapper, T为实体类User,需要加上@Service
注解
package com.zhuang.mp.service.impl; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.zhuang.mp.entity.User; import com.zhuang.mp.entity.UserVo; import com.zhuang.mp.mapper.UserMapper; import com.zhuang.mp.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestBody; import javax.annotation.Resource; import java.util.List; /** * @program: mp * @description: * @author: mrzhuang * @create: 2022-12-15 00:49 **/ @DS("slave_1") @Service @Slf4j public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Resource private UserMapper userMapper; @Override public int addUser(User user) { int insert = userMapper.insert(user); return insert; } @Override public int updateUser(@RequestBody User user) { int update = userMapper.updateById(user); return update; } @Override public Page<User> searchPage(Page<User> page) { Page<User> userPage = userMapper.selectPage(page, null); return userPage; } @Override public List<User> searchByAges(List<Long> ages) { List<User> list = userMapper.searchByAges(ages); return list; } @Override public List<UserVo> selectBynames(List<String> names) { return userMapper.selectBynames(names); } }
5.controller层
UserController类:
package com.zhuang.mp.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.zhuang.mp.entity.User; import com.zhuang.mp.entity.UserVo; import com.zhuang.mp.enums.CodeEnum; import com.zhuang.mp.service.UserService; import com.zhuang.mp.vo.PageVo; import com.zhuang.mp.vo.ResponseVo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; /** * @program: mp * @description: * @author: mrzhuang * @create: 2022-12-17 21:40 **/ @Slf4j @Api(tags = "用户接口") @RestController @RequestMapping("/user") public class UserController { @Resource UserService userService; @ApiOperation("用户增加") @RequestMapping("/add") public ResponseVo<User> addUser(@RequestBody User user){ log.info("user: {}", user); int insert = userService.addUser(user); if (insert > 0){ log.info("插入成功!"); return new ResponseVo<>(CodeEnum.SUCESS.code, CodeEnum.SUCESS.message); } log.error("插入失败!"); return new ResponseVo<>(CodeEnum.FAILUIRE.code, CodeEnum.FAILUIRE.message); } @RequestMapping("/update") public ResponseVo<User> updateUser(@RequestBody User user){ log.info("user: {}", user); int update = userService.updateUser(user); if (update > 0){ log.info("更新成功!"); return new ResponseVo<>(CodeEnum.SUCESS.code, CodeEnum.SUCESS.message); } log.error("更新失败!"); return new ResponseVo<>(CodeEnum.FAILUIRE.code, CodeEnum.FAILUIRE.message); } @PostMapping("/searchPage") public ResponseVo<PageVo<User>> searchPage(@RequestBody Page<User> page){ Page<User> userPage = userService.searchPage(page); PageVo<User> userPageVo = new PageVo<>(); BeanUtils.copyProperties(userPage, userPageVo); return new ResponseVo<>(userPageVo); } @PostMapping("/searchByAges") public ResponseVo<List<User>> searchByAges(@RequestBody List<Long> ages){ List<User> list = userService.searchByAges(ages); return new ResponseVo<>(list); } @PostMapping("/searchByNames") public ResponseVo<List<UserVo>> searchByNames(@RequestBody List<String> names){ List<UserVo> list = userService.selectBynames(names); return new ResponseVo<>(list); } }
三、设置时间自动填充
1.实体类日期类型设置
需要再实体类的日期属性上使用@TableField(fill = FieldFill.INSERT)
FiledFill为枚举类型
public enum FieldFill { /** * 默认不处理 */ DEFAULT, /** * 插入时填充字段 */ INSERT, /** * 更新时填充字段 */ UPDATE, /** * 插入和更新时填充字段 */ INSERT_UPDATE }
实体类:
@TableField(value = "create_time", fill = FieldFill.INSERT) //后端传给前端的时间格式 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") //前端传给后端的时间格式 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonAlias("create_time") private Date createTime; @JsonAlias("update_time") @TableField(value = "update_time" ,fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime;
2.自定义元对象处理器
实现 MetaObjectHandler
接口
package com.zhuang.mp.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.Date; @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); // 起始版本 3.3.0(推荐使用) this.strictInsertFill(metaObject, "updateTime", Date.class, new Date()); // 起始版本 3.3.0(推荐使用) // // 或者 // this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐) // // 或者 // this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug) } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐) // // 或者 // this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐) // // 或者 // this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug) } }
四、分页查询
1.配置类中创建bean
ackage com.zhuang.mp.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfig { //分页查询 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //添加分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
2.调用分页查询的方法
@Resource private UserMapper userMapper; Page<User> userPage = userMapper.selectPage(page, null);
五、多对一映射、一对多映射
举例: 一个老师有多名学生是一对多
关系,而一个学生只能有一个老师是多对一
关系
1.数据库表设计
设计studen和teacher表, 两个表中的字段命名需要不一样,否则在映射过程中会有问题。
1、student表
java实体类:包含老师属性
package com.zhuang.mp.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.annotations.ApiModel; import lombok.Data; import java.io.Serializable; /** * <p> * * </p> * * @author mrzhuang * @since 2022-12-21 */ @ApiModel(value = "Student对象", description = "") @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class Student implements Serializable { private static final long serialVersionUID = 1L; @TableId(type = IdType.AUTO) private Integer sid; @TableField(value = "s_name") private String studentName; private Integer tid; @TableField(exist = false) private Teacher teacher; }
2、teacher表:
java实体类:
package com.zhuang.mp.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; import java.util.List; /** * <p> * * </p> * * @author mrzhuang * @since 2022-12-21 */ @ApiModel(value = "Teacher对象", description = "教师") @Data @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(value = JsonInclude.Include.NON_NULL) public class Teacher implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty("老师id") @TableId(value = "t_id", type = IdType.AUTO) private Integer tid; @ApiModelProperty("老师姓名") @TableField(value = "t_name") private String teacherName; @ApiModelProperty("学生集合") @TableField(exist = false) private List<Student> studentList; }
2.多对一映射:association
StudentMapper.xml配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zhuang.mp.mapper.StudentMapper"> <resultMap id="stuResultMap" type="Student"> <id property="sid" column="s_id"/> <result property="studentName" column="s_name"/> <result property="tid" column="t_id"/> <association property="teacher" javaType="teacher"> <id property="tid" column="t_id"/> <result property="teacherName" column="t_name"/> </association> </resultMap> <select id="selectByMap" resultMap="stuResultMap"> select * from student s left join teacher t on s.t_id = t.t_id </select> </mapper>
StudentMapper类:
package com.zhuang.mp.mapper; import com.zhuang.mp.entity.Student; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.List; /** * <p> * Mapper 接口 * </p> * * @author mrzhuang * @since 2022-12-21 */ public interface StudentMapper extends BaseMapper<Student> { /** * 查询所有学生 * @return / */ List<Student> selectByMap(); }
StudentController:
package com.zhuang.mp.controller; import com.zhuang.mp.entity.Student; import com.zhuang.mp.service.IStudentService; import com.zhuang.mp.vo.ResponseVo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; /** * <p> * 前端控制器 * </p> * * @author mrzhuang * @since 2022-12-21 */ @RestController @RequestMapping("/mp/student") public class StudentController { @Resource IStudentService studentService; @GetMapping("/selectByMap") public ResponseVo<List<Student>> selsectByMap(){ /** * 查询所有学生 */ List<Student> students = studentService.selectByMap(); return new ResponseVo<>(students); } }
结果:
3.一对多映射:collection
TeacherMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zhuang.mp.mapper.TeacherMapper"> <resultMap id="techResultMap" type="teacher"> <id property="tid" column="t_id"/> <result property="teacherName" column="t_name"/> <collection property="studentList" ofType="student"> <id property="sid" column="s_id"/> <result property="studentName" column="s_name"/> <result property="tid" column="t_id"/> </collection> </resultMap> <select id="selectByMap" resultMap="techResultMap"> select * from teacher t right join student s on s.t_id = t.t_id </select> </mapper>
TeacherMapper类:
package com.zhuang.mp.mapper; import com.zhuang.mp.entity.Teacher; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.List; /** * <p> * Mapper 接口 * </p> * * @author mrzhuang * @since 2022-12-21 */ public interface TeacherMapper extends BaseMapper<Teacher> { /** * 查询全部老师 * @return */ List<Teacher> selectByMap(); }
TeacherController:
package com.zhuang.mp.controller; import com.zhuang.mp.entity.Teacher; import com.zhuang.mp.service.ITeacherService; import com.zhuang.mp.vo.ResponseVo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; /** * <p> * 前端控制器 * </p> * * @author mrzhuang * @since 2022-12-21 */ @Api(tags = "教师接口") @RestController @RequestMapping("/mp/teacher") public class TeacherController { @Resource ITeacherService teacherService; @ApiOperation("获得全部的老师") @GetMapping("searchAll") public ResponseVo<List<Teacher>> searchAll(){ List<Teacher> teachers = teacherService.searchAll(); return new ResponseVo<>(teachers); } @ApiOperation("一对一多映射") @GetMapping("/selectByMap") public ResponseVo<List<Teacher>> selectByMap(){ List<Teacher> teachers = teacherService.selectByMap(); return new ResponseVo<>(teachers); } }
结果:
六、代码生成器
1.maven依赖
<!--逆向代码生成模版--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>
2.代码编写
package com.zhuang.generator; import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.OutputFile; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.util.Collections; /** * @program: mp * @description: 逆向代码生成器 * @author: mrzhuang * @create: 2022-12-17 20:56 **/ public class CodeGenerator { public static void main(String[] args) { String url = "jdbc:mysql://1.13.152.218:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai"; String username = "root"; String password = "zhuang123"; String author = "mrzhuang"; String outputDir = "/Users/mrzhuang/Downloads/mp/generator"; String parent = "com.zhuang"; String moduleName = "mp"; String xmlPath = "/Users/mrzhuang/Downloads/mp/generator"; //String tablename = "user"; FastAutoGenerator.create(url, username, password) .globalConfig(builder -> { builder.author(author) // 设置作者 .enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir(outputDir); // 指定输出目录 }) .packageConfig(builder -> { builder.parent(parent) // 设置父包名 .moduleName(moduleName) // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.xml, xmlPath)); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("teacher").addInclude("student"); // 设置需要生成的表名 // .addTablePrefix("t_", "c_"); // 设置过滤表前缀 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。