查看原文
其他

SpringBoot | 第九章:Mybatis-plus 的集成和使用

oKong ImportNew 2019-05-30

(点击上方公众号,可快速关注)


来源:oKong ,

blog.lqdev.cn/2018/07/21/springboot/chapter-nine/


前言


本章节开始介绍数据访问方面的相关知识点。对于后端开发者而言,和数据库打交道是每天都在进行的,所以一个好用的ORM框架是很有必要的。目前,绝大部分公司都选择MyBatis框架作为底层数据库持久化框架。


多说几句


看着现在Mybatis框架的大行其道,让我不禁想起,大学时期,当时还是hibernate的时代,现在基本已经忘记了。而当时,Mybatis的前身iBatis还在书中的某个章节出现过。当时大学老师的意思是:目前国内基本没有使用iBatis的公司,所以这一章节略过,略,过。。。现在对这个还记忆犹新,看着现在Mybatis大行其道,不禁令人唏嘘呀。


Mybatis-Plus


Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。


官方网站:http://mp.baomidou.com


简单来说,Mybatis-Plus是Mybatis的增强工具包,其简化了CRUD操作,提供了代码生成器,强大的条件构造器(这是我最喜欢的一个),同时内置了多个实用插件:标配的分页插件、性能分析插件、全局拦截插件等。使得开发过程中,基本的范式代码都一句话解决了,省去了很多重复的操作(程序猿存在的意义呢,说好的让我们搬砖呢!)。


SpringBoot集成


这里选用的mybatis-plus版本为:2.1.9,

mybatisplus-spring-boot-starter版本为:1.0.5。

对应Mybatis版本为:3.4.5


0. 这里以user表为例子,数据库为mysql


DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (

  `id` bigint(20) DEFAULT NULL COMMENT '唯一标示',

  `code` varchar(20) DEFAULT NULL COMMENT '编码',

  `name` varchar(64) DEFAULT NULL COMMENT '名称',

  `status` char(1) DEFAULT '1' COMMENT '状态 1启用 0 停用',

  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间'

) ENGINE=InnoDB DEFAULT CHARSET=utf8;


1. pom依赖:


<!--mybatis plus -->

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatisplus-spring-boot-starter</artifactId>

    <version>1.0.5</version>

</dependency>

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus</artifactId>

    <version>2.1.9</version>

</dependency>


2. 配置文件(当然也可以直接使用@Bean的方式进行或者通过application配置文件进行,详见官网)


