Spring boot introductory tutorial-integrating Mybatis-Plus

Introduction

Plus-MyBatis (abbreviated MP) is a  MyBatis  enhancement tools, enhanced not only change on the basis of MyBatis, to simplify development, increase efficiency and health.

Vision

Our vision is to be the best partner of MyBatis, just like   the 1P, 2P in Contra , the combination of base and friends, double the efficiency.

# Characteristics

  • No intrusion : only enhance and do not change, the introduction of it will not affect the existing project, it is as smooth as silk
  • Low loss : basic CURD will be automatically injected at startup, performance is basically no loss, direct object-oriented operation
  • Powerful CRUD operations : built-in general Mapper, general service, only a small amount of configuration can realize most of the CRUD operations of a single table, and a more powerful condition builder to meet various usage requirements
  • Support Lambda form call : through Lambda expressions, you can easily write all kinds of query conditions, no need to worry about writing wrong fields
  • Support multiple databases : support MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer2005, SQLServer and other databases
  • Supports automatic primary key generation : supports up to 4 primary key strategies (including a distributed unique ID generator-Sequence), which can be configured freely, which perfectly solves the primary key problem
  • Support XML hot reload : Mapper corresponding XML supports hot reload, for simple CRUD operations, it can even start without XML
  • Support ActiveRecord mode : Support ActiveRecord form call, entity classes only need to inherit Model class to perform powerful CRUD operations
  • Support custom global general operations : support global general method injection (Write once, use anywhere)
  • Support keyword automatic escaping : Support database keywords (order, key...) automatic escaping, and keywords can be customized
  • Built-in code generator : Use code or Maven plug-in to quickly generate Mapper, Model, Service, Controller layer code, support template engine, and more custom configurations for you to use
  • Built-in paging plug-in : Based on MyBatis physical paging, developers do not need to care about specific operations. After configuring the plug-in, writing paging is equivalent to ordinary List query
  • Built-in performance analysis plug-in : Sql statement and its execution time can be output. It is recommended to enable this function during development and testing to quickly detect slow queries
  • Built-in global interception plug-in : Provides intelligent analysis and blocking of delete and update operations of the entire table, and can also customize interception rules to prevent misoperations
  • Built-in Sql injection stripper : supports Sql injection stripping, effectively preventing Sql injection attacks

# Frame structure

framework

 The above content comes from the official website of Mybatis-Plus , the content is very detailed, since it provides a lot of traversal, then learn it, the following is a record of my learning process.

First post the maven dependency:

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.46</version>
        </dependency>
        
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
       
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>
        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.5.0</version>
        </dependency>

Here is where I added the dependencies that I will use later, including swagger, fastjson, jackson, freemarker, velocity, lombok, etc. Of course, the most important is mybatis-plus-boot-starter, the version 3.0.3 used here It's relatively new. After introducing it, there is no need to add mybatis dependency.

Configure the data source to add in application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/exchange?useUnicode=true&characterEncoding=gbk&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

Add data source configuration class:

@Configuration
public class MybatisConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    /**
     * 分页拦截器
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

}

Use the code generation function of MP:

Create the code generator class:

package com.elens.data.rbces.mybatis;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

/**
 * @BelongsProject: rbc-es
 * @BelongsPackage: com.elens.data.rbces.mybatis
 * @Author: xuweichao
 * @CreateTime: 2019-04-10 17:08
 * @Description: 代码生成
 */
public class MysqlGenerator {
    private static String projectPath = System.getProperty("user.dir");
    //父包路径
    private static String parentPackageName = "com.elens.data.rbces";
    //作者名字
    private static String authorName = "xuweichao";

    /**
     * 全局设置
     *
     * @return
     */
    public static GlobalConfig globalConfig() {

        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(projectPath + "/src/main/java")
                // 是否支持 AR
                .setActiveRecord(true)
                //设置作者名字
                .setAuthor(authorName)
                //文件覆盖(全新文件)
                .setFileOverride(true)
                //主键策略
                .setIdType(IdType.AUTO)
                //SQL 映射文件
                .setBaseResultMap(true)
                //SQL 片段
                .setBaseColumnList(true)
                .setSwagger2(true)
                .setEnableCache(false)
                .setOpen(false)
                //时间类型
                .setDateType(DateType.ONLY_DATE)
                .setEnableCache(false)
        ;
        return globalConfig;
    }

