【项目实战】基于MyBatis-Plus的最新版本SpringBoot项目搭建

一、简介

因公司框架更新的缘故,需实现于JAVA17版本下的SpringBoot项目搭建,过程中也有遇到一些问题,希望借本文分享给大家。创作时间较紧,难免存在纰漏,望在评论区指出。

1.1 配置版本

具体使用到的各配置版本信息如下:

  • JAVA17 当前最新版本为20,但害怕功能不稳定故选用JAVA17;
  • SpringBoot 3.0.5 当前最新版本为3.1.0(SNAPSHOT),但是镜像上找不到该版本的spring-boot-starter-parent包,故退而求其次;
  • MyBatis-Plus 3.5.3.1 官网上标注的最新版本为3.5.2,3.5.3.1是Maven能拉取到的最高版本的包。选用该版本是因为SpringBoot 3.0.0以上的版本无法使用springfox的包,而是使用springdoc的包,3.5.2版本不支持生成该包的对应注解,但是官网的文档并未对3.5.3.1版本的更新作说明;
  • MySql 8.0.30 对应自己的安装版本即可;
  • Swagger OpenAI 3 版本2无法支持SpringBoot 3.0.0以上的版本使用。

1.2 配置文件

pom.xml文件部分代码如下:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>3.0.5</version>
	<relativePath/>
</parent>

<properties>
	<java.version>17</java.version>
</properties>

<!-- Spring Boot 相关配置 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

<!-- 解决:No active profile set, falling back to default profiles: default -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- MyBatis Plus 相关配置 -->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.5.3.1</version>
</dependency>

<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generator</artifactId>
	<version>3.5.3.1</version>
</dependency>

<dependency>
	<groupId>org.apache.velocity</groupId>
	<artifactId>velocity-engine-core</artifactId>
	<version>2.3</version>
</dependency>

<!-- MySQL相关配置 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.30</version>
</dependency>

<!-- Lombox相关配置 -->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

<!-- Swagger配置 -->
<dependency>
	<groupId>org.springdoc</groupId>
	<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
	<version>2.0.4</version>
</dependency>

1.3 项目结构

项目结构如下图所示:
项目结构图

二、项目搭建

2.1 SpringBoot项目搭建

进入Spring Initializr,根据下图完成配置,点击生成。
项目搭建图例

2.2 项目的初次启动

首次启动项目会发现控制台输出No active profile set, falling back to default profiles: default后即终止,在pom.xml中添加如下配置即可解决:

<!-- 解决:No active profile set, falling back to default profiles: default -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.3 MyBatis-Plus配置与自动生成代码实现

官方文档:https://baomidou.com/

2.3.1 application.properties文件

配置信息如下:

server.port = 8081
spring.profiles.active=default
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/saas?useLegacyDatetimeCode=false&amp
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2.3.2 Application文件

添加MapperScan扫描Dao层,代码如下:

package com.example.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.example.demo.dao")
public class Application {
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

2.3.3 MySQL代码生成器

⚠️ 注意:

