项目架构参照上一篇笔记,不过今天的笔记只涉及到后端。
mybatis-plus代码生成器
前几天的笔记记录了mybatis-plus的依赖,但不包含代码生成器单独的依赖。需要引入代码生成器的依赖。
新建一个测试的数据表
使用heidisql,在vueDemo数据库下新建一个price表,用于测试。
CREATE TABLE `price` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
`from` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
`price` DOUBLE NULL DEFAULT NULL,
`count` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;
引入依赖
打开mybatis-plus官网,找到代码生成器的依赖页面。
引入mybatis-plus-generato依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
新建代码生成器的类
在src目录下新建CodeGenerator文件夹,新建CodeGenerator.class,文件夹和类名可以按照自己的习惯进行随意起。
代码如下:
package com.zhuoaninfo.vueDemo.CodeGenerator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
generate();
}
private static void generate() {
}
}
从mybati-plus代码生成器配置新页面,拷贝以下代码
FastAutoGenerator.create("url", "username", "password")
.globalConfig(builder -> {
builder.author("baomidou") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://"); // 指定输出目录
})
.dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {
// 自定义类型转换
return DbColumnType.INTEGER;
}
return typeRegistry.getColumnType(metaInfo);
}))
.packageConfig(builder -> {
builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
.moduleName("system") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("t_simple") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
到CodeGenerator.class的generate()中,并依据注释进行简单的调整如下。
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/vueDemo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8", "root", "123456")
.globalConfig(builder -> {
builder.author("zhuoaninfo") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D:\\electron\\test2024\\vueDemo\\src\\main\\java\\"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.zhuoaninfo.vueDemo") // 设置父包名
.moduleName("CodeMode") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperxXml, "D:\\electron\\test2024\\vueDemo\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("price") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
// .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
完整的CodeGenerator.class代码为:
package com.zhuoaninfo.vueDemo.CodeGenerator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
generate();
}
private static void generate() {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/vueDemo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8", "root", "123456")
.globalConfig(builder -> {
builder.author("zhuoaninfo") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D:\\electron\\test2024\\vueDemo\\src\\main\\java\\"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.zhuoaninfo.vueDemo") // 设置父包名
.moduleName("CodeMode") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D:\\electron\\test2024\\vueDemo\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("price") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
// .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
对上面的代码做一下说明,为了防止和原有的代码混淆,保持项目的纯洁。使用 .moduleName(“CodeMode”) 语句,指的是在src会自动生成一个CodeMode的文件夹,用于存放生成的代码。
在项目的代码空白区右键,点击run ‘CodeGenerator.main()’
启动报错
我们缺少velocity
我们去mvn中央库去查找
在porn中添加
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
porn文件的完整代码为:
<?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.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zhuoaninfo</groupId>
<artifactId>vueDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>vueDemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!-- <scope>provided</scope>-->
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-web</artifactId>
<version>0.3.3</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 集成swagger3-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!--解决配置文件中的路径不能为com.zhuoaninfo.vueDemo.controller的问题,强制升级spring-plugin-core为2.0-->
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
<build>
<finalName>manager</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.5</version>
<configuration>
<fork>true</fork>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>aliyun-repos</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>central</id>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>aliyun-plugin</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
重启运行CodeGenerator.main() ,代码生成成功。
打开priceController.class,查看代码
package com.zhuoaninfo.vueDemo.CodeMode.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
/**
* <p>
* 前端控制器
* </p>
*
* @author zhuoaninfo
* @since 2024-03-09
*/
@Controller
@RequestMapping("/CodeMode/price")
public class PriceController {
}
没有相关的增删改查的内容,而且也不是@restController
首先解决@RestController的问题,在CodeGenerator.class中.strategyConfig的代码里面增加,builder.controllerBuilder().enableRestStyle();这里的代码前面controllerBuilder()代表是controller的生成配置,必要要有。CodeGenerator.class的完整代码为:
package com.zhuoaninfo.vueDemo.CodeGenerator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
generate();
}
private static void generate() {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/vueDemo?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8", "root", "zhuoan123")
.globalConfig(builder -> {
builder.author("zhuoaninfo") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D:\\electron\\test2024\\vueDemo\\src\\main\\java\\"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.zhuoaninfo.vueDemo") // 设置父包名
.moduleName("CodeMode") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D:\\electron\\test2024\\vueDemo\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("price") // 设置需要生成的表名
.addTablePrefix("t_", "c_");// 设置过滤表前缀
builder.controllerBuilder().enableRestStyle();
})
.execute();
}
}
再次运行,生成的Controller里面就有@RestController注释了。
下面编辑controller.java.vm模版来生成相应的增删改查代码。
编辑controller.java.vm模版
首先找到\com\baomidou\mybatis-plus-generator\3.5.1\mybatis-plus-generator-3.5.1.jar!\templates\controller.java.vm
拷贝controller.java.vm到resource/templates中
打开controller.java.vm,查看代码:
package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end
/**
* <p>
* $!{table.comment} 前端控制器
* </p>
*
* @author ${author}
* @since ${date}
*/
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
#else
#if(${superControllerClass})
public class ${table.controllerName} extends ${superControllerClass} {
#else
public class ${table.controllerName} {
#end
}
#end
模版生成的主要原来就是依赖变量
${table.entityPath}: 首字母小写的变量,这里生成PriceController,表示的就是price,这个变量一般用户实体,或者mapping中,变量值在controller.java.vm。
${table.serviceName}:对应的PriceService,从service.java.vm找到的变量值
${entity}:对应的priceEntity实体类,从service.java.vm找到的变量值
了解到了上述变量的含义我们就方便书写了模版了。
参照我们之前写的UserController.class代码:
package com.zhuoaninfo.vueDemo.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhuoaninfo.vueDemo.entity.User;
import com.zhuoaninfo.vueDemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@Controller
@RequestMapping("/vueDemo")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/")
public String index() {
return "welcome to springboot!";
}
@RequestMapping("/users")
public List<User> getUsers() {
return userService.list();
}
@PostMapping("/user")
public Boolean addUser(@RequestBody User vo) {
return userService.saveOrUpdate(vo);
}
@PutMapping("/user")
public Boolean updateUser(@RequestBody User vo) {
return userService.updateById(vo);
}
@DeleteMapping("/{id}")
public Boolean deleteUser(@PathVariable Integer id) {
return userService.removeById(id);
}
@PostMapping ("/del/delbatch")
public Boolean deleteUsers(@RequestBody List<Integer> ids)
{
return userService.removeByIds(ids);
}
@RequestMapping("/getPages")
public IPage<User> getPages(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam String name, @RequestParam String real_name) {
IPage<User> page = new Page<>(pageNum, pageSize);
QueryWrapper<User> query = new QueryWrapper<>();
return userService.page(page, query);
}
}
编写我们的controler.java.vm的模版
package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import ${package.Entity}.${entity};
import ${package.Service}.${table.serviceName};
#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end
/**
* <p>
* $!{table.comment} 前端控制器
* </p>
*
* @author ${author}
* @since ${date}
*/
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
#else
#if(${superControllerClass})
public class ${table.controllerName} extends ${superControllerClass} {
#else
public class ${table.controllerName} {
#end
@Autowired
private ${table.serviceName} ${table.entityPath}Service;
@RequestMapping("/${table.entityPath}s")
public List<${entity}> ${entity}s() {
return ${table.entityPath}Service.list();
}
@PostMapping("/${table.entityPath}")
public Boolean add${entity}(@RequestBody ${entity} ${table.entityPath}) {
return ${table.entityPath}Service.saveOrUpdate(${table.entityPath});
}
@PutMapping("/${table.entityPath}")
public Boolean update${entity}(@RequestBody ${entity} ${table.entityPath}) {
return ${table.entityPath}Service.updateById(${table.entityPath});
}
@DeleteMapping("/{id}")
public Boolean delete${entity}(@PathVariable Integer id) {
return ${table.entityPath}Service.removeById(id);
}
@PostMapping ("/del/delbatch")
public Boolean delete${entity}s(@RequestBody List<Integer> ids)
{
return ${table.entityPath}Service.removeByIds(ids);
}
@RequestMapping("/${table.entityPath}/getPages")
public IPage<${entity}> getPages(@RequestParam Integer pageNum, @RequestParam Integer pageSize) {
IPage<${entity}> page = new Page<>(pageNum, pageSize);
QueryWrapper<${entity}> query = new QueryWrapper<>();
return ${table.entityPath}Service.page(page, query);
}
}
#end
最后依据模版生成的PriceController.class为
package com.zhuoaninfo.vueDemo.CodeMode.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.zhuoaninfo.vueDemo.CodeMode.entity.Price;
import com.zhuoaninfo.vueDemo.CodeMode.service.IPriceService;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author zhuoaninfo
* @since 2024-03-09
*/
@RestController
@RequestMapping("/price")
public class PriceController {
@Autowired
private IPriceService priceService;
@RequestMapping("/prices")
public List<Price> Prices() {
return priceService.list();
}
@PostMapping("/price")
public Boolean addPrice(@RequestBody Price price) {
return priceService.saveOrUpdate(price);
}
@PutMapping("/price")
public Boolean updatePrice(@RequestBody Price price) {
return priceService.updateById(price);
}
@DeleteMapping("/{id}")
public Boolean deletePrice(@PathVariable Integer id) {
return priceService.removeById(id);
}
@PostMapping ("/del/delbatch")
public Boolean deletePrices(@RequestBody List<Integer> ids)
{
return priceService.removeByIds(ids);
}
@RequestMapping("/price/getPages")
public IPage<Price> getPages(@RequestParam Integer pageNum, @RequestParam Integer pageSize) {
IPage<Price> page = new Page<>(pageNum, pageSize);
QueryWrapper<Price> query = new QueryWrapper<>();
return priceService.page(page, query);
}
}
将生成的对应的类放到对应的包里面,
启动项目测试。提示了一些导包的错误,重新按照新路径倒一下包。这里遇到的一个坑是,我开始引入了快速生成代码生成器代码后运行CodeGenerator,生成了一个test文件夹,没有注意,所以启动的时候可能有冲突,删除/main/vueDemo/zhuoainfo/test就可以了。千万不能删除了,系统自带的test文件夹不在/main里面。
测试中发现from的属性和sql语言中的关集字,有冲突。修改数据库已经对应的entity里面的from字段即可。
修改后重新启动后端
使用postman测试成功。