Spring-boot整合MybatisPlus自定义枚举转换器及各种CRUD扩展的简单使用

一、创建springboot项目

在这里插入图片描述

引入pom文件依赖

   <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter</artifactId>
   </dependency>
   <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.58</version>
   </dependency>
   <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
   </dependency>
   <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
   </dependency>
   <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger2</artifactId>
          <version>2.9.2</version>
   </dependency>
          <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
   <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger-ui</artifactId>
          <version>2.9.2</version>
  </dependency>
          <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
          <!--因为plus代码生成器需要一个模板引擎,velocity和freemarker任选一个,velocity是生成器中默认使用的,根据你的选择引依赖-->
   <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-boot-starter</artifactId>
         <version>3.4.3.4</version>
   </dependency>
       <!--mybatis-plus代码生成器-->
   <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-generator</artifactId>
         <version>3.5.1</version>
   </dependency>
       <!--velocity模板-->
   <dependency>
         <groupId>org.apache.velocity</groupId>
         <artifactId>velocity-engine-core</artifactId>
         <version>2.3</version>
   </dependency>
   <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <scope>runtime</scope>
   </dependency>
   <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

三、创建对应的mysql表

-- auto-generated definition
create table user
(
    id          int unsigned auto_increment
        primary key,
    name        varchar(10)   null,
    pwd         int(10)       null,
    gender      int(10)       null,
    create_time datetime      null,
    update_time datetime      null,
    version     int default 1 null,
    deleted     int default 0 null,
    content     json          null
);

注意:数据库id字段一定要是自增!

四、编写mybaitsplus自动生成类,生成对应文件

public class Code {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=ture&characterEncoding=utf-8", "root", "123456")
                .globalConfig(builder -> {
                            builder.outputDir(System.getProperty("user.dir") + "\\src\\main\\java")
                                    .author("fei")
                                    .disableOpenDir()//不打开资源管理器
                                    .dateType(DateType.TIME_PACK)
                                    .commentDate("yyyy-MM-dd")//注释时间
                                    .enableSwagger();
                            //.fileOverride();//覆盖已生成文件


                        }
                )
                .packageConfig(builder -> {
                            builder.parent("com.example.demo")
                                    .moduleName("sys")
                                    .entity("entity")
                                    .service("service")
                                    .serviceImpl("service.impl")
                                    .mapper("mapper")
                                    .xml("mapper")
                                    .controller("controller")
                                    .other("other")
                                    .pathInfo(Collections.singletonMap(OutputFile.mapperXml, System.getProperty("user.dir") + "\\src\\main\\resources\\mapper"));

                        }
                )
                .strategyConfig(Builder -> {
                    Builder.enableCapitalMode()
                            .enableSkipView()
                            .disableSqlFilter()
                            .addInclude("user")

                            .entityBuilder()
                            .enableLombok()
                            .enableTableFieldAnnotation()
                            .versionColumnName("version")
                            .versionPropertyName("version")//两种方式
                            .logicDeleteColumnName("deleted")
                            .logicDeletePropertyName("deleted")//两种方式
                            .naming(NamingStrategy.underline_to_camel)//表驼峰
                            .columnNaming(NamingStrategy.underline_to_camel)//列驼峰
                            .addTableFills(new Column("create_time", FieldFill.INSERT))
                            .addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE))//两种方式
                            .idType(IdType.AUTO)
                            .formatFileName("%sEntity")

                            .controllerBuilder()
                            .enableHyphenStyle()
                            .enableRestStyle()
                            .formatFileName("%sAction")

                            .serviceBuilder()
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImp")

                            .mapperBuilder()
                            .superClass(BaseMapper.class)
                            .enableMapperAnnotation()
                            .enableBaseResultMap()
                            .enableBaseColumnList()
                            .formatMapperFileName("%sDao")
                            .formatXmlFileName("%sXml");

                })
                //.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}

生成和自己添加的目录结构如图:
在这里插入图片描述

五、代码部分

  1. 配置类
package com.example.demo.sys.config;
import java.util.ArrayList;

/**
 * @program: demos
 * @description:
 * @author: fei
 * @create: 2021-11-21 12:21
 */

@Configuration
@EnableSwagger2
public class Myconfig {
    //乐观锁
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

