今天搬个砖,给大家整理了一份SpringBoot集成Mybatis-Plus外加自动生成代码到项目里面,让大家能更好的使用Mybatis-Plus。当然也顺带优化一下公司的框架,O(∩_∩)O哈哈~,跟着我的步骤一起复制粘贴吧。
第一步:导入相关maven依赖
<!-- mybatis puls + 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- plus 3.2.0以上的版本会需要用到一个扩展包,但是和springboot整合的starter里面还没有 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 连表查询 -->
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.4.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<!-- 生成代码需要用到测试类哦 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
第二步:配置测试类
在src目录下面创建一个test文件夹,创建一个包名,一定要和我们代码的包名一致哦,不然会报错的。在下面粘贴下面的代码。
package com.app.web;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
//这里指向我们启动类的class
@SpringBootTest(classes = WebApiApplication.class)
@WebAppConfiguration
public class TmallApplicationTests {
@Before
public void init() {
//System.out.println("开始测试-----------------");
}
@After
public void after() {
//System.out.println("测试结束-----------------");
}
}
package com.app.web;
import com.app.db.jooq.tables.records.UserRecord;
import com.app.web.service.UserService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
public class WebTest extends TmallApplicationTests {
@Autowired
private UserService userService;
@Test
public void testGetEntFileById(){
UserRecord userRecord = userService.fetchOne(1);
System.out.printf("测试类配置成功啦");
}
@Test
public void testGetEntFileList(){
System.out.printf("222222");
}
}
第三步:集成mybatis-plus
配置我们的application文件,加入下面的配置进去。相关依赖在第一步已经全部贴出来了。
mybatis:
configuration:
#默认是不允许自动转换驼峰命名,得自己设置为true
map-underscore-to-camel-case: true
#扫描所有mybatis的xml文件
mapper-locations: classpath:mapper/*.xml
mybatis-plus:
configuration:
#默认是允许自动转换驼峰命名
map-underscore-to-camel-case: true
#开启日志
#log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#如果项目使用的是 lombok 的 @Slf4j就开启下面的日志
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
第四步:配置我们的代码自动生成
在测试目录加入以下代码,需要注意一下代码生成的相关策略哦,作者配置:表相关类已经生成了重新生成的时候不会进行覆盖,但是实体类每次生成都会覆盖成数据库最新的数据结构。
package com.app.web;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* 相关类生成
*/
public class MysqlTest extends TmallApplicationTests {
/**
* 数据库的配置 jdbc:mysql://127.0.0.1:3306/web_api?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&allowMultiQueries=true
*/
@Value("${spring.datasource.url}")
private String sqlUrl;
/**
* 数据库用户名
*/
@Value("${spring.datasource.username}")
private String username;
/**
* 数据库密码
*/
@Value("${spring.datasource.password}")
private String password;
/**
* 代码生成
*/
@Test
public void codeGeneration() throws Exception{
String[] table = {"sys_config","t_user"};
String[] prefix = {"t_", "sys_"};
//获取当前项目的路径
String rootDir = System.getProperty("user.dir");
File curr = new File(rootDir);
rootDir = curr.getParent();
Map<OutputFile, String> pathInfo = new HashMap<>();
pathInfo.put(OutputFile.entity, rootDir+"\\web-db\\src\\main\\java\\com\\app\\db\\entity"); // 实体类生成目录
pathInfo.put(OutputFile.service, rootDir+"\\web-api\\src\\main\\java\\com\\app\\web\\service"); // 服务接口生成目录
pathInfo.put(OutputFile.serviceImpl, rootDir+"\\web-api\\src\\main\\java\\com\\app\\web\\service\\impl"); // 服务实现类生成目录
pathInfo.put(OutputFile.mapper, rootDir+"\\web-db\\src\\main\\java\\com\\app\\db\\mapper"); // Mapper接口生成目录
pathInfo.put(OutputFile.mapperXml, rootDir+"\\web-db\\src\\main\\resources\\mapper"); // Mapper XML生成目录
pathInfo.put(OutputFile.controller, rootDir+"\\web-api\\src\\main\\java\\com\\app\\web\\api"); // 控制器生成目录
FastAutoGenerator.create(sqlUrl, username, password)
.globalConfig(builder -> {
builder.author("HayDen") // 设置作者
.enableSwagger(); // 开启 swagger 模式
//.fileOverride() // 注释掉可以避免覆盖已有文件
})
.packageConfig(builder -> {
builder.parent("com.app") // 设置父包名
.entity("db.entity") // 设置实体类包名
.service("web.service") // 设置服务类包名
.serviceImpl("web.service.impl") // 设置服务实现类包名
.mapper("db.mapper") // 设置Mapper接口包名
.controller("web.api") // 设置控制器包名
.pathInfo(pathInfo); // 设置不同类型类的生成路径
})
.strategyConfig(builder -> {
builder.entityBuilder().enableLombok(); // entity中使用lombok
builder.mapperBuilder().enableMapperAnnotation().build(); // mapper接口中默认添加mapper注解
builder.controllerBuilder().enableHyphenStyle() // 开启驼峰转连字符
.enableRestStyle(); // 开启生成@RestController 控制器
builder.addInclude(table) // 设置需要生成的表名
.addTablePrefix(prefix); // 设置过滤表前缀
})
.injectionConfig(builder -> {
builder.beforeOutputFile((tableInfo, objectMap) -> {
// 仅覆盖实体类
String entityFile = pathInfo.get(OutputFile.entity) + File.separator + tableInfo.getEntityName() + ".java";
File file = new File(entityFile);
if (file.exists()) {
file.delete(); // 删除已有的实体类文件
}
});
})
.execute();
}
}
下面是代码生成的规则代码,在resources目录下面创建templates,并吧生成的vm文件复制进去。
package ${package.Controller};
import com.app.common.annotation.Login;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import io.swagger.annotations.Api;
import org.springframework.transaction.annotation.Transactional;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};
#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end
import org.springframework.transaction.annotation.Isolation;
/**
* <p>
* $!{table.comment} 前端控制器
* </p>
*
* @author ${author}
* @since ${date}
*/
@Slf4j
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("/api/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
#else
@Api(tags = "$!{table.comment}")
@Transactional(isolation = Isolation.READ_COMMITTED)
#if(${superControllerClass})
public class ${table.controllerName} extends ${superControllerClass} {
#else
public class ${table.controllerName} {
#end
@Resource
private ${table.serviceName} ${table.entityPath}Service;
/**
* 查询所有数据
* @return
*/
@Login
@GetMapping
@ApiOperation("查询$!{table.comment}列表")
public List<${entity}> findAll() {
return ${table.entityPath}Service.list();
}
/**
* 新增或者更新
* @return
*/
@Login
@PostMapping
@ApiOperation("添加或者更新$!{table.comment}")
public Map<String,Boolean> saveOrUpdate(@RequestBody ${entity} ${table.entityPath}) {
Map<String,Boolean> map = new HashMap<>();
map.put("result",true);
${table.entityPath}Service.saveOrUpdate(${table.entityPath});
return map;
}
/**
* 根据id查询一条数据
* @return
*/
@Login
@GetMapping("/{id}")
@ApiOperation("根据ID查询$!{table.comment}")
public ${entity} findOne(@PathVariable Integer id) {
return ${table.entityPath}Service.getById(id);
}
/**
* 分页查询
* @return
*/
@Login
@GetMapping("/page")
@ApiOperation("分页查询$!{table.comment}")
public Page findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize) {
QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id");
Page page = ${table.entityPath}Service.page(new Page<>(pageNum, pageSize), queryWrapper);
return page;
}
}
#end
package ${package.Entity};
#foreach($pkg in ${table.importPackages})
import ${pkg};
#end
#if(${swagger})
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#end
#if(${entityLombokModel})
import lombok.Data;
#if(${chainModel})
import lombok.experimental.Accessors;
#end
#end
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* <p>
* $!{table.comment}
* </p>
*
* @author ${author}
* @since ${date}
*/
#if(${entityLombokModel})
@Data
#if(${chainModel})
@Accessors(chain = true)
#end
#end
#if(${table.convert})
@TableName("${schemaName}${table.name}")
#end
#if(${swagger})
@ApiModel(value = "${entity}对象", description = "$!{table.comment}")
#end
public class ${entity} #if(${superEntityClass}) extends ${superEntityClass}#if(${activeRecord})<${entity}>#end #elseif(${activeRecord}) extends Model<${entity}> #elseif(${entitySerialVersionUID})implements Serializable #end{
#if(${entitySerialVersionUID})
private static final long serialVersionUID = 1L;
#end
## ---------- BEGIN 字段循环遍历 ----------
#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if(${field.keyIdentityFlag})
@ApiModelProperty("ID")
#elseif(${field.propertyName} == "createTime")
@ApiModelProperty("创建时间")
#elseif(${field.propertyName} == "updateTime")
@ApiModelProperty("更新时间")
#else
@ApiModelProperty("${field.comment}")
#end
#if(${field.keyFlag})
## 主键
#if(${field.keyIdentityFlag})
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
#elseif(!$null.isNull(${idType}) && "$!idType" != "")
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
#elseif(${field.convert})
@TableId("${field.annotationColumnName}")
#end
#elseif(${field.fill})
## ----- 存在字段填充设置 -----
#if(${field.convert})
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
#else
@TableField(fill = FieldFill.${field.fill})
#end
#elseif(${field.convert})
@TableField("${field.annotationColumnName}")
#end
## 日期格式化注解
#if(${field.propertyType} == "LocalDateTime")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
#end
#if(${field.propertyType} == "LocalDate")
@JsonFormat(pattern = "yyyy-MM-dd")
#end
## 乐观锁注解
#if(${field.versionField})
@Version
#end
## 逻辑删除注解
#if(${field.logicDeleteField})
@TableLogic
#end
private ${field.propertyType} ${field.propertyName};
#end
## ---------- END 字段循环遍历 ----------
#if(!${entityLombokModel})
#foreach($field in ${table.fields})
#if(${field.propertyType.equals("boolean")})
#set($getprefix="is")
#else
#set($getprefix="get")
#end
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
#if(${chainModel})
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#else
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#end
this.${field.propertyName} = ${field.propertyName};
#if(${chainModel})
return this;
#end
}
#end
## --foreach end---
#end
## --end of #if(!${entityLombokModel})--
#if(${entityColumnConstant})
#foreach($field in ${table.fields})
public static final String ${field.name.toUpperCase()} = "${field.name}";
#end
#end
#if(${activeRecord})
@Override
public Serializable pkVal() {
#if(${keyPropertyName})
return this.${keyPropertyName};
#else
return null;
#end
}
#end
#if(!${entityLombokModel})
@Override
public String toString() {
return "${entity}{" +
#foreach($field in ${table.fields})
#if($!{foreach.index} == 0)
"${field.propertyName}=" + ${field.propertyName} +
#else
", ${field.propertyName}=" + ${field.propertyName} +
#end
#end
"}";
}
#end
}
package ${package.Mapper};
import ${package.Entity}.${entity};
import ${superMapperClassPackage};
#if(${mapperAnnotation})
import org.apache.ibatis.annotations.Mapper;
#end
/**
* <p>
* $!{table.comment} Mapper 接口
* </p>
*
* @author ${author}
* @since ${date}
*/
#if(${mapperAnnotation})
@Mapper
#end
#if(${kotlin})
interface ${table.mapperName} : ${superMapperClass}<${entity}>
#else
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
}
#end
package ${package.Service};
import ${package.Entity}.${entity};
import ${superServiceClassPackage};
/**
* <p>
* $!{table.comment} 服务类
* </p>
*
* @author ${author}
* @since ${date}
*/
#if(${kotlin})
interface ${table.serviceName} : ${superServiceClass}<${entity}>
#else
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
}
#end
package ${package.ServiceImpl};
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import org.springframework.stereotype.Service;
/**
* <p>
* $!{table.comment} 服务实现类
* </p>
*
* @author ${author}
* @since ${date}
*/
@Service
#if(${kotlin})
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
}
#else
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
}
#end
至此所有配置相关结束。启动MysqlTest类的codeGeneration()方法,相关代码就会直接生成到我们配置的目录里面啦。作者配置的是项目的目录里面,所以生成一下就直接在项目里面加好了。
Mybatis-Plus:
@GetMapping("/page")
@ApiOperation("分页查询配置表")
public Page findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize) {
//分页查询
QueryWrapper<Config> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id");
Page page = configService.page(new Page<>(pageNum, pageSize), queryWrapper);
//关联查询
MPJLambdaWrapper wrapper = new MPJLambdaWrapper<CarIllegalDto>()
.selectAll(CarIllegalDto.class)
.selectAs(AttachmentsFile::getId,CarIllegalDto::getCarNo)
.selectCollection(AttachmentsFile.class,CarIllegalDto::getAttachmentsFileList)
.leftJoin(AttachmentsFile.class,AttachmentsFile::getTargetId, CarIllegal::getId);
IPage<CarIllegalDto> carIllegalDtoList = carIllegalMapper.selectJoinPage(new Page<>(1, 10),CarIllegalDto.class,wrapper);
//统计
LambdaQueryWrapper<Config> count = new LambdaQueryWrapper<>();
count.eq(Config::getNodeKey,"21");
configService.count(count);
//范围查询
LambdaQueryWrapper<Config> getOne = new LambdaQueryWrapper<>();
getOne.between(Config::getId,1,50);
configService.getOne(count);
//保存单条
configService.save(new Config());
//批量保持
configService.saveBatch(new ArrayList<>());
//有ID更新,没ID保存
configService.saveOrUpdate(new Config());
//根据ID更新
configService.updateById(new Config());
.......
return page;
}
如果这篇文章在你一筹莫展的时候帮助到了你,可以请作者吃个棒棒糖🙂,如果有啥疑问或者需要完善的地方欢迎大家在下面留言或者私信作者优化改进。