十二、微服务进阶之Mybatis-Plus

十二、微服务进阶之Mybatis-Plus

功能介绍功能介绍

针对需要与数据库交互数据的业务引入此模块即可正常使用 Mybatis-Plus 的全部功能,无需继续单独配置,同之前的模块只是为了减少代码的冗余;Mybatis-Plus 官网地址: MyBatis-Plus 官方文档

代码展示

自定义数据库连接配置属性,MybatisValueConfiguration

@ConfigurationProperties(prefix = "spring.mybatis", ignoreInvalidFields = true)
@Data
public class MybatisValueConfiguration {
    /** * 需要使用的数据库名称 */
    private String database;
    /** * 数据库服务器地址 */
    private String url;
    /** * 数据库服务器用户名 */
    private String name;
    /** * 数据库服务器密码 */
    private String password;
    /** * 使用自定义编码为 utf-8;默认gbk */
    private boolean useUnicode = true;
    /** * 配置上个属性使用,指定编码集 */
    private String characterEncoding = "utf8";
    /** * 指定时区,也可配置成"GMT+8",但特殊字符'+'需要转换成十六进制'%2B',即="GMT%2B8" */
    private String serverTimezone = "Asia/Shanghai";
    /** * 高版本mysql需要指定是否使用ssl连接 */
    private boolean ssl = false;

    /** * 自行拼接数据库的地址 */
    public String getUrl() {
        StringBuilder address = new StringBuilder();
        address.append(this.url)
                .append(StrUtil.SLASH)
                .append(this.database)
                .append("?")
                .append(useUnicode ? "useUnicode=true&characterEncoding=" + this.characterEncoding + "&" : "")
                .append("serverTimezone=")
                .append(this.serverTimezone)
                .append("&")
                .append("useSSL=")
                .append(this.ssl);
        return address.toString();
    }
}

对应的配置属性

"spring.mybatis.character-encoding": "配置上个属性使用,指定编码集" 
"spring.mybatis.database": "需要使用的数据库名称" 
"spring.mybatis.server-timezone": "指定时区,也可配置成'GMT+8'" 
"spring.mybatis.ssl": "高版本mysql需要指定是否使用ssl连接" 
"spring.mybatis.url": "数据库服务器地址" 
"spring.mybatis.use-unicode": "使用自定义编码为 utf-8;默认gbk"

Mybatis-Plus 配置类,MybatisPlusConfiguration

@SpringBootConfiguration
@EnableConfigurationProperties(MybatisValueConfiguration.class)
public class MybatisPlusConfiguration {
    @Autowired
    private MybatisValueConfiguration mybatisValueConfiguration;

    /** * 重新注入自己的属性配置,依旧采用默认的连接方式 * 并指定优先使用自己的配置属性 */
    @Bean
    @Primary
    public DataSourceProperties dataSourceProperties(DataSourceProperties properties) {
        properties.setUrl(mybatisValueConfiguration.getUrl());
        properties.setUsername(mybatisValueConfiguration.getName());
        properties.setPassword(mybatisValueConfiguration.getPassword());
        return properties;
    }

    /** * 元对象字段自动填充控制器 */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MetaObjectHandler() {
            /** * # @TableField 注解使用 fill = INSERT_UPDATE or INSERT 会使用当前方法进行填充 */
            @Override
            public void insertFill(MetaObject metaObject) {
                if (metaObject.hasGetter(BaseEntity.CREATE_TIME) && metaObject.hasSetter(BaseEntity.CREATE_TIME)) {
                    setFieldValByName(BaseEntity.CREATE_TIME, DateUtil.now(), metaObject);
                }
                if (metaObject.hasGetter(BaseEntity.UPDATE_TIME) && metaObject.hasSetter(BaseEntity.UPDATE_TIME)) {
                    setFieldValByName(BaseEntity.UPDATE_TIME, DateUtil.now(), metaObject);
                }
            }

            /** 
             * # @TableField 注解使用 fill = INSERT_UPDATE or UPDATE 会使用当前方法进行填充 * 更新时字段名称有前缀 Constants.ENTITY 
             * * @see com.baomidou.mybatisplus.core.mapper.BaseMapper#updateById(java.lang.Object)
             */
            @Override
            public void updateFill(MetaObject metaObject) {
                if (metaObject.hasGetter(BaseEntity.UPDATE_TIME) && metaObject.hasSetter(BaseEntity.UPDATE_TIME)) {
                    setFieldValByName(Constants.ENTITY + StrUtil.DOT + BaseEntity.UPDATE_TIME, DateUtil.now(), metaObject);
                }
            }
        };
    }

    /** 
     * 新的分页插件,一缓和二缓遵循 mybatis 的规则 
     * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) 
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    /** * 自定义其他配置,预留接口 */
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> {
            configuration.setUseDeprecatedExecutor(Boolean.FALSE);
        };
    }
}

注:数据库的配置可以直接使用默认的 spring.datasource 配置参数进行配置;使用自定义的配置参数理由同 rabbit 模块

额外封装
@Data
public class BaseEntity implements Serializable {
    private static final long serialVersionUID = 2698577164797748107L;
    public static final String CREATE_USER = "create_user";
    public static final String CREATE_TIME = "create_time";
    public static final String UPDATE_USER = "update_user";
    public static final String UPDATE_TIME = "update_time";
    public static final String IS_DELETED = "is_deleted";
    /** * 创建人id */
    private Long createUser;
    /** * 创建时间 */
    @TableField(value = CREATE_TIME, fill = FieldFill.INSERT)
    private Date createTime;
    /** * 更新人id */
    private Long updateUser;
    /** * 更新时间 */
    @TableField(value = UPDATE_TIME, fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    /** * 逻辑删除字段,含有当前字段的实体调用删除接口时不会物理删除数据 * 默认值即 value = 0, delval = 1; 可不用配置 */
    @TableLogic(value = "0", delval = "1")
    private Boolean isDeleted;
}
常用依赖
<properties>
    <druid.version>1.1.22</druid.version>
    <jdbc.version>5.2.9.RELEASE</jdbc.version>
    <mysql.version>8.0.21</mysql.version>
    <mybatis-plus.version>3.4.2</mybatis-plus.version>
</properties>
<dependencies>
    <!-- 自定义配置参数提示 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
        <!-- 不传递依赖,只是一个工具依赖 -->
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${jdbc.version}</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>${mybatis-plus.version}</version>
    </dependency>
</dependencies>
补充说明

数据库配置类中使用了@Primary, 作用是什么?
答:spring 注入 bean 的方式有两种:byName/byType; 其中 ByName 即根据 bean 的名称(id)注入,使用@Resource(name=””)即可;但是大多数情况下都是按照 ByType 的方式注入的,包括使用 @Autowired 或者初始化配置类中的成员变量时都是采用 ByType;IOC 容器中同一个名称的 bean 只能有一个,但是同一种类型的 bean 可以有多个,这种规则导致在采用 ByType 注入 bean 时如果容器中有多个同类型的 bean 时无法精确使用哪一个,spring 就会报错;@Primary 作用就是在采用 ByType 注入 bean 时,如果存在多个同类型的优先使用当前注解标记的 bean;