    /**
     * 数据源配置
     *
     * @return
     */
    public static DataSourceConfig dataSourceConfig() {
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        ResourceBundle rootResource = ResourceBundle.getBundle("application");
        String url = rootResource.getString("spring.datasource.url");
        String username = rootResource.getString("spring.datasource.username");
        String password = rootResource.getString("spring.datasource.password");
        String driverClassName = rootResource.getString("spring.datasource.driver-class-name");

        dataSourceConfig
                .setDbType(DbType.MYSQL)
                .setUrl(url)
                .setDriverName(driverClassName)
                .setUsername(username)
//                .setSchemaName("public")
                .setPassword(password);
        return dataSourceConfig;
    }

    /**
     * 包名相关配置
     *
     * @return
     */
    public static PackageConfig packageConfig(String moduleName) {
        PackageConfig packageConfig = new PackageConfig();
        //配置父包路径
        packageConfig.setParent(parentPackageName)
                .setMapper("mybatis.mapper")
                .setXml("mybatis.mapper")
                .setEntity("mybatis.entity")
                .setService("service")
                //会自动生成 impl,可以不设定
                .setServiceImpl("service.impl")
                .setController("controller");

        if (StringUtils.isNotEmpty(moduleName)) {
            //配置业务包路径
            packageConfig.setModuleName(moduleName);
        }

        return packageConfig;
    }

    /**
     * 配置模板
     *
     * @return
     */
    public static InjectionConfig injectionConfig(String moduleName) {
        InjectionConfig injectionConfig = new InjectionConfig() {
            //自定义属性注入:abc
            //在.ftl(或者是.vm)模板中,通过${cfg.abc}获取属性
            @Override
            public void initMap() {
//                Map<String, Object> map = new HashMap<>();
//                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
//                this.setMap(map);
            }
        };

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {

                if (StringUtils.isEmpty(moduleName)) {
                    // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                    return projectPath + "/src/main/java/com/elens/data/rbces/mybatis/mapper/"
                            + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                } else {
                    return projectPath + "/src/main/java/com/elens/data/rbces/mybatis/mapper/"
                            + moduleName + "/"
                            + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                }

            }
        });
        injectionConfig.setFileOutConfigList(focList);

        return injectionConfig;
    }

    /**
     * 生成策略配置
     *
     * @param tableName
     * @return
     */
    public static StrategyConfig strategyConfig(String moduleName, String... tableName) {
        StrategyConfig strategyConfig = new StrategyConfig();
        //设置命名规则  underline_to_camel 底线变驼峰
        strategyConfig.setNaming(NamingStrategy.underline_to_camel)
                //设置设置列命名  underline_to_camel 底线变驼峰
                .setColumnNaming(NamingStrategy.underline_to_camel)
                //设置继承类
                //.setSuperEntityClass("com.maoxs.pojo")
                //设置继承类
                //.setSuperControllerClass("com.maoxs.controller")
                //是否加入lombok
                .setEntityLombokModel(true)
                .setRestControllerStyle(true)
                .setControllerMappingHyphenStyle(true)
                //设置表名
                .setInclude(tableName)
                //设置超级列
//                .setSuperEntityColumns("id")
                //设置controller映射联字符
                .setControllerMappingHyphenStyle(true)
                //表的前缀
                .setTablePrefix(packageConfig(moduleName).getModuleName() + "_");
        return strategyConfig;
    }

    /**
     * 配置模板
     *
     * @return
     */
    public static TemplateConfig templateConfig() {
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        templateConfig.setController("/templates/controller.java");

        templateConfig.setXml(null);
        return templateConfig;
    }

    public static void Generator(String moduleName, String... tableName) {
        AutoGenerator mpg = new AutoGenerator()
                .setCfg(injectionConfig(moduleName))
                .setTemplate(templateConfig())
                .setGlobalConfig(globalConfig())
                .setDataSource(dataSourceConfig())
                .setPackageInfo(packageConfig(moduleName))
                .setStrategy(strategyConfig(moduleName, tableName))
//              选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!默认 Veloctiy
                .setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

    public static void main(String[] args) {
        Generator(null, new String[]{"elens_report"});
    }
}

