3.基于SpringBoot3集成MybatisPlus及批量插入与分页查询及定制化代码生成器类

一. 集成MybatisPlus

1.1 依赖添加

implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3.1'
implementation 'com.baomidou:mybatis-plus-boot-starter-test:3.5.3.1'
implementation 'com.mysql:mysql-connector-j'
implementation 'com.alibaba:druid-spring-boot-3-starter:1.2.18'

// 只是在代码生成测试阶段用
testImplementation 'com.baomidou:mybatis-plus-generator:3.5.3.1'
implementation 'org.apache.velocity:velocity-engine-core:2.3'

1.2 配置

新建application.yml配置如下:

spring:
  jackson:
    # JSON 序列化不返回值为NULL的字段
    default-property-inclusion: NON_EMPTY
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    # druid 连接池管理
    druid:
      filter:
        config:
          # 开启密钥加密
          enabled: true
        stat:
          enabled: true
      # 配置默认的监控统计拦截的Filter
      # 不配置则监控页面中的SQL无法统计
      # stat - SQL监控配置
      # wall - SQL防火墙配置
      # slf4j - Druid日志配置
      filters: stat,wall,slf4j
      # 初始化连接池大小
      initial-size: 20
      # 连接池最大连接数
      max-active: 500
      # 每个连接上PSCache的最大值
      # 如果大于0,pool-prepared-statements自动开启
      max-pool-prepared-statement-per-connection-size: -1
      # 连接时最大等待时间(单位:毫秒)
      max-wait: 60000
      # 保持空闲连接不被关闭的最小生存时间(单位:毫秒)
      min-evictable-idle-time-millis: 25200000
      # 连接池最小空闲数
      min-idle: 0
      # 是否开启PSCache,即是否缓存preparedStatement(提升写入、查询效率)
      # 建议在支持游标的数据库开启,例如:Oracle
      pool-prepared-statements: false
      # 检测获取连接时的有效性
      # 开启后会影响性能
      test-on-borrow: false
      # 检测归还连接时的有效性
      # 开启后会影响性能
      test-on-return: false
      # 检测空闲连接
      # 不影响性能,建议开启
      test-while-idle: true
      # 检测关闭空闲连接的时间间隔(单位:毫秒)
      time-between-eviction-runs-millis: 60000
      # 检测连接有效的SQL
      # 为空则test-while-idle、test-on-borrow、test-on-return配置失效
      validation-query: SELECT 1
      # 检测连接是否有效的超时时间
      validation-query-timeout: 1
      stat-view-servlet:
        # 访问白名单
        allow: 127.0.0.1
        # 配置统计页面
        enabled: true
        # 访问密码
        login-password: suanfaxiaosheng
        # 访问用户名
        login-username: root
        # 允许重置监控数据
        reset-enable: true
      web-stat-filter:
        # 配置统计页面过滤
        enabled: true
        # 排除路径
        exclusions: .js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
        # 开启session统计
        session-stat-enable: true
        # session统计的最大个数
        session-stat-max-count: 100
        # 过滤路径
        url-pattern: /*
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  global-config:
    db-config:
      # 主键类型:自增
      id-type: auto
  # mapper xml文件路径
  mapper-locations: classpath:mapper/*.xml

在application-dev.yml配置错误打印SQL日志

spring:
  datasource:
    druid:
      url: jdbc:mysql://127.0.0.1:3306/cloud?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai
      username: cloud
      password: 123456

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl

1.3 新建user.sql脚本

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户ID',
  `username` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登录账号',
  `name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

1.4 新建代码生成工具类FastAutoGeneratorTest.java

/**
 * 根据数据表生成代码工具
 *
 * @author shenjian
 * @since 2023/8/16
 */
public class FastAutoGeneratorTest {


    public static void main(String[] args) {
        DataSourceConfig.Builder dataSourceConfig = new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/cloud?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai","cloud","123456");
        FastAutoGenerator.create(dataSourceConfig)
                // 全局配置
                .globalConfig((scanner, builder) -> builder.enableSwagger().author(scanner.apply("请输入作者名称?")))
                // 包配置
                .packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))
                // 策略配置
                .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                        .controllerBuilder().enableRestStyle().enableHyphenStyle()
                        .entityBuilder().enableLombok().enableTableFieldAnnotation().idType(IdType.INPUT).formatFileName("%sModel").build())
                .execute();
    }

    // 处理 all 情况
    protected static List<String> getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

