Mybatis插件机制
- 拦截执行器的方法 Executor
- 拦截参数的处理 ParameterHandler
- 拦截结果集的处理 ResultSetHandler
- 拦截sql语法构建的处理 StatementHandler
myInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Intercepts({@Signature( type= Executor.class, // 拦截的类型 method = "update", // 拦截的方法名 args = {MappedStatement.class,Object.class})}) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //拦截方法,具体业务逻辑编写的位置 return invocation.proceed(); } @Override public Object plugin(Object target) { //创建target对象的代理对象,目的是将当前拦截器加入到该对象中 return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { //属性设置 } }
|
其中plugin方法会调用四次,分别将四种拦截器加入对象中
注入拦截器至容器
1 2 3 4
| @Bean //注入自定义的拦截器(插件) public MyInterceptor myInterceptor(){ return new MyInterceptor(); }
|
执行分析插件
可以用作阻断全表更新、删除的操作,仅适用于开发环境,不适用于生产环境(性能原因)
1 2 3 4 5 6 7 8 9 10 11 12
| @Bean //SQL分析插件 public SqlExplainInterceptor sqlExplainInterceptor(){ SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor(); List<ISqlParser> list = new ArrayList<>(); list.add(new BlockAttackSqlParser()); //全表更新、删除的阻断器 sqlExplainInterceptor.setSqlParserList(list); return sqlExplainInterceptor; }
|
性能分析插件
用于查看每条sql语句及其执行时间,可以设置最大执行时间,超出后会抛出异常。仅适用于开发环境,不适用于生产环境(性能原因)
1 2 3 4 5 6 7 8 9
| <plugins> <!-- 性能分析插件 --> <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor"> <!--最大的执行时间,单位为毫秒--> <property name="maxTime" value="100"/> <!--对输出的SQL做格式化,默认为false--> <property name="format" value="true"/> </plugin> </plugins>
|
乐观锁插件
更新一条记录的时候,禁止这条记录被别人更新
实现方式:
- 取出记录时,获得当前version
- 更新时带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,则更新失败
1
| <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>
|
需要对应数据库和实体类添加一个version字段
1 2
| @Version //乐观锁的版本字段 private Integer version;
|
Sql注入器
扩充BaseMapper
MyBaseMapper
1 2 3 4 5 6
| public interface MyBaseMapper<T> extends BaseMapper<T> { List<T> findAll(); // 扩展其他的方法 }
|
UserMapper
1 2 3 4 5
| public interface UserMapper extends MyBaseMapper<User> { User findById(Long id); }
|
MySqlInjector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList() { List<AbstractMethod> list = new ArrayList<>(); // 获取父类中的集合 list.addAll(super.getMethodList()); // 再扩充自定义的方法 list.add(new FindAll()); return list; } }
|
FindAll
1 2 3 4 5 6 7 8 9 10 11
| public class FindAll extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { String sql = "select * from " + tableInfo.getTableName(); SqlSource sqlSource = languageDriver.createSqlSource(configuration,sql, modelClass); return this.addSelectMappedStatement(mapperClass, "findAll", sqlSource, modelClass, tableInfo); } }
|
注入自定义SQL注入器
1 2 3 4 5 6 7 8
| /** * 注入自定义的SQL注入器 * @return */ @Bean public MySqlInjector mySqlInjector(){ return new MySqlInjector(); }
|
自动填充
对某些字段进行自动填充
1 2 3
| // 插入数据时进行填充 @TableField(fill = FieldFill.INSERT) private String password;
|
MyMetaObjectHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Component public class MyMetaObjectHandler implements MetaObjectHandler { /** * 插入数据时填充 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { // 先获取到password的值,再进行判断,如果为空,就进行填充,如果不为空,就不做处理 Object password = getFieldValByName("password", metaObject); if(null == password){ setFieldValByName("password", "888888", metaObject); } } /** * 更新数据时填充 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { } }
|
逻辑删除
标记为删除,但并不是物理删除
修改表结构
添加deleted字段,用于表示是否被删除,1删除,0未删除
1 2
| @TableLogic // 逻辑删除字段 ,1-删除,0-未删除 private Integer deleted;
|
application.properties
1 2 3 4 5 6 7
| # 删除状态的值为:1
mybatis-plus.global-config.db-config.logic-delete-value=1
# 未删除状态的值为:0
mybatis-plus.global-config.db-config.logic-not-delete-value=0
|
通用枚举
修改表结构
添加sex字段,1男,2女
1
| private SexEnum sex; //性别,枚举类型
|
定义枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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 this.value; } @Override public String toString() { return this.desc; } }
|
1 2 3
| # 枚举包扫描
mybatis-plus.type-enums-package=cn.itcast.mp.enums
|
代码生成器
MysqlGenerator.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| package cn.itcast.mp.generator; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.FileOutConfig; 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.TemplateConfig; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; /** * <p> * mysql 代码生成器演示例子 * </p> */ 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.toString()); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotEmpty(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("itcast"); gc.setOpen(false); mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&useSSL=false&characterEncoding=utf8"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName(scanner("模块名")); pc.setParent("cn.itcast.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 + "/itcast-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(); } }
|
MybatisX快速开发插件
在idea中安装插件,可以实现以下功能:
- Java与xml调用跳转
- Mapper自动生成xml