Here are some package names, and the customized things can be modified according to the situation.

Here I made a template for the generation of the controller class, and created controller.java.ftl under /resources/templates

code show as below:

package ${package.Controller};


<#if restControllerStyle>
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.java.Log;
import org.springframework.web.bind.annotation.*;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import com.elens.data.rbces.vo.Wrapper;
import com.elens.data.rbces.vo.WrapMapper;

import com.elens.data.rbces.vo.QueryPageDto;

import ${package.Service}.${table.serviceName};
import ${package.Entity}.${entity};


/**
 *
 * @author ${author}
 * @since ${date}
 */
<#if restControllerStyle??>
@Log
@Api(value="${entity} 相关接口",tags ="${entity} 相关接口")
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName??>${package.ModuleName}</#if><#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
</#if>
    @Autowired
    public ${table.serviceName} ${table.entityPath}Service;


    /**
     * 分页查询数据
     *
     * @return
     */
    @ApiOperation(value = "分页查询", notes = "分页查询")
    @PostMapping("getPage")
    public Wrapper get${entity}List(@RequestBody QueryPageDto queryPageDto){
        log.info("获取的参数:===>>" + queryPageDto);

        Page<${entity}> page = new Page<>(queryPageDto.getPage(), queryPageDto.getSize());
        try{
            QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
        <#--queryWrapper.select("user_name", "user_company");-->
        <#--queryWrapper.like("user_name", "测试");-->
        <#--queryWrapper.ne("user_company", "");-->
            ${table.entityPath}Service.pageMaps(page, queryWrapper);

            }catch(Exception e){
                e.printStackTrace();
                return WrapMapper.error();
            }
            return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, page);
    }

    /**
     * 添加修改
     * @param ${table.entityPath}
     * @return
     */
    @ApiOperation(value = "添加或修改", notes = "根据id添加或修改")
    @PostMapping("addUpd")
    public Wrapper ${table.entityPath}AddUpd(${entity} ${table.entityPath}){
        log.info("获取的参数:===>>" + ${table.entityPath});
            try{
                ${table.entityPath}Service.saveOrUpdate(${table.entityPath});
            }catch(Exception e){
                 e.printStackTrace();
                return WrapMapper.error();
            }
            return WrapMapper.ok();
    }



    /**
     * 根据id删除对象
     * @param id  实体ID
     */
    @ApiOperation(value = "删除", notes = "根据id删除")
    @GetMapping("del/{id}")
    public Wrapper ${table.entityPath}Delete(@PathVariable int id){
        log.info("获取的参数:===>>" + id);
            try{
                ${table.entityPath}Service.removeById(id);
            }catch(Exception e){
                e.printStackTrace();
                return WrapMapper.error();
            }
            return WrapMapper.ok();
    }

}

Including additions, deletions, changes, and paging query functions.

Start the MysqlGenerator class:

Visible build directory

The file name in red is the automatically generated file.

The controller file is as follows:

@Log
@Api(value="ElensReport 相关接口",tags ="ElensReport 相关接口")
@RestController
@RequestMapping("elens-report")
public class ElensReportController {
    @Autowired
    public IElensReportService elensReportService;