运行main方法根据提示创建包即可, 生成代码后我们在根据需要修改即可

1.5 新建自动注入然后正常启动项目即可

resources目录下新建META-INF.spring目录,然后新建文件
org.springframework.boot.autoconfigure.AutoConfiguration.imports内容如下

com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure

至此,可以正常启动项目,集成MybatisPlus完毕,对于使用语法,可以去官网查询,后续我们将介绍特殊的一些用法

二. 批量插入

MybatisPlus自带的批量插入为伪批量插入,故此我们自定义批量插入方法

2.1 新建InsertBatchSqlInjector类

/**
 * 自定义批量插入 SQL 注入器,Mybatis-Plus自带的saveBatch为伪批量插入
 */
public class InsertBatchSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
    	// super.getMethodList() 保留 Mybatis Plus 自带的方法
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        // 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }
}

2.2 新建MybatisPlusConfig类

@Configuration
@MapperScan("online.shenjian.cloud.**.mapper")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页用
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    /**
     * 自定义批量插入 SQL 注入器
     */
    @Bean
    public InsertBatchSqlInjector insertBatchSqlInjector() {
        return new InsertBatchSqlInjector();
    }
}

2.3 新建MyBaseMapper接口

/**
 * MyBaseMapper支持高效批量插入
 */
public interface MyBaseMapper<T> extends BaseMapper<T> {

    /**
     * 批量插入
     *
     * @param batchList
     * @return
     */
    int insertBatchSomeColumn(@Param("list") List<T> batchList);
}

2.4 修改UserMapper继承接口

@Repository
public interface UserMapper extends MyBaseMapper<User> {

}

2.5 新建测试类UserTest类

@RunWith(SpringRunner.class)
@SpringBootTest(classes = CloudApplication.class)
public class UserTest {

    @Autowired
    private UserMapper userMapper;

    /**
     * 批量插入
     */
    @Test
    public void testBatchSave() {
        List<User> users = new ArrayList<>();

        User userOne = new User();
        userOne.setId(IdUtil.getSnowflakeNextIdStr());
        userOne.setName("沈健");
        userOne.setUsername("shenjian");

        User userTwo = new User();
        userTwo.setId(IdUtil.getSnowflakeNextIdStr());
        userTwo.setName("算法小生");
        userTwo.setUsername("sfxs");

        users.add(userOne);
        users.add(userTwo);
        userMapper.insertBatchSomeColumn(users);
    }
}

OK, 批量插入成功

三. 分页查询

3.1 新建UserPlusMapper.java

/**
 * 用户加强版Mapper
 */
@Repository
public interface UserPlusMapper extends BaseMapper<UserDto> {

    /**
     * 直接写SQL即可,即使关联查询的结果也会映射到DTO中
     */
    String querySql = "SELECT " +
            "               u.username, u.name " +
            "          FROM " +
            "               user AS u";
    String wrapperSql = "SELECT * FROM ( " + querySql + " ) AS q ${ew.customSqlSegment}";

    @Select(wrapperSql)
    Page<UserDto> page(IPage page, @Param("ew") Wrapper queryWrapper);
}

3.2 测试验证

/**
 * @author shenjian
 * @since 2023/10/12
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = CloudApplication.class)
public class UserTest {

    @Autowired
    private UserPlusMapper userPlusMapper;

    /**
     * 分页查询
     */
    @Test
    public void testPage() {
        IPage<UserDto> page = new Page<>(1, 10);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", "sfxs");
        Page<UserDto> resultPage = userPlusMapper.page(page, queryWrapper);
        Assert.assertNotNull(resultPage.getRecords());
        Assert.assertEquals(1, resultPage.getTotal());
    }
}

四. 定制化代码生成器类

往往遗留代码生成的类格式或者命名不符合要求,需要手工修改,但是当表很多时就比较头痛,所以我们自定义模板在进行代码生成

4.1 新建MyTemplateEngine.java类

里面大多实现直接拷贝自VelocityTemplateEngine.java, 只是增加了反射,修改包名,搜索修改地方即可找到两处位置

public class MyTemplateEngine extends AbstractTemplateEngine {