    //配置了swagger的Docket的bean 实例
    @Bean
    public Docket docket0(Environment environment) {
        // 设置Swagger显示环境
        Profiles profiles = Profiles.of("dev", "test");

        // 通过 environment.acceptsProfiles(profiles) 判断是否在自己设定的环境当中
        boolean flag = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .groupName("A")
                .enable(flag)//不能在浏览器中访问swagger
                .select()
                // RequestHandlerSelectors 配置要扫描的包类
                // basePackage(): 指定要扫描的包
                // any(): 扫描全部
                // none(): 都不扫描
                // withClassAnnotation : 扫描类上的注解, 参数是一个注解的反射对象
                // 例如:withClassAnnotation(RestController.class) 只扫描类上有@RestController注解的生成文档
                // withMethodAnnotation: 扫描方法上的注解, 参数是一个注解的反射对象
                .apis(RequestHandlerSelectors.any())
                // paths(): 过滤路径
                .paths(PathSelectors.ant("/sys/**"))//只扫描访问路径有sys的api
                .build();
    }

    //配置了swagger的Docket 的 bean 实例
    @Bean
    public Docket docket(Environment environment) {
        // 设置Swagger显示环境
        Profiles profiles = Profiles.of("dev", "test");

        // 通过 environment.acceptsProfiles(profiles) 判断是否在自己设定的环境当中
        boolean flag = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .groupName("B")
                .enable(flag)//不能在浏览器中访问swagger
                .select()
                .apis(RequestHandlerSelectors.any())
                .build();
    }

    //配置 swagger 信息 = apiInfo
    private ApiInfo apiInfo() {
        //作者信息
        Contact contact = new Contact("fei", "http://blog.fei.com/", "2495057802@qq.com");
        return new ApiInfo("飞哥的SwaggerAPI文档",
                "API文档",
                "v1.0",
                "http://blog.fei.com/",
                contact,
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList()
        );
    }
}

乐观锁:1.先查询获取版本号version=1,再更新。
–线程一 update user set name =“yi” ,version=version+1 where id=2 and version=1
–线程二 线程抢先完成,这个时候version=2,会导致线程一修改失败 update user set name =“yi” ,version=version+1 where id=2 and version=1

2.controller层

@RestController
@RequestMapping("/sys/user")
public class UserAction {
    
    @Autowired
    UserService userServiceImp;

    @ResponseBody
    @ApiOperation("test控制类")
    @RequestMapping("/test")
    public List<UserEntity> test() {
        return userServiceImp.list();
    }
}


注意:
name方式注入根据上面描述,注入userServiceImpl这个Bean时失败,
(失败的原因就是实现接口,而springboot的事务默认是使用jdk的动态代理,即基于接口))。
在action层中注入的Bean是实现类,因此就会报错。

  1. 实体类
@Data
public class ser {
    private String id;
    private String name;
    private String nameEn;
    private String avatar;
}
package com.example.demo.sys.entity;
/**
 * <p>
 *
 * </p>
 *
 * @author fei
 * @since 2021-11-21
 */
@Getter
@Setter
@TableName(value = "user", autoResultMap = true)
@ApiModel(value = "UserEntity对象", description = "你好")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @TableField("name")
    @ApiModelProperty("用户名")
    private String name;
    @TableField("pwd")
    @ApiModelProperty("密码")
    private Integer pwd;
    @TableField(value = "gender", typeHandler = MyEnumTypeHanlder.class)
    //typeHandler = MyEnumTypeHanlder.class 局部属性方式转换器注入mybatis
    private GenderEnum gender;
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableField("version")
    @Version
    private Integer version;
    @TableField("deleted")
    @TableLogic
    private Integer deleted;
    @ApiModelProperty("联系方式")
    @TableField(value = "content", typeHandler = FastjsonTypeHandler.class)
    private List<ser> content;

    @Override
    public String toString() {
        return "UserEntity{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd=" + pwd +
                ", gender=" + gender +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                ", version=" + version +
                ", deleted=" + deleted +
                ", content=" + content +
                '}';
    }

}

typeHandler = FastjsonTypeHandler.class MybatisPlus 自带的json类型转换器,不过需要引入json相关依赖,不然不起作用。