  1. 笔者使用MacOS开发,WinOS可能需要修改对应的代码输出路径;
  2. MyBatis-Plus 3.5.3.1版本下,包配置中不存在other自定义文件的输出路径配置,需要通过重写配置引擎的自定义文件输出方法实现,自定义文件输出通过注入配置实现;
  3. 执行Main方法,即可生成对应表的代码;
  4. 自定义的模版文件放在resources下的templates包中,需对应自己引入的配置引擎选择,笔者选用的是velocity。自定义模版文件可以在mybatis-plus-generator库下的templates包中复制。

代码如下:

package com.example.demo.generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import jakarta.validation.constraints.NotNull;

import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MySQLGenerator{

    public static void main(String[] args) {
        Generation("saas", "sys_user");
    }

    /**
     * 根据表名生成相应结构代码
     *
     * @param databaseName 数据库名
     * @param tableName    表名
     */
    public static void Generation(String databaseName, String tableName) {
        FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/" + databaseName + "?&useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai", "root", "240010")

                // 全局配置
                .globalConfig(builder -> {
                    builder
                            // 禁止打开输出目录
                            .disableOpenDir()
                            // 作者名称
                            .author("")
                            // 启用swagger
                            .enableSpringdoc()
                            // 时间策略
                            .dateType(DateType.TIME_PACK)
                            // 注释日期
                            .commentDate("yyyy-MM-dd")
                            // 指定输出目录
                            .outputDir("src/main/java");
                })

                // 包配置
                .packageConfig(builder -> {
                    builder
                            // 父包名
                            .parent("com.example.demo")
                            // 实体类包名
                            .entity("bean")
                            // 控制层包名
                            .controller("controller")
                            // 服务层包名
                            .service("service")
                            // 服务层实现类包名
                            .serviceImpl("service.impl")
                            // 映射层包名
                            .mapper("dao")
                            // 映射层XML包名
                            .xml("dao.xml")
                            .joinPackage("dto");
                })

                // 模版配置
                .templateConfig(builder -> {
                    builder
                            // 实体类
                            .entity("/templates/entity.java")
                            // 控制类
                            .controller(("/templates/controller.java"))
                            // 服务类
                            .service("/templates/service.java")
                            // 服务实现类
                            .serviceImpl("/templates/serviceImpl.java")
                            // 映射
                            .mapper("/templates/mapper.java")
                            // 映射XML
                            .xml("/templates/mapper.xml");
                })

                // 策略配置
                .strategyConfig(builder -> {
                    builder
                            // 增加表匹配(内存过滤)
                            .addInclude(tableName)
                            // 实体类策略配置
                            .entityBuilder()
                            // 实体类:开启lombok模型
                            .enableLombok()
                            // 实体类:开启链式模型
                            .enableChainModel()
                            // 实体类:数据库表映射到实体的命名策略,默认下划线转驼峰命名:NamingStrategy.underline_to_camel
                            .naming(NamingStrategy.underline_to_camel)
                            // 实体类:表字段映射实体属性命名规则,默认null,不指定按照naming执行
                            .columnNaming(NamingStrategy.underline_to_camel)
                            // 实体类:添加全局主键类型
                            .idType(IdType.AUTO)
                            // 实体类:格式化文件名称
                            .formatFileName("%s")
                            // 实体类:覆盖已生成文件
                            .enableFileOverride()
                            // 映射层策略配置
                            .mapperBuilder()
                            // 映射层:启用 BaseResultMap 生成
                            .enableBaseResultMap()
                            // 映射层:启用 BaseColumnList
                            .enableBaseColumnList()
                            // 映射层:格式化 mapper 文件名称
                            .formatMapperFileName("%sDao")
                            // 映射层:格式化 xml 实现类文件名称
                            .formatXmlFileName("%sMapper")
                            // 映射层:覆盖已生成文件
                            .enableFileOverride()
                            // 服务层策略配置
                            .serviceBuilder()
                            // 服务层:格式化 service 接口文件名称
                            .formatServiceFileName("I%sService")
                            // 服务层:格式化 service 实现类文件名称
                            .formatServiceImplFileName("%sServiceImpl")
                            // 服务层:覆盖已生成文件
                            .enableFileOverride()
                            // 控制层策略配置
                            .controllerBuilder()
                            // 控制层:覆盖已生成文件
                            .enableFileOverride()
                            // 控制层:开启生成@RestController 控制器
                            .enableRestStyle();
                })

                // 注入配置
                .injectionConfig(consumer -> {
                    Map<String, Object> dtoMap = new HashMap<>();
                    // 传输类包名
                    dtoMap.put("dtoPackage", "dto");
                    // 传输类覆盖已生成文件
                    dtoMap.put("dtoOverride", true);
                    consumer
                            // 传输类自定义参数
                            .customMap(dtoMap)
                            // 传输类模版配置
                            .customFile(Collections.singletonMap("Dto.java", "/templates/dto.java.vm"));
                })

                // 配置引擎
                .templateEngine(new EnhanceFreemarkerTemplateEngine())

                .execute();
    }

    /**
     * 重写Dto生成方法的路径
     */
    public static final class EnhanceFreemarkerTemplateEngine extends VelocityTemplateEngine {
        public void outputCustomFile(@NotNull List<CustomFile> customFiles, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
            String entityName = tableInfo.getEntityName();
            String parentPath = this.getPathInfo(OutputFile.parent) + "/" + objectMap.get("dtoPackage");
            customFiles.forEach((file) -> {
                String filePath = StringUtils.isNotBlank(file.getFilePath()) ? file.getFilePath() : parentPath;
                if (StringUtils.isNotBlank(file.getPackageName())) {
                    filePath = filePath + File.separator + file.getPackageName();
                    filePath = filePath.replaceAll("\\.", "\\" + File.separator);
                }
                String fileName = filePath + File.separator + entityName + file.getFileName();
                this.outputFile(new File(fileName), objectMap, file.getTemplatePath(), (boolean) objectMap.get("dtoOverride"));
            });
        }
    }
}

2.3.4 项目地址

我的GitCode代码生成器项目地址,希望多多Star。

2.4 Swagger OpenAI 3.0配置

官方文档:https://springdoc.org/v2/index.html#Introduction

2.4.1 application.properties文件

配置信息如下:

springdoc.packagesToScan=com.example.demo
springdoc.api-docs.groups.enabled=true
springdoc.group-configs[0].group=service
springdoc.group-configs[0].paths-to-match=/service/**
springdoc.group-configs[1].group=api
springdoc.group-configs[1].paths-to-match=/api/**
springdoc.api-docs.resolve-schema-properties=true
springdoc.swagger-ui.urlsPrimaryName=service
springdoc.swagger-ui.operations-sorter=method

2.4.2 SwaggerConfig配置文件

package com.example.demo;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {
    @Bean
    public OpenAPI springShopOpenAPI() {
        return new OpenAPI().info(new Info().title("基于Swagger3【DEMO】接口管理系统").version("v1.0").description("API接口"))
                .components(new Components().addSecuritySchemes("bearer-key",
                                new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
    }
}

2.5 MyBatis-Plus官方分页实现

2.5.1 源码分析

官网分页配置如下图所示
官网分页配置
可以看到官网推荐的是在分页拦截器中配置对应的数据库类型,这个地方容易产生误导。我们的目标是实现一套工具类,如果每次都需要去修改是不切实际的。
找到源码设置数据库类型的位置:

public PaginationInnerInterceptor(DbType dbType) {
    this.dbType = dbType;
}

protected IDialect findIDialect(Executor executor) {
    if (this.dialect != null) {
        return this.dialect;
    } else if (this.dbType != null) {
        this.dialect = DialectFactory.getDialect(this.dbType);
        return this.dialect;
    } else {
        return DialectFactory.getDialect(JdbcUtils.getDbType(executor));
    }
}
public static DbType getDbType(Executor executor) {
    try {
        Connection conn = executor.getTransaction().getConnection();
        return (DbType)CollectionUtils.computeIfAbsent(JDBC_DB_TYPE_CACHE, conn.getMetaData().getURL(), JdbcUtils::getDbType);
    } catch (SQLException var2) {
        throw ExceptionUtils.mpe(var2);
    }
}

可以看到,当传入的数据库参数为空时,方法会根据数据库连接自动判断对应的数据库类型。
源码截图

2.5.2 MybatisPlusPageConfig配置代码

⚠️ 注意:如果配置成工具类,需要在Application中添加ComponentScan扫描该配置代码所属的包,否则代码无法执行。

@Configuration
public class MybatisPlusPageConfig {
    @Bean
    public MybatisPlusInterceptor paginationInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布熬夜了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值