    /**
     * 批量输出 java xml 文件
     */
    @NotNull
    public AbstractTemplateEngine batchOutput() {
        try {
            ConfigBuilder config = this.getConfigBuilder();
            List<TableInfo> tableInfoList = config.getTableInfoList();
            tableInfoList.forEach(tableInfo -> {
                Map<String, Object> objectMap = this.getObjectMap(config, tableInfo);
                // 修改地方一:通过反射修改属性值,替换不需要的前缀
                Class<? extends  TableInfo> clazz = tableInfo.getClass();
                try {
                    Field name = clazz.getDeclaredField("name");
                    name.setAccessible(true);
                    name.set(tableInfo, tableInfo.getName().replaceFirst("tb_", ""));

                    Field entityName = clazz.getDeclaredField("entityName");
                    entityName.setAccessible(true);
                    entityName.set(tableInfo, tableInfo.getEntityName().replaceFirst("Tb", ""));

                    Field mapperName = clazz.getDeclaredField("mapperName");
                    mapperName.setAccessible(true);
                    mapperName.set(tableInfo, tableInfo.getMapperName().replaceFirst("Tb", ""));

                    Field xmlName = clazz.getDeclaredField("xmlName");
                    xmlName.setAccessible(true);
                    xmlName.set(tableInfo, tableInfo.getXmlName().replaceFirst("Tb", ""));

                    Field serviceName = clazz.getDeclaredField("serviceName");
                    serviceName.setAccessible(true);
                    serviceName.set(tableInfo, tableInfo.getServiceName().replaceFirst("ITb", ""));

                    Field serviceImplName = clazz.getDeclaredField("serviceImplName");
                    serviceImplName.setAccessible(true);
                    serviceImplName.set(tableInfo, tableInfo.getServiceImplName().replaceFirst("Tb", ""));

                    Field controllerName = clazz.getDeclaredField("controllerName");
                    controllerName.setAccessible(true);
                    controllerName.set(tableInfo, tableInfo.getControllerName().replaceFirst("Tb", ""));
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
                Optional.ofNullable(config.getInjectionConfig()).ifPresent(t -> {
                    // 添加自定义属性
                    t.beforeOutputFile(tableInfo, objectMap);
                    // 输出自定义文件
                    outputCustomFile(t.getCustomFiles(), tableInfo, objectMap);
                });
		// 修改地方二
                objectMap.put("entity", String.valueOf(objectMap.get("entity")).replaceFirst("Tb", ""));
                // entity
                outputEntity(tableInfo, objectMap);
                // mapper and xml
                outputMapper(tableInfo, objectMap);
                // service
                outputService(tableInfo, objectMap);
                // controller
                outputController(tableInfo, objectMap);
            });
        } catch (Exception e) {
            throw new RuntimeException("无法创建文件,请检查配置信息!", e);
        }
        return this;
    }

    private VelocityEngine velocityEngine;

    {
        try {
            Class.forName("org.apache.velocity.util.DuckType");
        } catch (ClassNotFoundException e) {
            // velocity1.x的生成格式错乱 https://github.com/baomidou/generator/issues/5
            LOGGER.warn("Velocity 1.x is outdated, please upgrade to 2.x or later.");
        }
    }

    @Override
    public @NotNull MyTemplateEngine init(@NotNull ConfigBuilder configBuilder) {
        if (null == velocityEngine) {
            Properties p = new Properties();
            p.setProperty(ConstVal.VM_LOAD_PATH_KEY, ConstVal.VM_LOAD_PATH_VALUE);
            p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, StringPool.EMPTY);
            p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
            p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
            p.setProperty("file.resource.loader.unicode", StringPool.TRUE);
            velocityEngine = new VelocityEngine(p);
        }
        return this;
    }


    @Override
    public void writer(@NotNull Map<String, Object> objectMap, @NotNull String templatePath, @NotNull File outputFile) throws Exception {
        Template template = velocityEngine.getTemplate(templatePath, ConstVal.UTF8);
        try (FileOutputStream fos = new FileOutputStream(outputFile);
             OutputStreamWriter ow = new OutputStreamWriter(fos, ConstVal.UTF8);
             BufferedWriter writer = new BufferedWriter(ow)) {
            template.merge(new VelocityContext(objectMap), writer);
        }
        LOGGER.debug("模板:" + templatePath + ";  文件:" + outputFile);
    }


    @Override
    public @NotNull String templateFilePath(@NotNull String filePath) {
        final String dotVm = ".vm";
        return filePath.endsWith(dotVm) ? filePath : filePath + dotVm;
    }
}

4.2 模板文件替换修改

IDEA全局搜索需要的下图文件,拷贝至resources/templates下,然后把里面的内容根据自己需求进行模板调整

4.3 代码生成类

之前是Swagger注解,我们调整为Springdoc注解,并对实体不额外添加后缀%s

