文章目录
前言
文中controller中的返回类是我自定义的,源码中有,我的另一篇文章也有返回类,源码中还有文中表和数据的sql
源码地址:mybatis-plus
一、springboot和mybatis-plus整合
1、依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
2、配置文件
# 应用名称
spring:
application:
name: mybatis-plus
datasource:
driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: 123456
server:
port: 8782
#指定Mybatis的Mapper文件
mybatis:
mapper-locations: classpath:mappers/*xml
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志打印
3、启动类
启动类加@MapperScan注解,里面的内容为你自己mapper层接口的包。
@SpringBootApplication
@MapperScan("com.sofar.mybatisplus.mapper")
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
4、service接口,service实现类,mapper
mybatis-plus跟我们平时写的项目结构一样,由service到service实现类,到mapper。
service:IService
service实现类:ServiceImpl<M extends BaseMapper, T>
mapper:BaseMapper
mybatis-plus提供这几个都是泛型类,对应的泛型是我们要操作的的表对应的实体类,我们要操作一个表对应下来的service,service实现类,mapper的泛型都应该是同一个类。
1、service
public interface TblProductService extends IService<TblProduct> {
/**
* 分页查询
* @param tblProduct
* @param iPage
* @return
*/
IPage<TblProduct> queryByPage(TblProduct tblProduct, IPage<TblProduct> iPage);
}
2、service实现类
当你service实现类继承了ServiceImpl<M extends BaseMapper, T>后,会提示你要实现接口方法,但是你自己的接口明明实现了。不要着急,那是因为ServiceImpl依赖于BaseMapper,ServiceImpl<M extends BaseMapper, T>里面已经明确指出要继承BaseMapper,在mapper接口中去继承就好了,请看下一步。
这里有个小故事分享给大家,是我在工作中发现的,我们项目也用了mybatis-plus,有一个同事在写service和service实现类的时候,他mapper没有继承BaseMapper,而是在service实现类中去实现mybatis-plus的接口的方法,但是他只是实现了接口方法,并没有在方法里面写业务代码。相当于是他只是让报错消失,并没有解决问题。有一次我在控制层中调用mybatis-plus service 自带的方法新增数据,一直失败,我一直以为是数据原因,到后面才发现是没有service实现类中的新增数据方法是空,没有想到自带的方法被他实现了,但方法里没有具体实现,是空方法,导致新增失败,吐血。
提醒:继承的mybatis-plus的类后,不能跟基类的方法名一直,不然就是方法覆盖。自己真的想覆盖,可以写,不要搞出我上面陈诉的那种情况。
@Service("tblProductService")
public class TblProductServiceImpl extends ServiceImpl<TblProductMapper,TblProduct> implements TblProductService {
@Resource
private TblProductMapper tblProductMapper;
@Override
public IPage<TblProduct> queryByPage(TblProduct tblProduct, IPage<TblProduct> iPage) {
return tblProductMapper.queryAllByPage(tblProduct, iPage);
}
}
3、mapper
public interface TblProductMapper extends BaseMapper<TblProduct> {
/**
* 分页查询
* @param tblProduct
* @param iPage
* @return
*/
IPage<TblProduct> queryAllByPage(@Param("req") TblProduct tblProduct, IPage<TblProduct> iPage);
}
二.枚举类型处理及遇到坑解决
开发中我们经常用到枚举,例如性别,前端我们需要展示男、女,而数据库我们存的是1、0。
一、创建枚举类,在需要存储数据库的属性上添加@EnumValue注解,在需要前端展示的属性上添加@JsonValue注解;
@JsonValue可以用在get方法或者属性字段上,一个类只能用一个,当加上@JsonValue注解时,该类的json化结果,只有这个get方法的返回值,而不是这个类的属性键值对.
public enum SexEnum {
/**
* 女
*/
WOMAN(0,"女"),
/**
* 男
*/
MAN(1, "男");
@EnumValue
private Integer code;
@JsonValue
private String value;
SexEnum(int code, String value){
this.code = code;
this.value = value;
}
public Integer getCode(){
return this.code;
}
public String getValue(){
return this.value;
}
}
二、配置文件
#配置枚举 支持通配符 * 或者 ; 分割
mybatis-plus:
configuration:
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
type-enums-package: com.sofar.mybatisplus.enums #扫描枚举包
三、将实体类中的sex属性设置为枚举SexEnum;
/**
* 性别:0:女、 1:男
*/
private SexEnum sex;
四、遇到的问题
刚开始我数据库表中sex字段类型为tinyint,而SexEnum枚举中带@EnumValue注解的属性类型为Integer(如下面两张图所示),数据类型不一致,导致无法转换。调用接口sex字段一直为null,后面我将数据库字段类型换成int类型,才转换成功。@EnumValue注解是放在与数据库表字段对应的属性上,而且要保证与数据库字段类型要一致,才能转换成功
五、测试
controller中直接调用mybatis-plus自带的getById(id)方法。没有任何的业务处理,直接查库
/**
* 通过id查询
* @param id
* @return
*/
@GetMapping("getById/{id}")
public AjaxResult getById(@PathVariable("id") Long id){
TblUser byId = tblUserService.getById(id);
return Result.success(byId);
}
数据库数据,性别存了0、1
调用接口结果,自动将数据库的0、1转换成女、男
三.字段自动填充及问题解决
在开发中我们的表通常都会有创建时间、创建人、更新时间、更新人这几个字段,通常各个表都会统一这些字段的名称和类型。在我们新增各个表的数据的时候,都需要手动去维护这些字段,显得很麻烦、冗余,mybatis-plus提供了字段自动填充功能,帮我们解决了这一问题。
1、字段加注解
@TableField是字段注解(非主键),fill(字段自动填充策略),共有四种。DEFAULT、INSERT、UPDATE、INSERT_UPDATE,策略含义跟命名一致
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
2、自定义实现类 MyMetaObjectHandler
package com.sofar.mybatisplus.config;
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.util.Date;
/**
* @author
* @version 1.0.0
* @ClassName MyMetaObjectHandler
* @Description TODO
* @createTime 2022年08月31日 15:42:00
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 判断是否存在该字段,有的表没有,没有不用执行填充代码,避免资源浪费
boolean createTime = metaObject.hasSetter("createTime");
boolean updateTime = metaObject.hasSetter("updateTime");
log.info("start insert fill ....");
if (createTime){
// 填充的类型要和实体类的类型要一致,例如实体类是Date,填充是LocalDateTime,最后填充结果为null
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
}
if (updateTime){
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
}
}
/**
*
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
boolean updateTime = metaObject.hasSetter("updateTime");
if (updateTime){
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}
}
3、遇到问题
我的实体类中创建时间的类型是Date,如下。
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
而我参照的是mybatis-plus的官方文档,然后copy过来,
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
结果:没有自动填充成功,因为实体类的创建时间类型为Date,而我填充的是LocalDateTime。类型不一致,无法自动填充。
四、多数据源
1、依赖
<!-- mybatis-plus 多数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
2、配置文件
# 应用名称
spring:
application:
name: mybatis-plus
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: 123456
slave_1:
driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC
username: root
password: 123456
server:
port: 8782
#指定Mybatis的Mapper文件
mybatis:
mapper-locations: classpath:mappers/*xml
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、@DS注解
@DS注解可以放在类上,也可以放在方法上,当放在类上,数据源作用在类上(即类中所有方法都使用该数据源),放在方法上,数据源作用在方法上,当类和方法都有@DS注解,以方法的数据源为主。
@Service("tblUserService")
public class TblUserServiceImpl extends ServiceImpl<TblUserMapper,TblUser> implements TblUserService {
@Resource
private TblUserMapper tblUserMapper;
@DS("master")
@Override
public TblUser queryById(Long id) {
return this.getById(id);
}
}
4、测试
(1)、数据准备
准备两个数据库,我这里是test,test2,test中的tbl_user有两条数据,id分别为1、2,test2中有一条数据id为3
test
test2
(2)测试master数据源
controller
@RestController
@RequestMapping("tblUser")
public class TblUserController {
/**
* 服务对象
*/
@Resource
private TblUserService tblUserService;
/**
* 通过id查询
* @param id
* @return
*/
@GetMapping("getById/{id}")
public AjaxResult getById(@PathVariable("id") Long id){
TblUser byId = tblUserService.queryById(id);
return Result.success(byId);
}
}
service
public interface TblUserService extends IService<TblUser> {
/**
* 通过id查询单条数据
* @param id
* @return
*/
TblUser queryById(Long id);
}
serviceImpl
@Service("tblUserService")
public class TblUserServiceImpl extends ServiceImpl<TblUserMapper,TblUser> implements TblUserService {
@Resource
private TblUserMapper tblUserMapper;
@DS("master")
@Override
public TblUser queryById(Long id) {
return this.getById(id);
}
}
结果:查询到了id为1的数据
(3)查询slave_1数据源
其他层跟测试master数据源一样,serviceImpl方法上的@DS注解修改成slave_1数据源
@Service("tblUserService")
public class TblUserServiceImpl extends ServiceImpl<TblUserMapper,TblUser> implements TblUserService {
@Resource
private TblUserMapper tblUserMapper;
@DS("slave_1")
@Override
public TblUser queryById(Long id) {
return this.getById(id);
}
}
结果:查询到id为3的数据
至此测试完成,多数据源配置成功
五、后话
这是我个人的学习笔记,有错望指出!谢谢!