Introdução
Plus-MyBatis (abreviado MP) é uma ferramenta de aprimoramento do MyBatis , aprimorada não só pela mudança com base no MyBatis, para simplificar o desenvolvimento, aumentar a eficiência e a saúde.
Visão
Nossa visão é nos tornarmos o melhor parceiro da MyBatis, assim como o 1P, 2P no Contra , a combinação de base e amigos, o dobro da eficiência.
# Características
- Sem intrusão : apenas realce e não altere, a introdução disso não afetará o projeto existente, é tão suave como a seda
- Baixa perda : o CURD básico será injetado automaticamente na inicialização, o desempenho é basicamente sem perda, operação direta orientada a objetos
- Operações CRUD poderosas : mapeador geral integrado, serviço geral, apenas uma pequena quantidade de configuração pode realizar a maioria das operações CRUD de uma única tabela e um construtor de condição mais poderoso para atender a vários requisitos de uso
- Suporte a chamada de formulário Lambda : através de expressões Lambda, você pode facilmente escrever todos os tipos de condições de consulta, sem se preocupar em escrever campos errados
- Suporte a vários bancos de dados : suporte MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer2005, SQLServer e outros bancos de dados
- Suporta geração automática de chave primária : suporta até 4 estratégias de chave primária (incluindo uma sequência geradora de ID única distribuída), que pode ser configurada livremente, o que resolve perfeitamente o problema da chave primária
- Suporte a recarga automática de XML: o XML correspondente do mapeador oferece suporte a recarga automática, para operações simples de CRUD, pode até iniciar sem XML
- Suporte ao modo ActiveRecord : suporte a chamada de formulário ActiveRecord, classes de entidade precisam apenas herdar a classe Model para realizar operações CRUD poderosas
- Suporte a operações gerais globais personalizadas : suporte a injeção de método geral global (Escreva uma vez, use em qualquer lugar)
- Suporte para escape automático de palavras-chave : suporte para palavras-chave do banco de dados (pedido, chave ...) escape automático e palavras-chave podem ser personalizadas
- Gerador de código integrado : use o código ou o plug-in Maven para gerar rapidamente o mapeador, o modelo, o serviço, o código da camada do controlador, o mecanismo de modelo de suporte e mais configurações personalizadas para você usar
- Plug-in de paginação integrado: Com base na paginação física do MyBatis, os desenvolvedores não precisam se preocupar com operações específicas. Depois de configurar o plug-in, escrever paginação é equivalente à consulta de lista comum
- Plug-in de análise de desempenho integrado: a instrução Sql e seu tempo de execução podem ser produzidos. Recomenda-se habilitar essa função durante o desenvolvimento e o teste para detectar rapidamente consultas lentas
- Plug-in de interceptação global integrado : fornece análise inteligente e bloqueio de operações de exclusão e atualização de toda a tabela e também pode personalizar regras de interceptação para evitar operações incorretas
- Decapador de injeção Sql integrado : suporta a remoção de injeção Sql, prevenindo eficazmente ataques de injeção Sql
# Estrutura da moldura
O conteúdo acima vem do site oficial do Mybatis-Plus , o conteúdo é muito detalhado, pois proporciona muito percurso, então aprenda, a seguir é um registro do meu processo de aprendizagem.
Primeiro publique a dependência maven:
<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>
Aqui é onde adicionei as dependências que irei usar mais tarde, incluindo swagger, fastjson, jackson, freemarker, velocity, lombok, etc. Claro, o mais importante é mybatis-plus-boot-starter, a versão 3.0.3 usada aqui É relativamente novo. Depois de introduzi-lo, não há necessidade de adicionar a dependência mybatis.
Configure a fonte de dados para adicionar em 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
Adicionar classe de configuração da fonte de dados:
@Configuration
public class MybatisConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
return new DruidDataSource();
}
/**
* 分页拦截器
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
Use a função de geração de código de MP:
Crie a classe geradora de código:
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"});
}
}
Aqui estão alguns nomes de pacotes, e as coisas personalizadas podem ser modificadas de acordo com a situação.
Aqui eu fiz um modelo para a geração da classe do controlador e criei o controller.java.ftl em / resources / templates
código mostrado abaixo:
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();
}
}
Incluindo adições, exclusões, alterações e funções de consulta de paginação.
Inicie a classe MysqlGenerator:
Diretório de construção visível
O nome do arquivo em vermelho é o arquivo gerado automaticamente.
O arquivo do controlador é o seguinte:
@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();
}
}
Aqui está uma interface simples de adicionar, excluir, modificar e verificar. Os métodos invocados pelo serviço são todos MP integrados e outros métodos também podem ser configurados no modelo, se necessário.
A classe de entidade gerada será configurada com anotações relacionadas ao lombok.
@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> {
}
O chak do BaseMapper examina o código-fonte e você verá que ele já contém a maioria dos nossos métodos operacionais comumente usados.
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>
interface de serviço:
public interface IElensReportService extends IService<ElensReport> {
}
IService 接口也是MP 自带的接口同样内置了很多常用的方法:
服务实现类:
@Service
public class ElensReportServiceImpl extends ServiceImpl<ElensReportMapper, ElensReport> implements IElensReportService {
}
Além disso, você precisa adicionar a anotação @mapperScan à classe de inicialização do aplicativo para digitalizar e injetar o mapeador.
Eu configurei a bravata aqui.
@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();
}
}
Depois de iniciar a entrada do navegador de dados:
http:localhost:port/swagger-ui.html 可以看到生成的接口
Desta forma, o teste pode ser realizado diretamente.
Claro, se os próprios métodos do MP não podem atender às necessidades de negócios, podemos personalizar métodos em Serviço e escrever SQL na forma de Mybatis em Mapper.xml.