纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

news2025/6/12 8:02:24

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

  • 1、依赖
    • 1.1、依赖版本
    • 1.2、pom.xml
  • 2、代码
    • 2.1、SqlSession 构造器
    • 2.2、MybatisPlus代码生成器
    • 2.3、获取 config.yml 配置
      • 2.3.1、config.yml
      • 2.3.2、项目配置类
    • 2.4、ftl 模板
      • 2.4.1、实体类
      • 2.4.2、Mybatis-Plus Join Mapper 接口
  • 3、测试类
    • 3.1、非线程安全
    • 3.2、线程安全
    • 3.3、MybatisPlusJoin
    • 3.4、代码生成器

1、依赖

1.1、依赖版本

依赖版本
Mysql-Connector-J9.3.0
HikariCP5.1.0
SnakeYaml2.4
Lombok1.18.38
Mybatis-Plus3.5.9
Mybatis-Plus Generator3.5.9
Mybatis-Plus-Join1.4.13
Spring-Core5.3.39

1.2、pom.xml

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wxhnyfy</groupId>
    <artifactId>maven-mybatis-plus</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <name>maven-mybatis-plus</name>
    <url>http://maven.apache.org</url>

    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.13.1</junit.version>
        <mybatis-plus.version>3.5.9</mybatis-plus.version>
        <mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
        <org.apache.logging.log4j.version>2.23.1</org.apache.logging.log4j.version>
        <slf4j-reload4j.version>2.0.12</slf4j-reload4j.version>
        <mysql-connector-java.version>9.3.0</mysql-connector-java.version>
        <hikaricp.version>5.1.0</hikaricp.version>
        <freemarker.version>2.3.32</freemarker.version>
        <fastjson2.version>2.0.51</fastjson2.version>
        <vfs.version>3.3.2.Final</vfs.version>
        <lombok.version>1.18.38</lombok.version>
        <snakeyaml.version>2.4</snakeyaml.version>
        <commons-io.version>2.19.0</commons-io.version>
        <spring-core.version>5.3.39</spring-core.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${org.apache.logging.log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${org.apache.logging.log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-reload4j</artifactId>
            <version>${slf4j-reload4j.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>${freemarker.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>${fastjson2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.jboss</groupId>
            <artifactId>jboss-vfs</artifactId>
            <version>${vfs.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>${snakeyaml.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io.version}</version>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>${hikaricp.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>${mysql-connector-java.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-jsqlparser</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.yulichang</groupId>
            <artifactId>mybatis-plus-join</artifactId>
            <version>${mybatis-plus-join.version}</version>
        </dependency>
        <!-- mybatis-plus-join反射需要用到 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-core.version}</version>
        </dependency>

    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**</include>
                </includes>
            </resource>
            <!-- 扫描java目录下的xml文件 -->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**</include>
                </includes>
            </testResource>
            <testResource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </testResource>
        </testResources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2、代码

2.1、SqlSession 构造器

package com.wxhnyfy;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.injector.MPJSqlInjector;
import com.github.yulichang.interceptor.MPJInterceptor;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.session.SqlSessionManager;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 获取SqlSession
 *
 * @author wxhnyfy
 */
public class GetSqlSession {

    private static final Logger logger = LoggerFactory.getLogger(GetSqlSession.class);

    private static final ProjectConfiguration CONFIGURATION = ProjectConfiguration.getConfiguration();

    /**
     * SqlSession
     */
    private static SqlSession sqlSession;
    /**
     * SqlSessionFactory
     */
    private static SqlSessionFactory sqlSessionFactory;
    /**
     * SqlSessionManager
     */
    private static SqlSessionManager sqlSessionManager;

    /**
     * 获取SqlSessionFactory
     */
    private static void setMybatisPlusSqlSessionFactory() {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //这是mybatis-plus的配置对象,对mybatis的Configuration进行增强
        MybatisConfiguration configuration = new MybatisConfiguration();

        //构建mybatis-plus需要的globalconfig
        GlobalConfig globalConfig = new GlobalConfig();
        //必须初始化dbconfig,否则会报空指针
        globalConfig.setDbConfig(new GlobalConfig.DbConfig());
        //此参数会自动生成实现baseMapper的基础方法映射
        globalConfig.setSqlInjector(new DefaultSqlInjector());
        //设置id生成器
        globalConfig.setIdentifierGenerator(DefaultIdentifierGenerator.getInstance());
        //设置超类mapper
        globalConfig.setSuperMapperClass(BaseMapper.class);
        //globalConfig必须在添加Mapper之前设置到全局变量,否则会读取不到SQL注入器
        GlobalConfigUtils.setGlobalConfig(configuration, globalConfig);

        //这是初始化配置,后面会添加这部分代码
        initConfiguration(configuration);
        //设置数据源
        Environment environment = new Environment("1", new JdbcTransactionFactory(), initDataSource());
        configuration.setEnvironment(environment);

        try {
            registryMapperXml(configuration, CONFIGURATION.getMybatisPlusConfiguration().getMapperConfiguration().getXmlPackage());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //构建sqlSessionFactory
        sqlSessionFactory = sqlSessionFactoryBuilder.build(configuration);
    }

    /**
     * 获取 MybatisPlus-Join SqlSessionFactory
     */
    private static void setMybatisPlusJoinSqlSessionFactory() {
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //这是mybatis-plus的配置对象,对mybatis的Configuration进行增强
        MybatisConfiguration configuration = new MybatisConfiguration();
        //添加拦截器 MPJInterceptor
        configuration.addInterceptor(new MPJInterceptor());

        //构建mybatis-plus需要的globalconfig
        GlobalConfig globalConfig = new GlobalConfig();
        //必须初始化dbconfig,否则会报空指针
        globalConfig.setDbConfig(new GlobalConfig.DbConfig());
        //此参数会自动生成实现baseMapper的基础方法映射
        globalConfig.setSqlInjector(new MPJSqlInjector());
        //设置id生成器
        globalConfig.setIdentifierGenerator(DefaultIdentifierGenerator.getInstance());
        //设置超类mapper
        globalConfig.setSuperMapperClass(MPJBaseMapper.class);
        //globalConfig必须在添加Mapper之前设置到全局变量,否则会读取不到SQL注入器
        GlobalConfigUtils.setGlobalConfig(configuration, globalConfig);

        //这是初始化配置,后面会添加这部分代码
        initConfiguration(configuration);
        //设置数据源
        Environment environment = new Environment("1", new JdbcTransactionFactory(), initDataSource());
        configuration.setEnvironment(environment);

        try {
            registryMapperXml(configuration, CONFIGURATION.getMybatisPlusConfiguration().getMapperConfiguration().getXmlPackage());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        logger.debug("已注册的方法:{}", JSON.toJSONString(configuration.getMappedStatementNames(), JSONWriter.Feature.WriteMapNullValue));

        //构建sqlSessionFactory
        sqlSessionFactory = sqlSessionFactoryBuilder.build(configuration);
    }

    /**
     * 获取SqlSession(线程不安全)
     *
     * @return sqlSession
     */
    public static SqlSession getMybatisPlusSqlSession() {
        if (sqlSession == null) {
            setMybatisPlusSqlSessionFactory();
            sqlSession = sqlSessionFactory.openSession(true);
        }
        return sqlSession;
    }

    /**
     * 获取线程安全的SqlSessionManager
     *
     * @return sqlSessionManager
     */
    public static SqlSessionManager safeMybatisPlusSqlSession() {
        if (sqlSessionManager == null) {
            setMybatisPlusSqlSessionFactory();
            sqlSessionManager = SqlSessionManager.newInstance(sqlSessionFactory);
        }
        return sqlSessionManager;
    }

    /**
     * 获取线程安全的SqlSessionManager
     *
     * @return sqlSessionManager
     */
    public static SqlSessionManager safeMybatisPlusJoinSqlSession() {
        if (sqlSessionManager == null) {
            setMybatisPlusJoinSqlSessionFactory();
            sqlSessionManager = SqlSessionManager.newInstance(sqlSessionFactory);
        }
        return sqlSessionManager;
    }

    /**
     * 清理SqlSession
     */
    public static void cleanSqlSession() {
        if (sqlSession != null) {
            sqlSession.clearCache();
        }
    }

    /**
     * 清理sqlSessionManager
     */
    public static void cleanSqlSessionManager() {
        if (sqlSessionManager != null) {
            sqlSessionManager.clearCache();
        }
    }

    /**
     * 初始化配置
     *
     * @param configuration configuration
     */
    private static void initConfiguration(MybatisConfiguration configuration) {
        //开启驼峰大小写转换
        configuration.setMapUnderscoreToCamelCase(CONFIGURATION.getMybatisPlusConfiguration().getMapperConfiguration().isMapUnderscoreToCamelCase());
        //配置添加数据自动返回数据主键
        configuration.setUseGeneratedKeys(CONFIGURATION.getMybatisPlusConfiguration().getMapperConfiguration().isUseGeneratedKeys());
        //这是初始化连接器,如mybatis-plus的分页插件
        configuration.addInterceptor(initInterceptor());
        //配置日志实现,如果需要打印结果集,则取消注释
        //configuration.setLogImpl(StdOutImpl.class);
        //扫描mapper接口所在包
        configuration.addMappers(CONFIGURATION.getMybatisPlusConfiguration().getMapperConfiguration().getMapperPackage());
    }

    /**
     * 初始化数据源
     *
     * @return DataSource
     */
    private static DataSource initDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(CONFIGURATION.getJdbc().getUrl());
        dataSource.setDriverClassName(CONFIGURATION.getJdbc().getDriverClassName());
        dataSource.setUsername(CONFIGURATION.getJdbc().getUsername());
        dataSource.setPassword(CONFIGURATION.getJdbc().getPassword());
        dataSource.setIdleTimeout(60000);
        dataSource.setAutoCommit(true);
        dataSource.setMaximumPoolSize(5);
        dataSource.setMinimumIdle(1);
        dataSource.setMaxLifetime(60000 * 10);
        dataSource.setConnectionTestQuery("SELECT 1");
        return dataSource;
    }

    /**
     * 初始化分页拦截器
     *
     * @return Interceptor
     */
    private static Interceptor initInterceptor() {
        //创建mybatis-plus插件对象
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //构建分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true);
        paginationInnerInterceptor.setMaxLimit(200L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }

    /**
     * 解析mapper.xml文件
     *
     * @param configuration MybatisConfiguration
     * @param classPath     包名
     * @throws IOException 异常
     */
    private static void registryMapperXml(MybatisConfiguration configuration, String classPath) throws IOException {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        Enumeration<URL> mapper = contextClassLoader.getResources(classPath);
        while (mapper.hasMoreElements()) {
            URL url = mapper.nextElement();
            if ("file".equals(url.getProtocol())) {
                String path = url.getPath();
                File file = new File(path);
                File[] files = file.listFiles();
                if (files != null) {
                    for (File f : files) {
                        FileInputStream in = new FileInputStream(f);
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(in, configuration, f.getPath(), configuration.getSqlFragments());
                        xmlMapperBuilder.parse();
                        in.close();
                    }
                }
            } else {
                JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
                JarFile jarFile = urlConnection.getJarFile();
                Enumeration<JarEntry> entries = jarFile.entries();
                while (entries.hasMoreElements()) {
                    JarEntry jarEntry = entries.nextElement();
                    if (jarEntry.getName().endsWith(".xml")) {
                        InputStream in = jarFile.getInputStream(jarEntry);
                        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(in, configuration, jarEntry.getName(), configuration.getSqlFragments());
                        xmlMapperBuilder.parse();
                        in.close();
                    }
                }
            }
        }
    }
}

2.2、MybatisPlus代码生成器

package com.wxhnyfy;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.Entity;
import com.baomidou.mybatisplus.generator.config.builder.Mapper;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

/**
 * MybatisPlus代码生成器
 *
 * @author wxhnyfy
 * @package com.wxhnyfy
 * @project maven-mybatis-plus
 * @date 2025/6/7
 */
public class MybatisPlusGenerator {
    private static final Logger logger = LoggerFactory.getLogger(MybatisPlusGenerator.class);
    private static final ProjectConfiguration CONFIGURATION = ProjectConfiguration.getConfiguration();

    /**
     * 输出目录
     */
    private static String OUTPUT_DIR;
    /**
     * xml文件输出目录
     */
    private static String XML_FILE_OUTPUT_DIR;

    private static void initPath() {
        // 获取项目根目录
        File file = new File("1.txt");
        String projectPath = file.getAbsolutePath().replace(file.getName(), "");
        String projectName = CONFIGURATION.getMybatisPlusConfiguration().getGenerator().getProjectName();
        if (null != projectName &&
                !projectName.isEmpty()) {
            if (!projectName.endsWith("\\")) {
                CONFIGURATION.getMybatisPlusConfiguration().getGenerator().setProjectName(
                        projectName + "\\"
                );
            }
            projectPath = file.getAbsolutePath().replace(file.getName(), "")
                    + CONFIGURATION.getMybatisPlusConfiguration().getGenerator().getProjectName();
        }
        logger.info(">>>> 项目根目录: {}", projectPath);
        OUTPUT_DIR = projectPath + CONFIGURATION.getMybatisPlusConfiguration().getGenerator().getCodeDir();
        XML_FILE_OUTPUT_DIR = projectPath + CONFIGURATION.getMybatisPlusConfiguration().getGenerator().getXmlDir();
        logger.info(">>>> java文件输出目录: {}", OUTPUT_DIR);
        logger.info(">>>> xml文件输出目录: {}", XML_FILE_OUTPUT_DIR);
    }

    /**
     * 获取策略配置
     *
     * @param queryList           表名
     * @param isGenerateMpjMapper 是否生成mpj mapper
     * @return 策略配置
     */
    private static Consumer<StrategyConfig.Builder> getStrategyConfigBuilder(List<String> queryList, boolean isGenerateMpjMapper) {
        return builder -> {
            boolean isGenerateMapperXml = CONFIGURATION.getMybatisPlusConfiguration().getGenerator().isGenerateMapperXml();
            boolean isUseDefaultFreemarkerTemplate = CONFIGURATION.getMybatisPlusConfiguration().getGenerator().isUseDefaultFreemarkerTemplate();
            boolean isEnableLombok = CONFIGURATION.getMybatisPlusConfiguration().getGenerator().isEnableLombok();

            builder.addInclude(queryList).controllerBuilder().disable().serviceBuilder().disableService().disableServiceImpl().disable();

            Mapper.Builder mapperBuilder = builder.mapperBuilder();
            Entity.Builder entityBuilder = builder.entityBuilder();

            if (isGenerateMapperXml) {
                if (isGenerateMpjMapper) {
                    mapperBuilder.enableFileOverride().mapperTemplate("/templates/mapper-mpj.java");
                } else {
                    mapperBuilder.enableFileOverride();
                }
            } else {
                if (isGenerateMpjMapper) {
                    mapperBuilder.disableMapperXml().enableFileOverride().mapperTemplate("/templates/mapper-mpj.java");
                } else {
                    mapperBuilder.disableMapperXml().enableFileOverride();
                }
            }

            if (isEnableLombok) {
                if (isUseDefaultFreemarkerTemplate) {
                    entityBuilder.enableLombok().enableFileOverride();
                } else {
                    entityBuilder.enableLombok().enableFileOverride().javaTemplate("/templates/entity.java");
                }
            } else {
                entityBuilder.enableFileOverride();
            }
        };
    }

    /**
     * 全局配置
     *
     * @return 全局配置
     */
    private static Consumer<GlobalConfig.Builder> getGlobalConfigBuilder() {
        return builder -> {
            // 设置作者
            builder.author(CONFIGURATION.getMybatisPlusConfiguration().getGenerator().getAuthor())
                    // 生成后不打开目录
                    .disableOpenDir()
                    // 指定输出目录
                    .outputDir(OUTPUT_DIR);
        };
    }

    /**
     * 数据源配置
     *
     * @return 数据源配置
     */
    private static Consumer<DataSourceConfig.Builder> getDataSourceConfigBuilder() {
        return builder ->
                builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                    if (typeCode == Types.SMALLINT) {
                        // 自定义类型转换
                        return DbColumnType.INTEGER;
                    }
                    return typeRegistry.getColumnType(metaInfo);
                });
    }

    /**
     * 包配置
     *
     * @return 包配置
     */
    private static Consumer<PackageConfig.Builder> getPackageConfigBuilder() {
        return builder ->
                // 设置父包名
                builder.parent(CONFIGURATION.getMybatisPlusConfiguration().getGenerator().getParentPackage())
                        .entity("entity")
                        .mapper("mapper")
                        .pathInfo(Collections.singletonMap(OutputFile.xml, XML_FILE_OUTPUT_DIR));
    }

    /**
     * 代码生成器
     *
     * @param tableName 表名
     */
    public static void generatorMybatisPlus(String... tableName) {
        initPath();
        List<String> queryList = new ArrayList<>(List.of(tableName));
        logger.info(">>>> Mybatis-Plus 代码生成器,本实例只生成实体类和Mapper");
        logger.info(">>>> 本次生成的表名:{}", JSON.toJSONString(queryList, JSONWriter.Feature.WriteMapNullValue));

        FastAutoGenerator.create(CONFIGURATION.getJdbc().getUrl(), CONFIGURATION.getJdbc().getUsername(), CONFIGURATION.getJdbc().getPassword())
                .globalConfig(getGlobalConfigBuilder())
                .dataSourceConfig(getDataSourceConfigBuilder())
                .packageConfig(getPackageConfigBuilder())
                .strategyConfig(getStrategyConfigBuilder(queryList, false))
                // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .templateEngine(new FreemarkerTemplateEngine())
                .templateConfig(template ->
                        // 显式禁用
                        template.disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.SERVICE_IMPL)
                )
                .execute();
        logger.info(">>>> 成功!!!");
    }

    /**
     * 代码生成器(MPJ)
     *
     * @param tableName 表名
     */
    public static void generatorMybatisPlusJoin(String... tableName) {
        initPath();
        List<String> queryList = new ArrayList<>(List.of(tableName));
        logger.info(">>>> Mybatis-Plus 代码生成器,本实例只生成实体类和Mapper");
        logger.info(">>>> 本次生成的表名:{}", JSON.toJSONString(queryList, JSONWriter.Feature.WriteMapNullValue));

        FastAutoGenerator.create(CONFIGURATION.getJdbc().getUrl(), CONFIGURATION.getJdbc().getUsername(), CONFIGURATION.getJdbc().getPassword())
                .globalConfig(getGlobalConfigBuilder())
                .dataSourceConfig(getDataSourceConfigBuilder())
                .packageConfig(getPackageConfigBuilder())
                .strategyConfig(getStrategyConfigBuilder(queryList, true))
                // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .templateEngine(new FreemarkerTemplateEngine())
                .templateConfig(template ->
                        // 显式禁用
                        template.disable(TemplateType.CONTROLLER, TemplateType.SERVICE, TemplateType.SERVICE_IMPL)
                )
                .execute();
        logger.info(">>>> 成功!!!");
    }
}

2.3、获取 config.yml 配置

2.3.1、config.yml

jdbc:
  url: jdbc:mysql://localhost:3306/region?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
  username: root
  password: CWCcwy12
  driverClassName: com.mysql.cj.jdbc.Driver

mybatisPlusConfiguration:
  generator:
    #  作者
    author: wxhnyfy
    #  代码生成目录
    codeDir: src/main/java
    #  xml文件生成目录
    xmlDir: src/main/resources/mapper
    #  entity、mapper的父包名
    parentPackage: com.wxhnyfy
    #   是否生成mapper.xml文件
    generateMapperXml: true
    #  是否使用lombok
    enableLombok: true
    #  是否使用默认的freemarker模板
    useDefaultFreemarkerTemplate: false
    #  项目名(有子模块需要填写,否则为空)
    projectName: ""
  mapperConfiguration:
    #  是否开启驼峰转下划线
    mapUnderscoreToCamelCase: true
    #  是否添加数据自动返回数据主键
    useGeneratedKeys: true
    # mapper接口所在路径
    mapperPackage: com.wxhnyfy.mapper
    # mapper.xml文件所在路径(resources目录下)
    xmlPackage: mapper

2.3.2、项目配置类

package com.wxhnyfy;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;

/**
 * 项目配置
 *
 * @author wxhnyfy
 * @package com.wxhnyfy
 * @project maven-mybatis-plus
 * @date 2025/6/7
 */
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ProjectConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(ProjectConfiguration.class);
    /**
     * 数据库连接信息
     */
    private Jdbc jdbc;    
    /**
     * mybatis-plus配置
     */
    private static ProjectConfiguration CONFIGURATION;
    /**
     * mybatis-plus配置
     */
    private MybatisPlusConfiguration mybatisPlusConfiguration;

    /**
     * 获取项目配置
     *
     * @return 项目配置
     */
    public static ProjectConfiguration getConfiguration() {
        if (null == CONFIGURATION) {
            InputStream input = null;
            try {
                input = ProjectConfiguration.class.getResourceAsStream("/config.yml");
                if (input != null) {
                    String yamlStr = IOUtils.toString(input, StandardCharsets.UTF_8);
                    logger.debug(">>>> 读取配置文件内容:{}", yamlStr);
                    Yaml yaml = new Yaml();
                    CONFIGURATION = yaml.loadAs(yamlStr, ProjectConfiguration.class);
                }
            } catch (Exception ex) {
                logger.error(">>>> 读取配置文件出现错误:", ex);
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (Exception ex) {
                        logger.error(">>>> 读取配置文件出现错误:", ex);
                    }
                }
            }
        }
        return CONFIGURATION;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Jdbc {
        /**
         * 数据库连接地址
         */
        private String url;
        /**
         * 用户名
         */
        private String username;
        /**
         * 密码
         */
        private String password;
        /**
         * 驱动类
         */
        private String driverClassName;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class MybatisPlusConfiguration {
        /**
         * 代码生成信息
         */
        private Generator generator;
        /**
         * mapper配置信息
         */
        private MapperConfiguration mapperConfiguration;
    }

    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Generator {
        /**
         * 是否生成mapper.xml文件
         */
        private boolean generateMapperXml = true;
        /**
         * 是否使用lombok
         */
        private boolean enableLombok = true;
        /**
         * 是否使用默认的freemarker模板
         */
        private boolean useDefaultFreemarkerTemplate = false;
        /**
         * 作者
         */
        private String author;
        /**
         * 代码生成目录
         */
        private String codeDir;
        /**
         * xml文件生成目录
         */
        private String xmlDir;
        /**
         * entity、mapper的父包名
         */
        private String parentPackage;
        /**
         * 项目名(有子模块需要填写,否则为空)
         */
        private String projectName = "";
    }

    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    public static class MapperConfiguration {
        /**
         * 是否开启驼峰转下划线
         */
        private boolean mapUnderscoreToCamelCase = false;
        /**
         * 是否添加数据自动返回数据主键
         */
        private boolean useGeneratedKeys = false;
        /**
         * mapper接口所在路径
         */
        private String mapperPackage;
        /**
         * mapper.xml文件所在路径(resources目录下)
         */
        private String xmlPackage;
    }
}

2.4、ftl 模板

2.4.1、实体类

package ${package.Entity};

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.*;

/**
* ${table.comment!} 实体类
*
* @author ${author}
* @since ${date}
*/
@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
<#if table.convert>
@TableName("${table.name}")
</#if>
public class ${entity} {

<#-- 遍历字段生成属性 -->
<#list table.fields as field>
    <#if field.keyFlag>
        <#if field.keyIdentityFlag>
    @TableId(value = "${field.name}", type = IdType.AUTO)
        <#else>
    @TableId("${field.name}")
        </#if>
    <#else>
    @TableField("${field.name}")
    </#if>
    private ${field.propertyType} ${field.propertyName};

</#list>
}

2.4.2、Mybatis-Plus Join Mapper 接口

package ${package.Mapper};

import ${package.Entity}.${entity};
import com.github.yulichang.base.MPJBaseMapper;

/**
* ${table.comment!} Mapper 接口
*
* @author ${author}
* @since ${date}
*/
public interface ${table.mapperName} extends MPJBaseMapper<${entity}> {
}

3、测试类

3.1、非线程安全

@Test
public void testSqlSession() {
    SqlSession session = GetSqlSession.getMybatisPlusSqlSession();

    AmapRegionMapper amapRegionMapper = session.getMapper(AmapRegionMapper.class);
    List<AmapRegion> list = amapRegionMapper.selectList(new Page<>(1, 100),
            new LambdaQueryWrapper<AmapRegion>()
                    .eq(AmapRegion::getLevel, "province")
    );
    for (AmapRegion amapRegion : list) {
        logger.debug(">>> {}", JSON.toJSONString(amapRegion, JSONWriter.Feature.WriteMapNullValue));
    }
    GetSqlSession.cleanSqlSession();
    session.commit();
    session.close();
}

3.2、线程安全

@Test
public void testSqlSessionManager() {
    SqlSessionManager sqlSessionManager = GetSqlSession.safeMybatisPlusSqlSession();
    // 开启session管理
    sqlSessionManager.startManagedSession(true);
    AmapRegionMapper amapRegionMapper = sqlSessionManager.getMapper(AmapRegionMapper.class);
    List<AmapRegion> amapRegionList = amapRegionMapper.selectList(new Page<>(1, 100),
            new LambdaQueryWrapper<AmapRegion>()
                    .eq(AmapRegion::getLevel, "province")
    );
    for (AmapRegion amapRegion : amapRegionList) {
        logger.debug(">>> {}", JSON.toJSONString(amapRegion, JSONWriter.Feature.WriteMapNullValue));
    }
    GetSqlSession.cleanSqlSessionManager();
    //  提交
    sqlSessionManager.commit();
    sqlSessionManager.close();
}

3.3、MybatisPlusJoin

@Test
public void testMybatisPlusJoin() {
    SqlSessionManager sqlSessionManager = GetSqlSession.safeMybatisPlusJoinSqlSession();
    sqlSessionManager.startManagedSession();

    ChinaMcaRegionMapper mapper = sqlSessionManager.getMapper(ChinaMcaRegionMapper.class);

    long total = mapper.selectJoinCount(new MPJLambdaWrapper<ChinaMcaRegion>("l1")
            .leftJoin(ChinaMcaRegion.class, "l2", ChinaMcaRegion::getParentid, "l1", ChinaMcaRegion::getId)
            .leftJoin(ChinaMcaRegion.class, "l3", ChinaMcaRegion::getParentid, "l2", ChinaMcaRegion::getId)
            .eq("l1.level", "0")
            .orderBy(true, true, "l1.code", "l2.code", "l3.code"));
    logger.info(">>> total: {}", total);
    long pageSize = 200;
    logger.info(">>> pageSize: {}", pageSize);
    long pageCount = (total / pageSize) + (total % pageSize == 0 ? 0 : 1);
    logger.info(">>> pageCount: {}", pageCount);
    long pageNum = 8;
    logger.info(">>> pageNum: {}", pageNum);

    List<Map<String, Object>> resultPage = mapper.selectJoinMaps(new MPJLambdaWrapper<ChinaMcaRegion>("l1")
            .select("IF (( length( `l1`.`code` ) >= 6 ), `l1`.`code`, NULL ) AS `省级行政区编码`",
                    "`l1`.`name` AS `省/自治区/直辖市/特别行政区`",
                    "IF (( length( `l2`.`code` ) >= 6 ), `l2`.`code`, NULL ) AS `地级行政区编码`",
                    "`l2`.`name` AS `地级市/地区/自治州/盟`",
                    "IF (( length( `l3`.`code` ) >= 6 ), `l3`.`code`, NULL ) AS `县级行政区编码`",
                    "`l3`.`name` AS `市辖区/县级市/县/自治县/旗/自治旗/特区/林区`",
                    "( CASE WHEN ( ifnull( `l2`.`name`, '' ) = '' ) THEN " +
                            "concat( '中国/', `l1`.`name` ) " +
                            "WHEN ( ifnull( `l3`.`name`, '' ) = '' ) THEN " +
                            "concat( '中国/', `l1`.`name`, '/', `l2`.`name` ) ELSE concat( '中国/', `l1`.`name`, '/', `l2`.`name`, '/', `l3`.`name` ) " +
                            "END " +
                            ") AS `全路径名称`")
            .leftJoin(ChinaMcaRegion.class, "l2", ChinaMcaRegion::getParentid, "l1", ChinaMcaRegion::getId)
            .leftJoin(ChinaMcaRegion.class, "l3", ChinaMcaRegion::getParentid, "l2", ChinaMcaRegion::getId)
            .eq("l1.level", "0")
            .orderBy(true, true, "l1.code", "l2.code", "l3.code")
            .last("limit " + (pageNum - 1) * pageSize + "," + pageSize));

    logger.info(">>> resultPage.size(): {}", resultPage.size());
    for (Map<String, Object> row : resultPage) {
        logger.info(">>> {}", JSON.toJSONString(row, JSONWriter.Feature.WriteMapNullValue));
    }
    GetSqlSession.cleanSqlSessionManager();
    sqlSessionManager.commit();
    sqlSessionManager.close();
}

3.4、代码生成器

@Test
public void generatorTable() {
    MybatisPlusGenerator.generatorMybatisPlus("amap_region", "baidu_map");
    MybatisPlusGenerator.generatorMybatisPlusJoin("china_mca_region");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2407232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…