第一章:ActiveRecord
1.1 概述(摘自官网)
- ActiveRecord(简称AR)一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,对于
ActiveRecord 往往只能感叹其优雅,所以我们也在 AR 道路上进行了一定的探索,喜欢大家能够喜欢。
什么是ActiveRecord? ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记
录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而
且简洁易懂。ActiveRecord的主要思想是:
- 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段在类中都有相应的Field;
- ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;
- ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑;
1.2 开启AR之旅
- 在MP中,开启AR非常简单,只需要实体对象继承Model即可,同时还需要重写pkVal方法,并返回主键。
- 实体对象:
package com.example.mp.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
@Accessors(chain = true)
@ToString
public class User extends Model<User> {
@TableId(type= IdType.AUTO)
private Long id;
@TableField("user_name") //解决字段名不一致
private String username;
private String password;
private String name;
private Integer age;
private String email;
@Override
public Serializable pkVal() {
return id;
}
}
- UserMapper.java
package com.example.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mp.domain.User;
import org.apache.ibatis.annotations.Mapper;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:10
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
注意:UserMapper不能删除。
1.3 根据主键查询
- 示例:
package com.example.mp;
import com.example.mp.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-19 18:47
*/
@SpringBootTest
public class TestActiveRecord {
@Test
public void testSelectById() {
User user = new User().setId(1L).selectById();
System.out.println("user = " + user);
}
}
1.4 新增数据
- 示例:
package com.example.mp;
import com.example.mp.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-19 18:47
*/
@SpringBootTest
public class TestActiveRecord {
@Test
public void testInsert(){
boolean flag = new User()
.setUsername("xudaxian")
.setEmail("xudaxian@qq.com")
.setPassword("123456")
.setName("许大仙")
.setAge(18).insert();
System.out.println("flag = " + flag);
}
}
1.5 更新数据
- 示例:
package com.example.mp;
import com.example.mp.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-19 18:47
*/
@SpringBootTest
public class TestActiveRecord {
@Test
public void testUpdate(){
User user = new User();
user.setId(1L);
user.setAge(18);
boolean flag = user.updateById();
System.out.println("flag = " + flag);
}
}
1.6 删除数据
- 示例:
package com.example.mp;
import com.example.mp.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-19 18:47
*/
@SpringBootTest
public class TestActiveRecord {
@Test
public void testDelete(){
User user = new User();
user.setId(1L);
boolean flag = user.deleteById();
System.out.println("flag = " + flag);
}
}
1.7 根据条件查询数据
- 示例:
package com.example.mp;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mp.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-19 18:47
*/
@SpringBootTest
public class TestActiveRecord {
@Test
public void testSelect(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.le("age","20");
User user = new User();
List<User> userList = user.selectList(wrapper);
System.out.println("userList = " + userList);
}
}
第二章:Mybatis Plus的插件
2.1 mybatis的插件机制
- mybatis允许我们在已映射语句执行过程中的某一点进行拦截调用。默认情况下,Mybatis允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
- 我们可以看到可以拦截Executor接口的部分方法,比如update、query、commit、rollback等方法,还有其他接口的一些方法等。
- 总体概况为:
- 拦截执行器的方法。
- 拦截参数的处理。
- 拦截结果集的处理。
- 拦截Sql语法构建的处理。
- 示例:
- ①自定义拦截器
package com.example.mp.plugins;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Statement;
import java.util.Properties;
/**
* //定义拦截那个对象的那个方法的那个参数
*/
@Intercepts({@Signature(type = StatementHandler.class, method = "parameterize", args = Statement.class)})
public class MyInterceptor implements Interceptor {
/**
* 拦截目标对象的目标方法的执行
*
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("--------MyInterceptor.intercept------------"+invocation.getMethod());
//执行目标方法
Object proceed = invocation.proceed();
return proceed;
}
/**
* 包装目标对象:为目标对象创建一个代理对象
*
* @param target
* @return
*/
@Override
public Object plugin(Object target) {
System.out.println("------MyInterceptor--plugin-------"+target);
//借助Plugin的wrap使用当前的拦截器包装目标对象
Object wrap = Plugin.wrap(target, this);
//为当前target创建的动态代理
return wrap;
}
/**
* 将插件注册时的properties属性设置进来
*
* @param properties
*/
@Override
public void setProperties(Properties properties) {
System.out.println("插件配置的信息 = " + properties);
}
}
- ②注册到Spring的容器中:
package com.example.mp.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.example.mp.plugins.MyInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 22:42
*/
@Configuration
public class MybatisPlusConfig {
// 配置分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* 注册 插件
*
* @return
*/
@Bean
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}
}
2.2 防止全表更新与删除插件
- 在MP中提供了防止全表更新与删除插件。
注意:此插件仅适用于开发环境,不适用于生产环境。
- 示例:
- ①配置防止全表更新与删除的插件
package com.example.mp.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 22:42
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//配置分页插件
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
//配置防止全表更新与删除的插件
BlockAttackInnerInterceptor blockAttackInnerInterceptor = new BlockAttackInnerInterceptor();
interceptor.addInnerInterceptor(blockAttackInnerInterceptor);
return interceptor;
}
}
- ②测试:
package com.example.mp;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.mp.domain.User;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 19:22
*/
@SpringBootTest
public class TestUpdate {
@Autowired
private UserMapper userMapper;
@Test
public void test() {
//封装更新字段的对象
User user = new User();
user.setAge(18);
try {
int result = userMapper.update(user, null);
System.out.println("result = " + result);
} catch (MyBatisSystemException e) {
e.printStackTrace();
}
}
}
- ③结果。
2.3 乐观锁插件
2.3.1 主要适用场景
- 当要更新一条记录的时候,希望这条记录没有被别人更新。
- 乐观锁实现方式:
- ①取出记录时,获取当前version。
- ②更新时,带上这个version。
- ③执行更新时,
set version = newVersion where version = oldVersion
。 - ④如果version不对,就更新失败。
2.3.2 插件配置
- 乐观锁配置:
package com.example.mp.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 22:42
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//配置分页插件
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
//乐观锁配置
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
//配置防止全表更新与删除的插件
BlockAttackInnerInterceptor blockAttackInnerInterceptor = new BlockAttackInnerInterceptor();
interceptor.addInnerInterceptor(blockAttackInnerInterceptor);
return interceptor;
}
}
2.3.3 注解实体字段
- 需要为实体字段添加
@Version
注解。 - ①修改表,添加
version
字段,并且设置初始值为1。
ALTER TABLE `tb_user` ADD COLUMN `version` int NULL ;
UPDATE `tb_user` SET `version`='1';
- ②为User实体对象添加
version
字段,并且添加@Version
注解。
package com.example.mp.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
//@TableName("tb_user")
@ToString
@Accessors(chain = true)
public class User implements Serializable {
@TableId(type= IdType.AUTO)
private Long id;
@TableField("user_name") //解决字段名不一致
private String username;
private String password;
private String name;
private Integer age;
private String email;
@Version
private Integer version;
}
2.3.4 测试
- 测试:
package com.example.mp;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.mp.domain.User;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 19:22
*/
@SpringBootTest
public class TestUpdate {
@Autowired
private UserMapper userMapper;
@Test
public void testOptimisticLocker() {
//先查询再修改,会触发乐观锁配置,即实体对象中要有version字段值
User user = userMapper.selectById(1);
user.setUsername("许大仙");
int result = userMapper.updateById(user);
System.out.println("result = " + result);
}
}
2.3.5 特别说明
- 支持的数据类型只有:int、Integer、long、Long、Date、Timestamp、LocalDateTime。
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
第三章:SQL注入器
3.1 概述
- 我们知道,在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到Mybatis容器中,这样这些方法才可以正常执行。
- 那么,我们如果需要扩充BaseMapper中的方法,又该如何实现。
3.2 编写MyBaseMapper
- MyBaseMapper.java
package com.example.mp.config;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface MyBaseMapper<T> extends BaseMapper<T> {
List<T> findALl();
}
- 其他的Mapper都可以继承该Mapper,这样实现了统一的扩展:
package com.example.mp.mapper;
import com.example.mp.config.MyBaseMapper;
import com.example.mp.domain.User;
import org.apache.ibatis.annotations.Mapper;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:10
*/
@Mapper
public interface UserMapper extends MyBaseMapper<User> {
}
3.3 编写FindAll
package com.example.mp.config;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class FindAll extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sqlMethod = "findAll";
String sql = "select * from " + tableInfo.getTableName();
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql,
modelClass);
return this.addSelectMappedStatementForTable(mapperClass, sqlMethod, sqlSource, tableInfo);
}
}
3.4 编写MySqlInjector
- 如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,我们选择继承DefaultSqlInjector来实现扩展。
package com.example.mp.config;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new FindAll());
return methodList;
}
}
3.5 测试
package com.example.mp;
import com.example.mp.domain.User;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MpApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void test(){
List<User> userList = userMapper.findAll();
System.out.println("userList = " + userList);
}
}
第四章:自动填充
4.1 概述
- 有些时候,我们可能会有这样的需求,插入或更新数据的时候,希望有些字段可以自动填充数据,比如:密码、version等。在MP中提供了这样的功能,可能实现自动填充。
4.2 添加@TableField注解
- User.java
package com.example.mp.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Accessors(chain = true)
public class User implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("user_name") //解决字段名不一致
private String username;
private String password;
private String name;
private Integer age;
private String email;
@Version
private Integer version;
/**
* 为createTime添加自动填充功能,在新增数据的时候有效
*/
@TableField(value = "create_time",fill = FieldFill.INSERT)
private Date createTime;
/**
* 为updateTime添加自动填充功能,在更新数据的时候有效
*/
@TableField(value = "update_time",fill = FieldFill.UPDATE)
private Date updateTime;
}
- sql脚本:
ALTER TABLE `tb_user` ADD COLUMN `create_time` datetime NULL ;
ALTER TABLE `tb_user` ADD COLUMN `update_time` datetime NULL ;
- FieldFill提供了多种模式选择:
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入时填充字段
*/
INSERT,
/**
* 更新时填充字段
*/
UPDATE,
/**
* 插入和更新时填充字段
*/
INSERT_UPDATE
}
4.3 自定义MetaObjectHandler
package com.example.mp.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;
@Slf4j
@Component
public class MPMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", () -> new Date(), Date.class);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", () -> new Date(), Date.class);
}
}
4.4 测试
- 示例:
package com.example.mp;
import com.example.mp.domain.User;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MpApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setUsername("zhangsan");
user.setPassword("123456");
user.setName("张三");
user.setAge(18);
user.setEmail("123456@qq.com");
int count = userMapper.insert(user);
System.out.println("count = " + count); //数据库受影响的行数
System.out.println("user.getId() = " + user.getId()); //自增后的id会回填到对象中
}
}
- 结果:
第五章:逻辑删除
5.1 概述
- 开发系统的时候,有时候在实现功能的时候,删除操作需要实现逻辑删除,所谓的逻辑删除就是将数据标记为删除,而非真正的物理删除(非DELETE操作),查询的时候需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。
5.2 修改表结构
- 为
tb_user
表添加deleted
字段,用于表示数据是否被删除,1代表删除,0代表未删除。
ALTER TABLE `tb_user` ADD COLUMN `deleted` INT ( 1 ) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;
- 修改User实体,增加deleted属性,并添加@TableLogic注解。
package com.example.mp.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Accessors(chain = true)
public class User implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("user_name") //解决字段名不一致
private String username;
private String password;
private String name;
private Integer age;
private String email;
@Version
private Integer version;
/**
* 为createTime添加自动填充功能,在新增数据的时候有效
*/
@TableField(value = "create_time",fill = FieldFill.INSERT)
private Date createTime;
/**
* 为updateTime添加自动填充功能,在更新数据的时候有效
*/
@TableField(value = "update_time",fill = FieldFill.UPDATE)
private Date updateTime;
@TableLogic
private Integer deleted;
}
5.3 配置
- application.yml
# MP配置
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
logic-delete-field: deleted #全局逻辑删除的实体字段名
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
configuration:
# 开启日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5.4 测试
- 测试删除:
package com.example.mp;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 20:04
*/
@SpringBootTest
public class TestDeleteById {
@Autowired
private UserMapper userMapper;
@Test
public void test(){
//执行删除操作
int result = userMapper.deleteById(6);
System.out.println("result = " + result);
}
}
- 结果:
- 测试查询:
package com.example.mp;
import com.example.mp.domain.User;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-18 21:00
*/
@SpringBootTest
public class TestSelectById {
@Autowired
private UserMapper userMapper;
@Test
public void test(){
//根据id查询数据
User user = userMapper.selectById(6);
System.out.println("user = " + user);
}
}
- 结果:
第六章:通用枚举
6.1 概述
- 解决了繁琐的配置,让 mybatis 优雅的使用枚举属性!
6.2 修改表结构
ALTER TABLE `tb_user`
ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;
6.3 定义枚举
package com.example.mp.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
public enum SexEnum implements IEnum<Integer> {
MAN(1,"男"),
WOMAN(2,"女");
private int value;
private String desc;
SexEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public Integer getValue() {
return value;
}
}
6.4 配置
- application.yml
# MP配置
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
logic-delete-field: deleted #全局逻辑删除的实体字段名
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
configuration:
# 开启日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 配置枚举包扫描
type-enums-package: com.example.mp.enums
6.5 修改实体
package com.example.mp.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.example.mp.enums.SexEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @author 许大仙
* @version 1.0
* @since 2021-06-17 21:01
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Accessors(chain = true)
public class User implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("user_name") //解决字段名不一致
private String username;
private String password;
private String name;
private Integer age;
private String email;
//性别为枚举
private SexEnum sex;
@Version
@TableField(value = "version", fill = FieldFill.INSERT)
private Integer version;
/**
* 为createTime添加自动填充功能,在新增数据的时候有效
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
/**
* 为updateTime添加自动填充功能,在更新数据的时候有效
*/
@TableField(value = "update_time", fill = FieldFill.UPDATE)
private Date updateTime;
@TableLogic
private Integer deleted;
}
6.6 测试
- 示例:
package com.example.mp;
import com.example.mp.domain.User;
import com.example.mp.enums.SexEnum;
import com.example.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MpApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert(){
User user = new User();
user.setUsername("wangba");
user.setPassword("123456");
user.setName("王八");
user.setAge(18);
user.setEmail("123456@qq.com");
user.setSex(SexEnum.MAN);
int count = userMapper.insert(user);
System.out.println("count = " + count); //数据库受影响的行数
System.out.println("user.getId() = " + user.getId()); //自增后的id会回填到对象中
}
}
- 结果:
第七章:代码生成器
7.1 概述
- AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
7.2 创建工程
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>mp-generator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mp-generator</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mybatis-plus对SpringBoot的支持 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7.3 生成器代码
package com.example.mp.generator;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Scanner;
public class MysqlGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help);
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
/**
* RUN THIS
*/
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("许大仙");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.example.mp.generator");
mpg.setPackageInfo(pc);
// // 自定义配置
// InjectionConfig cfg = new InjectionConfig() {
// @Override
// public void initMap() {
// // to do nothing
// }
// };
// List<FileOutConfig> focList = new ArrayList<>();
// focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
// @Override
// public String outputFile(TableInfo tableInfo) {
// // 自定义输入文件名称
// return projectPath + "/xudaxain-mp-generator/src/main/resources/mapper/" + pc.getModuleName()
// + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
// }
// });
// cfg.setFileOutConfigList(focList);
// mpg.setCfg(cfg);
// mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
strategy.setEntityLombokModel(true);
// strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
strategy.setInclude(scanner("表名"));
strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}