    /**
     * 分页查询数据
     *
     * @return
     */
    @ApiOperation(value = "分页查询", notes = "分页查询")
    @PostMapping("getPage")
    public Wrapper getElensReportList(@RequestBody QueryPageDto queryPageDto){
        log.info("获取的参数:===>>" + queryPageDto);

        Page<ElensReport> page = new Page<>(queryPageDto.getPage(), queryPageDto.getSize());
        try{
            QueryWrapper<ElensReport> queryWrapper = new QueryWrapper<>();
            elensReportService.pageMaps(page, queryWrapper);

            }catch(Exception e){
                e.printStackTrace();
                return WrapMapper.error();
            }
            return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, page);
    }

    /**
     * 添加修改
     * @param elensReport
     * @return
     */
    @ApiOperation(value = "添加或修改", notes = "根据id添加或修改")
    @PostMapping("addUpd")
    public Wrapper elensReportAddUpd(ElensReport elensReport){
        log.info("获取的参数:===>>" + elensReport);
            try{
                elensReportService.saveOrUpdate(elensReport);
            }catch(Exception e){
                 e.printStackTrace();
                return WrapMapper.error();
            }
            return WrapMapper.ok();
    }



    /**
     * 根据id删除对象
     * @param id  实体ID
     */
    @ApiOperation(value = "删除", notes = "根据id删除")
    @GetMapping("del/{id}")
    public Wrapper elensReportDelete(@PathVariable int id){
        log.info("获取的参数:===>>" + id);
            try{
                elensReportService.removeById(id);
            }catch(Exception e){
                e.printStackTrace();
                return WrapMapper.error();
            }
            return WrapMapper.ok();
    }

}

Here is a simple add, delete, modify, and check interface. The methods invoked by the service are all built in MP, and other methods can be configured into the template if needed.

The generated entity class will be configured with lombok related annotations.

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="ElensReport对象", description="")
public class ElensReport extends Model<ElensReport> {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "报告名称")
    private String reportName;

    @ApiModelProperty(value = "标题")
    private String reportTitle;

    @ApiModelProperty(value = "报告内容")
    private String reportContent;

    @ApiModelProperty(value = "修改时间")
    private Date updateTime;

    private String photo;

    private String perId;

    private Date createTime;


    @Override
    protected Serializable pkVal() {
        return this.id;
    }

}
//Mapper 接口 集成BaseMapper
public interface ElensReportMapper extends BaseMapper<ElensReport> {

}

BaseMapper chak looks at the source code and you will see that it already contains most of our commonly used operating methods.

mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.elens.data.rbces.mybatis.mapper.ElensReportMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.elens.data.rbces.mybatis.entity.ElensReport">
        <id column="id" property="id" />
        <result column="report_name" property="reportName" />
        <result column="report_title" property="reportTitle" />
        <result column="report_content" property="reportContent" />
        <result column="update_time" property="updateTime" />
        <result column="photo" property="photo" />
        <result column="per_id" property="perId" />
        <result column="create_time" property="createTime" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, report_name, report_title, report_content, update_time, photo, per_id, create_time
    </sql>

</mapper>

service interface:

public interface IElensReportService extends IService<ElensReport> {

}
IService 接口也是MP 自带的接口同样内置了很多常用的方法:

 

服务实现类:
@Service
public class ElensReportServiceImpl extends ServiceImpl<ElensReportMapper, ElensReport> implements IElensReportService {

}

In addition, you need to add the annotation @mapperScan to the Application startup class to scan and inject the mapper.

I have configured swagger here.

@EnableSwagger2
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket apiDoc() {
        return docket();
    }

    private Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2).select()
//                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))//这里采用包含注解的方式来确定要显示的接口
//                .apis(RequestHandlerSelectors.basePackage("com.elens.data.oauth.manager.controller"))    //这里采用包扫描的方式来确定要显示的接口
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build()
                .ignoredParameterTypes(Errors.class)
                .apiInfo(apiInfo());

    }

   private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Swagger2 api文档")
                .description("Swagger2 api文档")
                .version("1.0.0")
                .build();

    }
}

After starting the data browser input:

http:localhost:port/swagger-ui.html 可以看到生成的接口




In this way, the test can be performed directly.

Of course, if MP's own methods cannot meet business needs, we can customize the methods in Service and write SQL in the way of Mybatis in Mapper.xml.

Guess you like

Origin blog.csdn.net/qq_27828675/article/details/89307878