目录
一、配置
1.1 基本配置
1.1.1 configLocation
1.1.2 mapperLocations
1.1.3 typeAliasesPackage
1.2 进阶配置
1.2.1 mapUnderscoreToCamelCase
1.2.2 cacheEnabled
二、条件构造器
2.1 allEq
2.1.1 说明
2.1.2 测试用例
2.2 基本比较操作
2.3 模糊查询
2.4 排序
2.5 逻辑查询
2.6 select
三、ActiveRecord
3.1 快速开始AR
3.2 根据主键查询
3.3 新增数据
3.4 更新操作
3.5 删除操作
3.6 根据条件查询
四、插件
4.1 mybatis的插件机制
4.2 执行分析插件
4.3 性能分析插件
4.4 乐观锁插件
4.4.1 主要使用场景
4.4.2 插件配置
4.4.3 注解实体字段
4.4.4 测试
4.4.5 特别说明
五、Sql注入器
5.1 编写BaseMapper
5.2 编写MySqlInjector
5.3 编写FindAll
5.4 注册到Spring容器
5.5 测试
六、自动填充功能
6.1 添加@TableField注解
6.2 编写MyMetaObjectHandler
七、逻辑删除
7.1 修改表结构
7.2 配置
7.3 测试
八、通用枚举
8.1 修改表结构
8.2 定义枚举
8.3 配置
8.4 修改实体
8.5 测试
九、代码生成器
9.1 创建工程
9.2 代码
十、MybatisX快速开发插件
在MP中有大量的配置,其中有一部分是Mybatis原生的配置,另一部分是MP的配置,详情:https://mybatis.plus/c onfig/
MyBatis 配置文件位置,如果您有单独的 MyBatis 配置,请将其路径配置到 configLocation 中。 MyBatis Configuration 的具体内容请参考MyBatis 官方文档
Spring Boot:
mybatis-plus.config-location = classpath:mybatis-config.xml
Spring MVC:
MyBatis Mapper 所对应的 XML 文件位置,如果您在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,告诉 Mapper 所对应的 XML 文件位置
Spring Boot:
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
Spring MVC:
Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件)
MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使 用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)
Spring Boot:
mybatis-plus.type-aliases-package = cn.itcast.mp.pojo
Spring MVC:
本部分(Configuration)的配置大都为 MyBatis 原生支持的配置,这意味着可以通过 MyBatis XML 配置文件的形式进行配置。
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属 性名 aColumn(驼峰命名) 的类似映射
注意: 此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将用于生成最终的 SQL 的 select body 如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名
示例(SpringBoot):
#关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在 mybatis-plus.configuration.map-underscore-to-camel-case=false
全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true
示例:
mybatis-plus.configuration.cache-enabled=false
在MP中,Wrapper接口的实现类关系如下:
AbstractWrapper和AbstractChainWrapper是重点实现
说明: QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类 用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件 注意: entity 生成的 where 条件与 使用各个 api 生成 的 where 条件没有任何关联行为
@Test
public void testAllEq() {
Map params = new HashMap<>();
params.put("name", "李四");
params.put("age", "20");
params.put("password", null);
QueryWrapper wrapper = new QueryWrapper<>();
// wrapper.allEq(params);
// wrapper.allEq(params,false);
wrapper.allEq((k, v) -> (k.equals("age") || k.equals("id")), params);
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
- eq: 等于 =
- ne: 不等于 <>
- gt: 大于 >
- ge: 大于等于 >=
- lt: 小于 <
- le: 小于等于 <=
- between: BETWEEN 值1 AND 值2
- notBetween: NOT BETWEEN 值1 AND 值2
- in: 字段 IN (value.get(0), value.get(1), ...)
- notIn: 字段 NOT IN (v0, v1, ...)
测试用例:
@Test public void testEq() { QueryWrapper
wrapper = new QueryWrapper<>(); //SELECT id,user_name,password,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?) wrapper.eq("password", "123456") .ge("age", 20) .in("name", "李四", "王五", "赵六"); List users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
- like
○LIKE '%值%'
○例: like("name", "王") ---> name like '%王%'
- notLike
○NOT LIKE '%值%'
○例: notLike("name", "王") ---> name not like '%王%'
- likeLeft
○LIKE '%值'
○例: likeLeft("name", "王") ---> name like '%王'
- likeRight
○LIKE '值%'
○例: likeRight("name", "王") ---> name like '王%'
测试用例:
@Test public void testLike(){ QueryWrapper
wrapper = new QueryWrapper<>(); //SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name LIKE ? //参数:%五(String) wrapper.likeLeft("name","五"); List users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
- orderBy
○排序:ORDER BY 字段, ...
○例: orderBy(true, true, "id", "name") ---> order by id ASC,name ASC
- orderByAsc
○排序:ORDER BY 字段, ... ASC
○例: orderByAsc("id", "name") ---> order by id ASC,name ASC
- orderByDesc
○排序:ORDER BY 字段, ... DESC
○例: orderByDesc("id", "name") ---> order by id DESC,name DESC
测试用例:
@Test public void testOrderByAgeDesc() { QueryWrapper
wrapper = new QueryWrapper<>(); //按照年龄倒序排序 //SELECT id,user_name,name,age,email AS mail FROM tb_user ORDER BY age DESC wrapper.orderByDesc("age"); List users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
- or
○拼接 OR
○主动调用 or 表示紧接着下一个方法不是用 and 连接!(不调用 or 则默认为使用 and 连接)
- and
○AND 嵌套
○例: and(i -> i.eq("name", "李白").ne("status", "活着")) ---> and (name = '李白' and status <> '活着')
测试用例:
@Test public void testOr() { QueryWrapper
wrapper = new QueryWrapper<>(); // SELECT id,user_name,name,age,email AS mail FROM tb_user WHERE name = ? OR age = ? wrapper.eq("name","王五").or().eq("age",21); List users = this.userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } }
在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段
@Test
public void testSelect() {
QueryWrapper wrapper = new QueryWrapper<>();
//SELECT id,name,age FROM tb_user WHERE name = ? OR age >= ?
wrapper.eq("name", "王五")
.or()
.ge("age", 21)
.select("id","name","age"); //指定查询的字段
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
什么是ActiveRecord?
ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记 录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而 且简洁易懂。
ActiveRecord的主要思想是:
- 每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录;通常表的每个字段 在类中都有相应的Field;
- ActiveRecord同时负责把自己持久化,在ActiveRecord中封装了对数据库的访问,即CURD;
- ActiveRecord是一种领域模型(Domain Model),封装了部分业务逻辑;
在MP中,开启AR非常简单,只需要将实体对象继承Model即可
package com.learn.mp.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 咕咕猫
* @version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends Model {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestUserMapper2 {
@Test
public void selectById(){
User user = new User();
user.setId(2L);
User user1 = user.selectById();
System.out.println(user1);
}
}
@Test
public void testInsert(){
User user = new User();
user.setUserName("liubei");
user.setPassword("123456");
user.setAge(30);
user.setName("刘备");
user.setMail("[email protected]");
//调用AR的insert方法进行插入数据
boolean result = user.insert();
System.out.println("result -》" + result);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(7L); //查询条件
user.setAge(31);//更新数据
boolean result = user.updateById();
System.out.println("result -》" + result);
}
@Test
public void testDelete(){
User user = new User();
user.setId(6L);
boolean delete = user.deleteById();
System.out.println("result -》" + delete);
}
@Test
public void testSelect(){
User user = new User();
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.ge("age",25); //大于等于25岁的用户
List users = user.selectList(wrapper);
for (User user1 : users) {
System.out.println(user1);
}
}
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法 调用包括:
1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
2. ParameterHandler (getParameterObject, setParameters)
3. ResultSetHandler (handleResultSets, handleOutputParameters)
4. StatementHandler (prepare, parameterize, batch, update, query)
我们看到了可以拦截Executor接口的部分方法,比如update,query,commit,rollback等方法,还要其他接口的一些方法等。
总体概括为:
- 拦截执行器的方法
- 拦截参数的处理
- 拦截结果集的处理
- 拦截Sql语法构建的处理
拦截器示例:
package com.learn.mp.plugins; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import java.util.Properties; /** * @author 咕咕猫 * @version 1.0 */ @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) { //属性设置 } }
注入到Spring容器:
/** * 自定义拦截器 */ @Bean public MyInterceptor myInterceptor(){ return new MyInterceptor(); }
或者通过xml配置,mybatis-config.xml:
在MP中提供了对SQL执行的分析的插件,可用作阻断全表更新、删除的操作,注意:该插件仅适用于开发环境,不适用于生产环境
SpringBoot配置:
@Bean //SQL分析插件 public SqlExplainInterceptor sqlExplainInterceptor(){ SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor(); List
list = new ArrayList<>(); list.add(new BlockAttackSqlParser()); //全表更新、删除的阻断器 sqlExplainInterceptor.setSqlParserList(list); return sqlExplainInterceptor; } 测试:
/** * 测试全表更新,SQL分析器的阻断效果 */ @Test public void testUpdateAll(){ User user = new User(); user.setAge(31);//更新数据 boolean result = user.update(null); //全表更新 System.out.println("result -》" + result); }
性能分析拦截器,用于输出每条SQL语句及其执行时间,可以设置最大执行时间,超过时间会抛出异常。该插件仅适用于开发环境,不适用于生产环境
配置:
意图:当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁的实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
spring xml:
spring boot:
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
需要为实体字段添加@Version注解
第一步,为表添加version字段,并且设置初始值为1
ALTER TABLE `tb_user` ADD COLUMN `version` int(10) NULL AFTER `email`; UPDATE `tb_user` SET `version`='1';
第二步,为User实体对象添加version字段,并且添加@Version注解:
@Version private Integer version;
/** * 测试乐观锁 */ @Test public void testUpdateVersion(){ User user = new User(); user.setId(2L); //查询条件 User userVersion = user.selectById(); user.setAge(23);//更新数据 user.setVersion(userVersion.getVersion());//当前的版本信息 boolean result = user.updateById(); System.out.println("result -》" + result);
- 支持的数据类型只有:int,Interge,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下 newVersion = oldVersion + 1
- newVersion会会写到 entity 中
- 仅支持 updateById(id) 与 updateById(entity,wrapper) 方法
- 在update(entity,wrapper) 方法下,wrapper不能复用!!!
package com.learn.mp.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.learn.mp.pojo.User; import java.util.List; /** * @author 咕咕猫 * @version 1.0 */ public interface MyBaseMapper
extends BaseMapper { List findAll(); //可以扩展其他方法 } 其他的Mapper都可以继承该Mapper,这样实现了统一的扩展。 如:
package com.learn.mp.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.learn.mp.pojo.User; import java.util.List; /** * @author 咕咕猫 * @version 1.0 */ public interface UserMapper extends MyBaseMapper
{ void selectList(long l); User findById(Long id); }
如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以我们选择继承DefaultSqlInjector进行扩展
package com.learn.mp.injector; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import java.sql.Array; import java.util.ArrayList; import java.util.List; /** * @author 咕咕猫 * @version 1.0 */ public class MySqlInjector extends DefaultSqlInjector { @Override public List
getMethodList() { List list = new ArrayList<>(); //获取父类中的集合 list.addAll(super.getMethodList()); //再扩充自定义的方法 list.add(new FindAll()); return list; } }
package com.learn.mp.injector; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector; import com.baomidou.mybatisplus.core.metadata.TableInfo; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; /** * @author 咕咕猫 * @version 1.0 */ 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注入器 * @return */ @Bean public MySqlInjector mySqlInjector() { return new MySqlInjector(); }
@Test public void testFindAll(){ List
users = this.userMapper.findAll(); for (User user : users) { System.out.println(user); } } 输出的SQL:
至此,我们实现了全局扩展SQL注入器。
有时候在插入或者更新数据时,希望有些字段可以自动填充数据,比如面膜、version等。在MP中提供了这样的功能,可实现自动填充
@TableField(fill = FieldFill.INSERT) //插入数据时进行填充 private String password;
为password添加自动填充功能,在新增数据时有效。
FieldFill提供了多种模式选择:
public enum FieldFill { /** * 默认不处理 */ DEFAULT, /** * 插入时填充字段 */ INSERT, /** * 更新时填充字段 */ UPDATE, /** * 插入和更新时填充字段 */ INSERT_UPDATE }
package com.learn.mp.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
/**
* @author 咕咕猫
* @version 1.0
*/
@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) {
}
}
开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,却表被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除
为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注解:
@TableLogic private Integer deleted;
application.properties:
# 逻辑已删除值(默认为 1) mybatis-plus.global-config.db-config.logic-delete-value=1 # 逻辑未删除值(默认为 0) mybatis-plus.global-config.db-config.logic-not-delete-value=0
@Test public void testDeleteById(){ this.userMapper.deleteById(2L); }
解决了繁琐的配置,让mybaits优雅的使用枚举属性
ALTER TABLE `tb_user` ADD COLUMN `sex` int(1) NULL DEFAULT 1 COMMENT '1-男,2-女' AFTER `deleted`;
package com.learn.mp.enums; import com.baomidou.mybatisplus.core.enums.IEnum; public enum SexEnum implements IEnum
{ 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; } }
# 枚举包扫描 mybatis-plus.type-enums-package=cn.itcast.mp.enums
private SexEnum sex;
测试插入数据:
@Test public void testInsert(){ User user = new User(); user.setUserName("diaochan"); user.setPassword("123456"); user.setAge(20); user.setName("貂蝉"); user.setMail("[email protected]"); user.setVersion(1); user.setSex(SexEnum.WOMAN); //调用AR的insert方法进行插入数据 boolean result = user.insert(); System.out.println("result -》" + result); }
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
pom.xml:
4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.4.RELEASE cn.itcast.mp itcast-mp-generator 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test com.baomidou mybatis-plus-boot-starter 3.1.1 com.baomidou mybatis-plus-generator 3.1.1 org.springframework.boot spring-boot-starter-freemarker mysql mysql-connector-java 5.1.47 org.slf4j slf4j-log4j12 org.springframework.boot spring-boot-maven-plugin
package com.learn.mp; 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; /** *
* mysql 代码生成器演示例子 *
*/ public class MysqlGenerator { /** ** 读取控制台内容 *
*/ 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("gugumao"); 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 } }; ListfocList = new ArrayList<>(); focList.add(new FileOutConfig("/templates/mapper.xml.ftl") { @Override public String outputFile(TableInfo tableInfo) { // 自定义输入文件名称 return projectPath + "/itcast-mpgenerator/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 的快速开发插件,为效率而生。 安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。
功能:
- Java与XML调回跳转
- Mapper方法自动生成XML