spring-mybatis.xml

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

 

    <!--创建jdbc数据源 这里直接使用阿里的druid数据库连接池 -->

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">

        <property name="driverClassName" value="${mysql.driver}"/>

        <property name="url" value="${mysql.url}"/>

        <property name="username" value="${mysql.username}"/>

        <property name="password" value="${mysql.password}"/>

        <!-- 初始化连接大小 -->

        <property name="initialSize" value="0"/>

        <!-- 连接池最大使用连接数量 -->

        <property name="maxActive" value="20"/>

        <!-- 连接池最大空闲 -->

        <property name="maxIdle" value="20"/>

        <!-- 连接池最小空闲 -->

        <property name="minIdle" value="0"/>

        <!-- 获取连接最大等待时间 -->

        <property name="maxWait" value="60000"/>

 

        <property name="validationQuery" value="${validationQuery}"/>

        <property name="testOnBorrow" value="false"/>

        <property name="testOnReturn" value="false"/>

        <property name="testWhileIdle" value="true"/>

 

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->

        <property name="timeBetweenEvictionRunsMillis" value="60000"/>

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->

        <property name="minEvictableIdleTimeMillis" value="25200000"/>

 

        <!-- 打开removeAbandoned功能 -->

        <property name="removeAbandoned" value="true"/>

        <!-- 1800秒,也就是30分钟 -->

        <property name="removeAbandonedTimeout" value="1800"/>

        <!-- 关闭abanded连接时输出错误日志 -->

        <property name="logAbandoned" value="true"/>

 

        <!-- 监控数据库 -->

        <property name="filters" value="mergeStat"/>

    </bean>

 

    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->

    <bean id="transactionManager"

          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

    </bean>

 

    <!-- 可通过注解控制事务 -->

    <tx:annotation-driven transaction-manager="transactionManager"/>

 

    <!--mybatis-->

    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource"/>

        <!-- 自动扫描mapper.xml文件,支持通配符 -->

        <property name="mapperLocations" value="classpath:mapper/**/*.xml"/>

        <!-- 配置文件,比如参数配置(是否启动驼峰等)、插件配置等 -->

        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>

        <!-- 启用别名,这样就无需写全路径类名了,具体可自行查阅资料 -->

        <property name="typeAliasesPackage" value="cn.lqdev.learning.springboot.chapter9.biz.entity"/>

        <!-- MP 全局配置注入 -->

        <property name="globalConfig" ref="globalConfig"/>

    </bean>

    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">

        <!--

            AUTO->`0`("数据库ID自增")QW

             INPUT->`1`(用户输入ID")

            ID_WORKER->`2`("全局唯一ID")

            UUID->`3`("全局唯一ID")

        -->

        <property name="idType" value="3" />

    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

    <!-- 自动扫描包路径,接口自动注册为一个bean类 -->

        <property name="basePackage" value="cn.lqdev.learning.springboot.chapter9.biz.dao"/>

    </bean>

 

</beans>


3. 编写启动类,应用启动时自动加载配置xml文件


/**

 *  mybatisPlus 配置类,使其加载配置文件

 * @author oKong

 *

 */

@Configuration

@ImportResource(locations = {"classpath:/mybatis/spring-mybatis.xml"})

//@MapperScan("cn.lqdev.learning.springboot.chapter9.biz.dao")

//@EnableTransactionManagement

public class MybatisPlusConfig {

 

}


至此,mybatis-plus就配置完成了,接下来,利用代码生成器一次性创建所需的dao、mapper、通用CRUDservice类。


4. 编写代码生成器类


由于生成器依赖velocity模版引擎,故需要加入依赖:


<dependency>

    <groupId>org.apache.velocity</groupId>

    <artifactId>velocity-engine-core</artifactId>

    <version>2.0</version>

    <scope>test</scope>

</dependency>


MysqlGenerator,此类较长,相关配置可根据实际情况信息修改替换。


public class MysqlGenerator {

 

    private static final String PACKAGE_NAME = "cn.lqdev.learning.springboot.chapter9";

    private static final String MODULE_NAME = "biz";

    private static final String OUT_PATH = "D:\\develop\\code";

    private static final String AUTHOR = "oKong";

 

    private static final String DRIVER = "com.mysql.jdbc.Driver";

    private static final String URL = "jdbc:mysql://127.0.0.1:3306/learning?useUnicode=true&characterEncoding=UTF-8";

    private static final String USER_NAME = "root";

    private static final String PASSWORD = "123456";

 

    /**

     * <p>

     * MySQL 生成演示

     * </p>

     */

    public static void main(String[] args) {

        // 自定义需要填充的字段

        List<TableFill> tableFillList = new ArrayList<TableFill>();

 

        // 代码生成器

        AutoGenerator mpg = new AutoGenerator().setGlobalConfig(

                // 全局配置

                new GlobalConfig().setOutputDir(OUT_PATH)// 输出目录

                        .setFileOverride(true)// 是否覆盖文件

                        .setActiveRecord(true)// 开启 activeRecord 模式

                        .setEnableCache(false)// XML 二级缓存

                        .setBaseResultMap(false)// XML ResultMap

                        .setBaseColumnList(true)// XML columList

                        .setAuthor(AUTHOR)

                        // 自定义文件命名,注意 %s 会自动填充表实体属性!

                        .setXmlName("%sMapper").setMapperName("%sDao")

        // .setServiceName("MP%sService")

        // .setServiceImplName("%sServiceDiy")

        // .setControllerName("%sAction")

        ).setDataSource(

                // 数据源配置

                new DataSourceConfig().setDbType(DbType.MYSQL)// 数据库类型

                        .setTypeConvert(new MySqlTypeConvert() {

                            // 自定义数据库表字段类型转换【可选】

                            @Override

                            public DbColumnType processTypeConvert(String fieldType) {

                                System.out.println("转换类型:" + fieldType);

                                // if ( fieldType.toLowerCase().contains( "tinyint" ) ) {

                                // return DbColumnType.BOOLEAN;

                                // }

                                return super.processTypeConvert(fieldType);

                            }

                        }).setDriverName(DRIVER).setUsername(USER_NAME).setPassword(PASSWORD).setUrl(URL))

                .setStrategy(

                        // 策略配置

                        new StrategyConfig()

                                // .setCapitalMode(true)// 全局大写命名

                                .setDbColumnUnderline(true)// 全局下划线命名

                                // .setTablePrefix(new String[]{"unionpay_"})// 此处可以修改为您的表前缀

                                .setNaming(NamingStrategy.underline_to_camel)// 表名生成策略

                                // .setInclude(new String[] {"citycode_org"}) // 需要生成的表

                                // .setExclude(new String[]{"test"}) // 排除生成的表

                                // 自定义实体,公共字段

                                // .setSuperEntityColumns(new String[]{"test_id"})

                                .setTableFillList(tableFillList)

                                // 自定义实体父类

                                // .setSuperEntityClass("com.baomidou.demo.common.base.BsBaseEntity")

                                // // 自定义 mapper 父类

                                // .setSuperMapperClass("com.baomidou.demo.common.base.BsBaseMapper")

                                // // 自定义 service 父类

                                // .setSuperServiceClass("com.baomidou.demo.common.base.BsBaseService")

                                // // 自定义 service 实现类父类

                                // .setSuperServiceImplClass("com.baomidou.demo.common.base.BsBaseServiceImpl")

                                // 自定义 controller 父类

                                // .setSuperControllerClass("com.baomidou.demo.TestController")

                                // 【实体】是否生成字段常量(默认 false)

                                // public static final String ID = "test_id";

                                .setEntityColumnConstant(true)

                                // 【实体】是否为构建者模型(默认 false)

                                // public User setName(String name) {this.name = name; return this;}

                                .setEntityBuilderModel(true)

                                // 【实体】是否为lombok模型(默认 false)<a href="https://projectlombok.org/">document</a>

                                .setEntityLombokModel(true)

                // Boolean类型字段是否移除is前缀处理

                // .setEntityBooleanColumnRemoveIsPrefix(true)

                // .setRestControllerStyle(true)

                // .setControllerMappingHyphenStyle(true)

                ).setPackageInfo(

                        // 包配置

                        new PackageConfig().setModuleName(MODULE_NAME).setParent(PACKAGE_NAME)// 自定义包路径

                                .setController("controller")// 这里是控制器包名,默认 web

                                .setXml("mapper").setMapper("dao")

 

                ).setCfg(

                        // 注入自定义配置,可以在 VM 中使用 cfg.abc 设置的值

                        new InjectionConfig() {

                            @Override

                            public void initMap() {

                                Map<String, Object> map = new HashMap<String, Object>();

                                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");

                                this.setMap(map);

                            }

                        }.setFileOutConfigList(

                                Collections.<FileOutConfig>singletonList(new FileOutConfig("/templates/mapper.xml.vm") {

                                    // 自定义输出文件目录

                                    @Override

                                    public String outputFile(TableInfo tableInfo) {

                                        return OUT_PATH + "/xml/" + tableInfo.getEntityName() + "Mapper.xml";

                                    }

                                })))

                .setTemplate(

                        // 关闭默认 xml 生成,调整生成 至 根目录

                        new TemplateConfig().setXml(null)

        // 自定义模板配置,模板可以参考源码 /mybatis-plus/src/main/resources/template 使用 copy

        // 至您项目 src/main/resources/template 目录下,模板名称也可自定义如下配置:

        // .setController("...");

        // .setEntity("...");

        // .setMapper("...");

        // .setXml("...");

        // .setService("...");

        // .setServiceImpl("...");

        );

 

        // 执行生成

        mpg.execute();

    }

 

}


运行后即可,省了多少事!



简单实例


简单演示下增删改查及分页的使用。


使用分页时,mybatis-config.xml需要加入分页插件:PerformanceInterceptor


<plugins>

  <!-- 分页插件配置 -->

  <plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></plugin>

</plugins>


编写控制层


/**

 * 用户控制层 简单演示增删改查及分页

 * @author oKong

 *

 */

@RestController

@RequestMapping("/user")

public class UserController {

 

    @Autowired

    IUserService userService;

 

    @PostMapping("add")

    //正常业务时, 需要在user类里面进行事务控制,控制层一般不进行业务控制的。

    //@Transactional(rollbackFor = Exception.class)

    public Map<String,String> addUser(@Valid @RequestBody UserReq userReq){

 

        User user = new User();

        user.setCode(userReq.getCode());

        user.setName(userReq.getName());

        //由于设置了主键策略 id可不用赋值 会自动生成

        //user.setId(0L);

        userService.insert(user);

        Map<String,String> result = new HashMap<String,String>();

        result.put("respCode", "01");

        result.put("respMsg", "新增成功");

        //事务测试

        //System.out.println(1/0);

        return result;

    }

 

    @PostMapping("update")

    public Map<String,String> updateUser(@Valid @RequestBody UserReq userReq){

 

        if(userReq.getId() == null || "".equals(userReq.getId())) {

            throw new CommonException("0000", "更新时ID不能为空");

        }

        User user = new User();

        user.setCode(userReq.getCode());

        user.setName(userReq.getName());

        user.setId(Long.parseLong(userReq.getId()));        

        userService.updateById(user);

        Map<String,String> result = new HashMap<String,String>();

        result.put("respCode", "01");

        result.put("respMsg", "更新成功");

        return result;

    }

 

    @GetMapping("/get/{id}")

    public Map<String,Object> getUser(@PathVariable("id") String id){

        //查询

        User user = userService.selectById(id);

        if(user == null) {

            throw new CommonException("0001", "用户ID:" + id + ",未找到");

        }

        UserResp resp = UserResp.builder()

                .id(user.getId().toString())

                .code(user.getCode())

                .name(user.getName())

                .status(user.getStatus())

                .build();

        Map<String,Object> result = new HashMap<String,Object>();

        result.put("respCode", "01");

        result.put("respMsg", "成功");

        result.put("data", resp);

        return result;

    }

 

    @GetMapping("/page")

    public Map<String,Object> pageUser(int current, int size){

        //分页

        Page<User> page = new Page<>(current, size);

        Map<String,Object> result = new HashMap<String,Object>();

        result.put("respCode", "01");

        result.put("respMsg", "成功");

        result.put("data", userService.selectPage(page));

        return result;

    }       

}


启动应用后,使用postman依次访问对应的url地址即可。



数据库:



分页



由于配置了分析插件,控制台会输出执行的sql语句



其他的就不一一贴图了。


关于事务


正常情况下,只需要在服务层中加入@Transactional即可,事务相关的此章节不进行阐述,之后有机会会专门拿一个章节来说明下。


示例中为了方便,直接在控制层中加入了@Transactional进行事务测试,正式开发过程中,强烈建议在服务层进行业务控制,控制层一般上是进行逻辑判断的!


实体对象字段为枚举类


可能在实际开发中,大家会碰到,为了方便,一些类型、状态字段会编写成枚举类型,比如启用状态:DISABLE(“0”),ENABLE(“1”)。此时可通过配置typeHandlers进行自定义类型的处理,这里简单以EnumOrdinalTypeHandler(存储enum类里的序号值)进行示例,当然也可根据需要进行自定义处理器的编写,比如编写一个通用的枚举转换器等,其他相关知识点,大家可自行谷歌。


StatusEnums


public enum StatusEnum {

 

    DISABLE,

    ENABLE;

 

}


将user对象修改成枚举类型


/**

 * 状态1 启用 0 停用

 */

private StatusEnum status;


配置文件mybatis-config.xml加入处理类


<typeHandlers>

   <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"

     javaType="cn.lqdev.learning.springboot.chapter9.biz.entity.StatusEnum"/>

</typeHandlers>


之后就会自动进行转换了。大家可下载示例,进行实际操作下。



总结


本章节主要是对Mybatis-plus的集成和简单使用进行了说明,详细的用法,可到官网查看,官网有详细的使用指南,这里就不班门弄斧了。至此,对于一般的开发需求基本上都可以满足了。接下来的章节会重点讲解其他配套工具的使用,敬请期待!


最后


目前互联网上很多大佬都有springboot系列教程,如有雷同,请多多包涵了。本文是作者在电脑前一字一句敲的,每一步都是实践的。若文中有所错误之处,还望提出,谢谢。


系列



【关于投稿】


如果大家有原创好文投稿,请直接给公号发送留言。


① 留言格式:
【投稿】+《 文章标题》+ 文章链接

② 示例:
【投稿】《不要自称是程序员,我十多年的 IT 职场总结》:http://blog.jobbole.com/94148/

③ 最后请附上您的个人简介哈~



看完本文有收获?请转发分享给更多人

关注「ImportNew」,提升Java技能

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存