4.枚举类

public interface BaseEnum {

    /**
     * 根据枚举值和type获取枚举
     */
    public static <T extends BaseEnum> T getEnum(Class<T> type, int value) {
        T[] objs = type.getEnumConstants();
        for (T em : objs) {
            if (em.getValue().equals(value)) {
                return em;
            }
        }
        return null;
    }


    /**
     * 获取枚举值
     *
     * @return
     */
    Integer getValue();

    /**
     * 获取枚举文本
     *
     * @return
     */
    String getLabel();
}

public enum GenderEnum implements BaseEnum {
    MALE(0, "男"),
    FEMALE(1, "女");


    @EnumValue
    private Integer value;

    private String label;

    GenderEnum(Integer value, String label) {
        this.label = label;
        this.value = value;
    }

    GenderEnum() {
    }

    @Override
    public Integer getValue() {
        return value;
    }

    @Override
    public String getLabel() {
        return label;
    }
}


5.填充策略代码

创建时间 . 修改时间! 这些个操作都是自动化完成的,我们不希望手动更新!

@Slf4j
@Component //把处理器加到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("Start insert fill.... ");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "deleted", Boolean.class, false);
    }

    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("Start update fill.... ");
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

5.mapper抽象类

@Mapper
@Repository
public interface UserDao extends BaseMapper<UserEntity> {
   
}

6.service层

public interface UserService extends IService<UserEntity> {
    List<UserEntity> userlist();
}
@Service
public class UserServiceImp extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    UserDao userDao;

    @Override
    public List<UserEntity> userlist() {
        return userDao.selectList(null);
    }
}

7.自定义枚举类型转换器


@MappedJdbcTypes(JdbcType.INTEGER)
@MappedTypes(GenderEnum.class)//限定作用范畴
public class MyEnumTypeHanlder extends BaseTypeHandler<GenderEnum> {
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, GenderEnum parameter, JdbcType jdbcType) throws SQLException {
        // 枚举code对应的数据库字段类型
        preparedStatement.setInt(i, parameter.getValue());
    }

    @Override
    public GenderEnum getNullableResult(ResultSet resultSet, String columName) throws SQLException {
        // 根据字段名获取枚举value值
        int code = resultSet.getInt(columName);
        // 获取枚举实体
        GenderEnum instance = BaseEnum.getEnum(GenderEnum.class, code);
        return instance;
    }

    @Override
    public GenderEnum getNullableResult(ResultSet resultSet, int columIndex) throws SQLException {
        int code = resultSet.getInt(columIndex);
        GenderEnum instance = BaseEnum.getEnum(GenderEnum.class, code);
        return instance;
    }

    @Override
    public GenderEnum getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }
}

8.启动类

@EnableTransactionManagement
@MapperScan("com\\example\\demo\\sys\\mapper")
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

注意: @MapperScan(“com\example\demo\sys\mapper”)扫描mapper接口,经常因为没加报错。

9.application配置

# 应用名称
spring.application.name=demo
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=ture&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 配置逻辑删除
#删除之后deleted数据库字段改为1
mybatis-plus.global-config.db-config.logic-delete-value=1
#没删deleted数据库字段为0;
mybatis-plus.global-config.db-config.logic-not-delete-value=0

mybatis-plus:
  #  type-handlers-package: com.example.demo.sys.typeHandler #包方式全局注入mybatis
  mapper-locations: classpath:mapper/*Xml.xml # 根据项目工程更改
  #  type-aliases-package: com.example.entity #根据项目工程更改 别名
  configuration:
    cache-enabled: false #2级缓存
    map-underscore-to-camel-case: true #开启驼峰
    auto-mapping-behavior: full #全都自动映射
  

server:
  port: 8080 #默认端口
spring:
  profiles:
    active: test #使用测试环境
---
server:
  port: 8082
spring:
  profiles: dev

---
server:
  port: 8083
spring:
  profiles: test

自动映射属性设置 ,默认是PARTIAL,只会自动映射没有定义嵌套结果集映射的结果集,不会自动映射一对多的结果集需要写 ,属性名和字段名一样也要写属性名和字段名不一样,有自动映射也要写。

MybatisPlus官方文档
MybatisPlus还有许多好用的东西,大家可以试试。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值