纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 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-J | 9.3.0 |
HikariCP | 5.1.0 |
SnakeYaml | 2.4 |
Lombok | 1.18.38 |
Mybatis-Plus | 3.5.9 |
Mybatis-Plus Generator | 3.5.9 |
Mybatis-Plus-Join | 1.4.13 |
Spring-Core | 5.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需要的globalconfigGlobalConfig globalConfig = new GlobalConfig();//必须初始化dbconfig,否则会报空指针globalConfig.setDbConfig(new GlobalConfig.DbConfig());//此参数会自动生成实现baseMapper的基础方法映射globalConfig.setSqlInjector(new DefaultSqlInjector());//设置id生成器globalConfig.setIdentifierGenerator(DefaultIdentifierGenerator.getInstance());//设置超类mapperglobalConfig.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);}//构建sqlSessionFactorysqlSessionFactory = sqlSessionFactoryBuilder.build(configuration);}/*** 获取 MybatisPlus-Join SqlSessionFactory*/private static void setMybatisPlusJoinSqlSessionFactory() {SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//这是mybatis-plus的配置对象,对mybatis的Configuration进行增强MybatisConfiguration configuration = new MybatisConfiguration();//添加拦截器 MPJInterceptorconfiguration.addInterceptor(new MPJInterceptor());//构建mybatis-plus需要的globalconfigGlobalConfig globalConfig = new GlobalConfig();//必须初始化dbconfig,否则会报空指针globalConfig.setDbConfig(new GlobalConfig.DbConfig());//此参数会自动生成实现baseMapper的基础方法映射globalConfig.setSqlInjector(new MPJSqlInjector());//设置id生成器globalConfig.setIdentifierGenerator(DefaultIdentifierGenerator.getInstance());//设置超类mapperglobalConfig.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));//构建sqlSessionFactorysqlSessionFactory = 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%2B8username: rootpassword: CWCcwy12driverClassName: com.mysql.cj.jdbc.DrivermybatisPlusConfiguration:generator:# 作者author: wxhnyfy# 代码生成目录codeDir: src/main/java# xml文件生成目录xmlDir: src/main/resources/mapper# entity、mapper的父包名parentPackage: com.wxhnyfy# 是否生成mapper.xml文件generateMapperXml: true# 是否使用lombokenableLombok: 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@AllArgsConstructorpublic static class Jdbc {/*** 数据库连接地址*/private String url;/*** 用户名*/private String username;/*** 密码*/private String password;/*** 驱动类*/private String driverClassName;}@Setter@Getter@NoArgsConstructor@AllArgsConstructorpublic static class MybatisPlusConfiguration {/*** 代码生成信息*/private Generator generator;/*** mapper配置信息*/private MapperConfiguration mapperConfiguration;}@Setter@Getter@NoArgsConstructor@AllArgsConstructorpublic 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@AllArgsConstructorpublic 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");
}
相关文章:
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 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.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

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

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...

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

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有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看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问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. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

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

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...

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

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

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

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...

华为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模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...

力扣热题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…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...

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

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...