汝之观览,吾之幸也! 从本文开始讲下项目中用到的一些框架和技术,最基本的框架使用的是SpringBoot(2.5.10)+Mybatis-plus(3.5.3.2)+lombok(1.18.28)+knife4j(3.0.3)+hutool(5.8.21),可以做到代码自动生成,满足最基本的增删查改。
<?xml version="1.0" encoding="UTF-8"?>
://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">
>4.0.0 >
>
>org.springframework.boot >
>spring-boot-starter-parent >
>2.5.10 >
> <!-- lookup parent from repository -->
com.mitool
springboot
0.0.1-SNAPSHOT
springboot
Demo project for Spring Boot
1.8
3.5.3.2
2.3.29
1.18.28
3.0.3
5.8.21
1.4.7
4.3.2
1.4.2.Final
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
mysql
mysql-connector-java
runtime
com.baomidou
mybatis-plus-boot-starter
${mybatis-plus.version}
com.baomidou
mybatis-plus-generator
${mybatis-plus.version}
com.baomidou
mybatis-plus-extension
org.freemarker
freemarker
${freemarker.version}
org.projectlombok
lombok
${lombok.version}
provided
com.github.xiaoymin
knife4j-spring-boot-starter
${knife4j.version}
cn.hutool
hutool-all
${hutool.version}
com.github.pagehelper
pagehelper-spring-boot-starter
${pagehelper.version}
com.alibaba.cola
cola-component-dto
${ali.cola.version}
org.mapstruct
mapstruct
${org.mapstruct.version}
>
>
>
>org.springframework.boot >
>spring-boot-maven-plugin >
>
>
>org.apache.maven.plugins >
>maven-compiler-plugin >
>3.8.1 >
>
>
>1.8 >
>
>
>org.projectlombok >
>lombok >
>${lombok.version} >
>
>
>org.mapstruct >
>mapstruct-processor >
>${org.mapstruct.version} >
>
>
>
>
>
>
>
配置application.properties文件,文件中包含数据库配置、knife4j配置
# 应用名称
spring.application.name=spring-demo
# 开发环境设置
spring.profiles.active=dev
# 应用路径
server.servlet.context-path=/springboot
# 编码字符集
server.servlet.encoding.charset=utf-8
# swagger
knife4j.enable=true
knife4j.production=false
knife4j.basic.enable=false
配置数据库,
localhost:数据库IP
db_source:数据库名称
username:用户名
password:密码
# 端口
server.port=9900
spring.datasource.url=jdbc:mysql://localhost:3306/db_source?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# SSO
zsc.open.token.check=false
package com.mitool.springboot.utils;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.InjectionConfig;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.Scanner;
/**
* Title: CodeGeneratorUtil
* Description:
* 描述:mybatis-plus 自动生成代码工具类
*
*
* @author Jimmy.Shen
* @version v1.0.0
* @since 2022-10-19 9:58
*/
@Slf4j
public class CodeGeneratorUtil {
/**
* 表前缀
*/
private static final String[] PREFIX = new String[]{"illp_", "t_"};
/**
* 是否生成controller、service、serviceImpl、converter
*/
private static final boolean ONLY_UPDATE_COLUMNS = true;
/**
* 数据源配置
*/
private static final DataSourceConfig.Builder DATA_SOURCE_CONFIG = new DataSourceConfig
.Builder("jdbc:mysql://10.10.177.151:3309/smart_park?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true",
"root", "ztesoft");
/**
* 读取控制台内容
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
log.info("### 请输入" + tip);
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StrUtil.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
String projectPath = System.getProperty("user.dir");
String outputDir = projectPath + "/springboot/src/main/java/";
String[] scannerArr = scanner("作者名,包名,表名").split(",");
String authorName = scannerArr[0];
String packageName = scannerArr[1];
String tableName = scannerArr[2];
// 规定代码路径,如果代码在不同项目中可进行调整
String controllerName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/controller/" + packageName;
String serviceName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/service/" + packageName;
String serviceImplName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/service/" + packageName + "/impl/";
String entityName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/entity/dataobject/" + packageName;
String mapperName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/mapper/" + packageName;
String mapperXmlName =
projectPath + "/springboot/src/main/resources/mybatis-mapper/" + packageName;
String voName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/entity/vo/" + packageName;
String converterName =
projectPath + "/springboot/src/main/java/com/mitool/springboot/converter/" + packageName;
FastAutoGenerator.create(DATA_SOURCE_CONFIG)
// 全局配置
.globalConfig(builder ->
//作者名
builder.author(authorName)
// 开启 swagger 模式 默认值:false
.enableSwagger()
// 禁止打开输出目录 默认值:true
.disableOpenDir()
// 指定输出目录
.outputDir(outputDir))
.packageConfig(builder -> builder.moduleName(packageName))
.injectionConfig(builder -> {
updateColumn(entityName, mapperName, mapperXmlName, voName, builder);
if (ONLY_UPDATE_COLUMNS) {
updateTemplate(controllerName, serviceName, serviceImplName, converterName, builder);
}
})
//具体的生成文件的策略配置
.strategyConfig(builder -> {
builder.addInclude(tableName.split("#"))
// .enableSkipView()
.addTablePrefix(Arrays.asList(PREFIX))
.entityBuilder()
.enableFileOverride()
.enableLombok()
// // controller
.controllerBuilder()
.enableRestStyle()
.formatFileName("%sController")
.enableFileOverride()
// service
.serviceBuilder()
.superServiceClass(IService.class)
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.enableFileOverride()
//开启生成mapper
.mapperBuilder()
.enableBaseResultMap()
.enableBaseColumnList()
.superClass(BaseMapper.class)
.formatMapperFileName("%sMapper")
.formatXmlFileName("%sXml")
.enableFileOverride();
})
//模板配置,如果你没有自定义的一些模板配置,这里直接使用默认即可。
.templateConfig(config -> config.entity("/templates/entity.java"))
//模板引擎配置
.templateEngine(new FreemarkerTemplateEngine())
.execute();
// 删除生成的自带的 baomidou代码
FileUtil.del(projectPath + "/springboot/src/main/java/com/baomidou");
}
private static void updateColumn(String entityName, String mapperName, String mapperXmlName, String voName, InjectionConfig.Builder builder) {
builder.customFile(consumer -> consumer
.fileName("DO.java")
.filePath(entityName)
.enableFileOverride()
.templatePath("/templates/entity.java.ftl"));
builder.customFile(consumer -> consumer
.fileName("Mapper.java")
.filePath(mapperName)
.enableFileOverride()
.templatePath("/templates/mapper.java.ftl"));
builder.customFile(consumer -> consumer
.fileName("Mapper.xml")
.filePath(mapperXmlName)
.enableFileOverride()
.templatePath("/templates/mapper.xml.ftl"));
builder.customFile(consumer -> consumer
.fileName("VO.java")
.filePath(voName)
.enableFileOverride()
.templatePath("/templates/vo.java.ftl"));
}
private static void updateTemplate(String controllerName,
String serviceName, String serviceImplName,
String converterName, InjectionConfig.Builder builder) {
builder.customFile(consumer -> consumer
.fileName("Controller.java")
.filePath(controllerName)
.enableFileOverride()
.templatePath("/templates/controller.java.ftl"));
builder.customFile(consumer -> consumer
.fileName("Service.java")
.filePath(serviceName)
.enableFileOverride()
.templatePath("/templates/service.java.ftl"));
builder.customFile(consumer -> consumer
.fileName("ServiceImpl.java")
.filePath(serviceImplName)
.enableFileOverride()
.templatePath("/templates/serviceImpl.java.ftl"));
builder.customFile(consumer -> consumer
.fileName("AppConverter.java")
.filePath(converterName)
.enableFileOverride()
.templatePath("/templates/converter.java.ftl"));
}
}
模板文件放在resource/templates下
package com.mitool.springboot.controller.${package.ModuleName};
import com.mitool.springboot.utils.PageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import com.mitool.springboot.service.${package.ModuleName}.${table.serviceName};
import com.mitool.springboot.entity.dataobject.${package.ModuleName}.${entity}DO;
import com.mitool.springboot.entity.vo.${package.ModuleName}.${entity}VO;
import com.mitool.springboot.converter.${package.ModuleName}.${entity}AppConverter;
import com.alibaba.cola.dto.SingleResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
#if>
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
*
* ${table.comment!} 前端控制器
*
*
* @author ${author}
* @since ${date}
*/
@Slf4j
@RestController
@RequestMapping("/api/<#if controllerMappingHyphenStyle>${controllerMappingHyphen}<#else>${table.entityPath}#if>")
@Api(value = "${table.comment!}", tags = "${table.comment!} 管理模块")
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
#if>
@Resource
private ${table.serviceName} service;
@Resource
private ${entity}AppConverter converter;
@ApiOperation(value = "${table.comment!}分页查询", notes = "${table.comment!}分页查询")
@GetMapping("/page")
public SingleResponse> page(@RequestParam Integer pageIndex, @RequestParam Integer pageSize) {
PageHelper.startPage(pageIndex, pageSize);
List<${entity}DO> list = service.list();
return SingleResponse.of(PageUtil.pageInfoCopy(new PageInfo<>(list), ${entity}VO.class, converter::toValueObject));
}
@ApiOperation(value = "${table.comment!}列表查询", notes = "${table.comment!}列表查询")
@GetMapping("/list")
public SingleResponse> list() {
List<${entity}DO> list = service.list();
return SingleResponse.of(converter.toValueObject(list));
}
@ApiOperation(value = "${table.comment!}详情", notes = "${table.comment!}详情")
@GetMapping("/detail")
public SingleResponse> detail(@RequestParam Integer id) {
return SingleResponse.of(converter.toValueObject(service.getById(id)));
}
@ApiOperation("新增")
@PostMapping("/save")
public SingleResponse> save(@RequestBody ${entity}VO param) {
${entity}DO dataObject = converter.toDataObject(param);
service.save(dataObject);
return SingleResponse.buildSuccess();
}
@ApiOperation("更新")
@PostMapping("/update")
public SingleResponse> update(@RequestBody ${entity}VO param) {
${entity}DO dataObject = converter.toDataObject(param);
service.updateById(dataObject);
return SingleResponse.buildSuccess();
}
@ApiOperation("删除")
@PostMapping("/remove")
public SingleResponse> remove(@RequestBody ${entity}VO param) {
service.removeById(param.getId());
return SingleResponse.buildSuccess();
}
}
package com.mitool.springboot.converter.${package.ModuleName};
import com.mitool.springboot.entity.dataobject.${package.ModuleName}.${entity}DO;
import com.mitool.springboot.entity.vo.${package.ModuleName}.${entity}VO;
import org.mapstruct.Mapper;
import java.util.List;
/**
*
* ${table.comment!} app 模型转换服务
*
*
* @author ${author}
* @since ${date}
*/
@Mapper(componentModel = "spring")
public interface ${entity}AppConverter {
${entity}DO toDataObject(${entity}VO ${entity?uncap_first}VO);
List<${entity}DO> toDataObject(List<${entity}VO> ${entity?uncap_first}VOList);
${entity}VO toValueObject(${entity}DO ${entity?uncap_first}DO);
List<${entity}VO> toValueObject(List<${entity}DO> ${entity?uncap_first}DOList);
}
package com.mitool.springboot.entity.dataobject.${package.ModuleName};
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
*
* Title:${entity}
*
*
* Description:描述:${table.comment} 对象
*
*
* @author ${author}
* @version 1.0.0
* @since ${date}
**/
@Data
@TableName("${table.name}")
public class ${entity}DO implements Serializable {
private static final long serialVersionUID = 1L;
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field>
/**
* ${field.comment}
*/
<#if field.keyFlag>
<#assign keyPropertyName="${field.propertyName}"/>
@TableId(value = "${field.name}", type = IdType.AUTO)
#if>
private ${field.propertyType} ${field.propertyName};
#list>
<#------------ END 字段循环遍历 ---------->
}
package com.mitool.springboot.mapper.${package.ModuleName};
import com.mitool.springboot.entity.dataobject.${package.ModuleName}.${entity}DO;
import ${superMapperClassPackage};
<#if mapperAnnotationClass??>
import ${mapperAnnotationClass.name};
#if>
import org.apache.ibatis.annotations.Mapper;
/**
*
* ${table.comment!} Mapper 接口
*
*
* @author ${author}
* @since ${date}
*/
<#if mapperAnnotationClass??>
@${mapperAnnotationClass.simpleName}
#if>
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}DO>
<#else>
@Mapper
public interface ${table.mapperName} extends ${superMapperClass}<${entity}DO> {
}
#if>
<#if enableCache>
#if>
<#list table.fields as field>
<#if field.keyFlag><#--生成主键排在第一位-->
#if>
#list>
<#list table.commonFields as field><#--生成公共字段 -->
#list>
<#list table.fields as field>
<#if !field.keyFlag><#--生成普通字段 -->
#if>
#list>
<#if baseColumnList>
<#list table.commonFields as field>
${field.columnName},
#list>
${table.fieldNames}
#if>
package com.mitool.springboot.service.${package.ModuleName};
import ${superServiceClassPackage};
import com.mitool.springboot.entity.dataobject.${package.ModuleName}.${entity}DO;
/**
*
* ${table.comment!} 服务类
*
*
* @author ${author}
* @since ${date}
*/
<#if kotlin>
interface ${table.serviceName} : ${superServiceClass}<${entity}DO>
<#else>
public interface ${table.serviceName} extends ${superServiceClass}<${entity}DO> {
}
#if>
package com.mitool.springboot.service.${package.ModuleName}.impl;
import com.mitool.springboot.mapper.${package.ModuleName}.${table.mapperName};
import com.mitool.springboot.service.${package.ModuleName}.${table.serviceName};
import com.mitool.springboot.entity.dataobject.${package.ModuleName}.${entity}DO;
import ${superServiceImplClassPackage};
import org.springframework.stereotype.Service;
/**
*
* ${table.comment!} 服务实现类
*
*
* @author ${author}
* @since ${date}
*/
@Service
<#if kotlin>
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}DO>(), ${table.serviceName} {
}
<#else>
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}DO> implements ${table.serviceName} {
}
#if>
package com.mitool.springboot.entity.vo.${package.ModuleName};
<#list table.importPackages as pkg>
<#if pkg?contains("baomidou")>
<#elseif pkg?contains("Serializable")>
<#else>
import ${pkg};
#if>
#list>
import lombok.Data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
*
* ${table.comment!} 请求模型
*
*
* @author ${author}
* @since ${date}
*/
@ApiModel(value="${entity}对象", description="${table.comment!}")
@Data
public class ${entity}VO {
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field>
<#if field.name != "is_delete">
<#if field.keyFlag>
<#assign keyPropertyName="${field.propertyName}"/>
#if>
<#if field.comment!?length gt 0>
/**
* ${field.comment}
*/
@ApiModelProperty(value = "${field.comment}")
#if>
private ${field.propertyType} ${field.propertyName};
#if>
#list>
<#------------ END 字段循环遍历 ---------->
}
使用到了分页的工具类,放在utils目录下
package com.mitool.springboot.utils;
import com.github.pagehelper.PageInfo;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 分页工具类
*
* @author Jimmy.Shen
* @since 2021/11/26
*/
public class PageUtil {
/**
* 通用pageInfo转换
*
* @param sourcePageInfo 源数据
* @param targetClass 目标类型
* @param mapper list转换方法
* @param 目标类型
* @param 源类型
*/
public static <T, S> PageInfo<T> pageInfoCopy(PageInfo<S> sourcePageInfo, Class<T> targetClass, Function<S, T> mapper) {
PageInfo<T> respPageInfo = new PageInfo<>();
respPageInfo.setPageNum(sourcePageInfo.getPageNum());
respPageInfo.setPageSize(sourcePageInfo.getPageSize());
respPageInfo.setSize(sourcePageInfo.getSize());
respPageInfo.setStartRow(sourcePageInfo.getStartRow());
respPageInfo.setEndRow(sourcePageInfo.getEndRow());
respPageInfo.setPages(sourcePageInfo.getPages());
respPageInfo.setPrePage(sourcePageInfo.getPrePage());
respPageInfo.setNextPage(sourcePageInfo.getNextPage());
respPageInfo.setIsFirstPage(sourcePageInfo.isIsFirstPage());
respPageInfo.setIsLastPage(sourcePageInfo.isIsLastPage());
respPageInfo.setHasPreviousPage(sourcePageInfo.isHasPreviousPage());
respPageInfo.setHasNextPage(sourcePageInfo.isHasNextPage());
respPageInfo.setNavigatePages(sourcePageInfo.getNavigatePages());
respPageInfo.setNavigatepageNums(sourcePageInfo.getNavigatepageNums());
respPageInfo.setNavigateFirstPage(sourcePageInfo.getNavigateFirstPage());
respPageInfo.setNavigateLastPage(sourcePageInfo.getNavigateLastPage());
respPageInfo.setTotal(sourcePageInfo.getTotal());
List<T> pageList = sourcePageInfo.getList().stream().map(mapper).collect(Collectors.toList());
respPageInfo.setList(pageList);
return respPageInfo;
}
}