public class FastAutoGeneratorTest {
    public static void main(String[] args) {
        DataSourceConfig.Builder dataSourceConfig = new DataSourceConfig.Builder("jdbc:mysql://XXXX:3306/yy_dev?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai","root","Gensci@123");
        FastAutoGenerator.create(dataSourceConfig)
                // 全局配置
                .globalConfig((scanner, builder) -> builder.enableSpringdoc().author(scanner.apply("请输入作者名称?")))
                // 包配置
                .packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))
                // 策略配置
                .templateEngine(new MyTemplateEngine())
                .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                        .controllerBuilder().enableRestStyle().enableHyphenStyle()
                        .entityBuilder().enableLombok().enableTableFieldAnnotation().idType(IdType.INPUT).formatFileName("%s").build())
                .execute();
    }

    // 处理 all 情况
    protected static List<String> getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

4.4 效果如图

五、I18N实现国际化

我们实践项目中的国际化需求案例DEMO,相关可变内容在配置文件中进行编写,当然这只是对后端国际化改造,如果涉及到前端,自行改造即可

5.1 新建资源文件

在resources目录下新建目录i18n, 然后
新建messages_en.properties文件

user.login.error=account or password error!

新建messages_zh_CN.properties文件

user.login.error=帐户或密码错误!

5.2 新建LocaleConfig.java文件

当然可以作为可变配置,当前设置为默认中文Locale.CHINA

@Configuration
public class LocaleConfig {

    @Bean
    public ResourceBundleMessageSource messageSource() {
        Locale.setDefault(Locale.CHINA);
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        //设置国际化文件存储路径和名称    i18n目录,messages文件名
        source.setBasenames("i18n/messages", "i18n/error", "i18n/message-system");
        //设置根据key如果没有获取到对应的文本信息,则返回key作为信息
        source.setUseCodeAsDefaultMessage(true);
        //设置字符编码
        source.setDefaultEncoding("UTF-8");
        return source;
    }

}

5.3 新建Utils.java文件

实现ApplicationContextAware接口,获取对应的提示信息

@Component
public class Utils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * 获取国际化信息
     *
     * @param key
     *            String :传入的国际化key
     * @param obj
     *            Object :传入的国际化参数
     * @return String 返回国际化信息
     */
    public static String getI18n(String key, Object[] obj) {
        // 目前我在Utils中写死中文,具体使用时请可配置化
        Locale locale = Locale.CHINA;
        String menuName = applicationContext.getMessage(key, obj, "", locale);
        return menuName;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (Utils.applicationContext == null) {
            Utils.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
}

5.4 改造登录接口

public ResponseVo login(UserDto userDto) {
        // 判断是否存在该用户
        if (user == null) {
            return ResponseVo.error(Utils.getI18n("user.login.error", null));
        }
}

5.5 启动项目验证

如果出现乱码情况,请将文件设置为UTF-8即可


欢迎关注公众号算法小生

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好!对于 MyBatis Plus 和 Spring Boot 的结合使用,可以提供更便捷的数据库操作和持久解决方案。 MyBatis Plus 是基于 MyBatis 的增强工具,它提供了很多常用的功能和特性,如代码生成器、分页插件、通用 CRUD 方法等。结合 Spring Boot,可以更方便地集成和配置。 要在 Spring Boot 中使用 MyBatis Plus,首先需要添加相关的依赖。您可以在 pom.xml 文件中添加以下依赖: ```xml <!-- MyBatis Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>最新版本号</version> </dependency> <!-- MyBatis Plus 代码生成器依赖(可选)--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>最新版本号</version> </dependency> ``` 然后,您可以在 application.properties 或 application.yml 文件中配置数据库连接信息和 MyBatis Plus 相关配置项,例如: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/db_example username: your_username password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: mapper-locations: classpath:mapper/**/*.xml ``` 接下来,您需要创建实体类、Mapper 接口以及对应的 XML 映射文件。MyBatis Plus 提供了注解和自动映射的功能,可以简开发过程。 最后,在需要使用数据库的地方,可以通过注入 Mapper 接口来进行数据库操作,例如: ```java @Autowired private UserMapper userMapper; public User getUserById(Long id) { return userMapper.selectById(id); } ``` 这就是简单介绍了 MyBatis Plus 和 Spring Boot 的结合使用。当然,还有很多其他的功能和特性可以探索,您可以根据具体需求进行配置和使用。希望对您有帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

算法小生Đ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值