mybatisplus链式编程
使用mybatisplus可以快速实现需要的业务基本接口,而且mybatisplus也提供了优雅的链式条件构造器,对于喜欢用lambd链式编程的码友来说太香了有木有。本文将总结如何使用代码生成器快速构建项目基本文件以及如何使用mybatisplus链式条件构造器撸代码
一、使用代码生成器创建基本文件
实现效果,在指定模块指定包下自动创建包、java和xml基本文件。
用mp模板只创建基本工程文件和简单mapper-entity-dao-service-controller逻辑关联,如果项目框架比较成熟,也可以自定义模板文件,生成功能较完整的一整套工程文件。
1.前期准备
1.1数据库创建一个表
field | type | desc |
---|---|---|
id(primarykey) | bigint | 自增id |
user_code | varchar | 编码 |
user_name | varchar | 名称 |
// 测试用表d_user
CREATE TABLE `d_user` (
`id` BIGINT(19) NOT NULL AUTO_INCREMENT,
`user_code` VARCHAR(50) NULL DEFAULT NULL COMMENT '编码' COLLATE 'utf8mb4_0900_ai_ci',
`user_name` VARCHAR(50) NULL DEFAULT NULL COMMENT '名称' COLLATE 'utf8mb4_0900_ai_ci',
PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
;
1.2 maven引入mp和generator依赖
引入三个必须依赖
plus、generator、velocity
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!-- mybatis-plus-generator -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<!-- mybatis-plus-velocity -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
本次使用的是3.5.1+的新版mp,如果同时引入了pagehelper可能会报兼容问题,需要另外引入mp的扩展增强依赖mybatis-plus-extension
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.5.2</version>
</dependency>
1.3 generator封装
新版的mp提供了lambd链式编程接口,可以一路点到底
工具类中使用了自定义模板文件,idea找到generator的jiar包com.baomidou.mybatisplus.generator
,将tamplates
目录下需要自定义的模板文件复制出来,配置模板的时候指定自定义模板所在目录即可
// 指定生成的表可以代码中指定,也可以在控制台输入。多个表用 , 分开
public class CodeGenUtils {
// 配置包名
private static final String PACKAGE_NAME = "com.demo.mpboot";
// 默认生成table
private static final String TABLE_NAME = "d_user";
// mapper文件位置
private static final String MAPPER_PATH = "\\src\\main\\resources\\mapper";
// 模板文件位置,从resources/xx
private static final String TEMPLATE_PATH_PREFIX = "\\templates\\vm\\";
private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/db?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true&serverTimezone=Asia/Shanghai";
private static final String DB_USERNAME = "root";
private static final String DB_PWD = "123456";
// 表名的前缀,从表生成代码时会去掉前缀
private static final String TABLE_PREFIX = "";
public static void main(String[] args) {
autoGenCode(DB_URL,DB_USERNAME,DB_PWD,"sys",false);
}
/**
* 指定包名,输入表名创建
* @param packageName 包名
*/
public static void builder(String packageName){
autoGenCode(DB_URL,DB_USERNAME,DB_PWD,packageName,true);
}
/**
* 生成entity、dao、service、controller、xml、(前端)
* @param url
* @param username
* @param password
* @param useInput true 控制台输入要生成的表 多个 , 分割 false 使用默认值
*/
public static void autoGenCode(String url, String username, String password,String packgeName, boolean useInput){
String projectPath = System.getProperty("user.dir")+"\\"+packgeName;
FastAutoGenerator.create(new DataSourceConfig.Builder(url, username,password)
.dbQuery(new MySqlQuery())
.typeConvert(new MySqlTypeConvert())
.keyWordsHandler(new MySqlKeyWordsHandler()))
//FastAutoGenerator.create(url, username, password)
// 全局配置
.globalConfig(builder -> {
// 设置作者为系统用户名
builder.author("dreamfsk")
// 开启 swagger 模式
//.enableSwagger()
// 设置时间类型使用java.util.date
.dateType(DateType.ONLY_DATE)
.commentDate("yyyy-MM-dd")
// 指定输出目录 "D://baomidou//generator"
.outputDir(projectPath + "/src/main/java")
.disableOpenDir();
})
// 包配置
.packageConfig(builder -> {
// 父包
builder.parent(PACKAGE_NAME)
.moduleName(packgeName)
.entity("entity")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
.mapper("dao")
.xml("mapper")
.pathInfo(Collections.singletonMap(OutputFile.xml,projectPath + MAPPER_PATH));
})
// 模板配置
.templateConfig(builder ->
builder.controller(TEMPLATE_PATH_PREFIX+"controller.java.vm")
.entity(TEMPLATE_PATH_PREFIX+"entity.java.vm")
.service(TEMPLATE_PATH_PREFIX+"service.java.vm")
.serviceImpl(TEMPLATE_PATH_PREFIX+"serviceImpl.java.vm")
.mapper(TEMPLATE_PATH_PREFIX+"mapper.java.vm")
.xml(TEMPLATE_PATH_PREFIX+"mapper.xml.vm"))
使用Freemarker引擎模板,默认的是Velocity引擎模板
//.templateEngine(new FreemarkerTemplateEngine())
.strategyConfig(builder -> {
// 设置需要生成的表名
builder.addInclude(getTable(useInput))
// 设置过滤表前缀
.addTablePrefix(TABLE_PREFIX)
.enableCapitalMode()
.enableSkipView()
.disableSqlFilter();
// 设置controller
builder.controllerBuilder()
// 开启rest模式
.enableRestStyle()
// 重新生成时覆盖原文件
.fileOverride()
.build();
builder.entityBuilder()
// 开启lombok模式
.enableLombok()
// 添加父类
//.superClass(BaseEntity.class)
// 重新生成时覆盖原文件
.fileOverride()
.enableTableFieldAnnotation()
.naming(NamingStrategy.underline_to_camel)
.columnNaming(NamingStrategy.underline_to_camel)
.enableColumnConstant()
.idType(IdType.AUTO)
//.formatFileName("%sEntity")
.build();
// 设置service
builder.serviceBuilder()
// 设置生成的文件名为XxxService.java,默认是IXxxService.java
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
// 重新生成时覆盖原文件
.fileOverride()
.build();
// 设置mapper
builder.mapperBuilder()
// 生成resultMap
.enableBaseResultMap()
// 生成baseColumn
.enableBaseColumnList()
// 设置生成的文件名为XxxDao.java,默认是XxxMapper.java
.formatMapperFileName("%sDao")
.formatXmlFileName("%sMapper")
.enableMapperAnnotation()
// 重新生成时覆盖原文件
.fileOverride()
.build();
})
.execute();
}
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入").append(tip).append(":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
/**
* 自动生成的表
* @param useInput
* @return
*/
public static String[] getTable(boolean useInput){
if(useInput){
return scanner("表名,多个英文逗号分割").split(",");
}else{
return TABLE_NAME.split(",");
}
}
}
``
```java
// 测试用user实体
@Data
public class User {
@TableId(value = "id")
private Long id;
private String code;
private String name;
@TableField(exist = false)
private String postName;
}
二、lambd链式编程
Mapper层接口继承BaseMapper即可食用mp的CURD接口,Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器。
Service层接口需要接口继承IService,实现类继承ServiceImpl<持久层接口,T>
本次使用的是lambd
条件构造器组装条件,实现链式编程
2.1.query
以最常用的接口实例、列表为例。使用链式编程,只需要.
出需要拼接的查询条件即可,参数字段也是lambd方式,不需要手动装填字符串。
//查询User实体信息
User u = new LambdaQueryChainWrapper<>(baseMapper)
.eq(User ::getName,"张三")
.one();
//如果继承了service层接口,可简写为
User u = lambdaQuery()
.eq(User ::getName,"张三")
.one();
列表链式查询返回数据可以继续链式数据处理,排序.sort(Comparator<? super E> c)
,聚合add(T)
,流处理.stream()..
//列表查询
List<User > list= new LambdaQueryChainWrapper<>(baseMapper)
.eq(User ::getName,"张三")
.list();
//如果继承了service层接口,可简写为
List<User > list= lambdaQuery()
.eq(User ::getName,"张三")
.list();
//提取返回列表中的id组成新的list
List<Long> ids =lambdaQuery()
.eq(User ::getName,"张三")
.list()
.stream().map(User ::getId).collect(Collectors.toList());
mp也是有使用限制的,并不大适合多表关联查询,喜欢事无巨细,简单curd都要写mabatisxml的大佬[抱拳,皮肤送上]。当然如果想用mp的方式(非mybatisxml)写多表关联的mapper接口,也不是不可以,只要在mapper接口上使用@Select("your sql")
也可以实现多表关联查询。有兴趣的可以研究下
2.2.update
// 按条件更新一条记录
new LambdaUpdateChainWrapper<>(baseMapper)
.set(User ::getName,"李四")
.eq(User ::getId,1L)
.update()
//提取返回列表中的id组成新的list
lambdaUpdate()
.set(User ::getName,"李四")
.eq(User ::getId,1L)
.update()
mp也是有使用限制的,单表操作用起来还是很优雅的,多表复合操作还是老老实实码sql