从零搭建开发脚手架 Spring Boot集成Mybatis-plus之二


接上篇
《从零搭建开发脚手架 Spring Boot集成Mybatis-plus之一》

分页查询

首先配置分页插件

    /**
     * 新的分页插件,一缓和二缓遵循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(false);
    }

普通分页

分页查询代码示例

    @GetMapping
    public Response pageAll(@RequestParam(required = false, defaultValue = "1") long current,
                            @RequestParam(required = false, defaultValue = "10") long size,
                            String roadName) {
    
    
        Page roadPage = new Page<>(current, size);
        LambdaQueryWrapper<Road> queryWrapper = new QueryWrapper().lambda();
        queryWrapper.like(StringUtils.isNotBlank(roadName), Road::getRoadName, roadName);
        Page pageList = roadService.page(roadPage, queryWrapper);
        return Response.ok(pageList);
    }

自动填充新建时间、更新时间、操作人等属性

  • 首先,实现元对象处理器接口:com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    
    @Override
    public void insertFill(MetaObject metaObject) {
    
     // Mapper调用insert操作时,进行如下操作
        log.info("start insert fill ...."); // 给entity的属性设置值
        this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
        this.strictInsertFill(metaObject, "operator", String.class, "张三");
    }
    @Override
    public void updateFill(MetaObject metaObject) {
    
    //  Mapper调用update操作时,进行如下操作
        log.info("start update fill ...."); // 给entity的属性设置值
        this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
        this.strictUpdateFill(metaObject, "operator", String.class, "张三");
    }
}

MetaObjectHandler提供的默认方法的策略均为:

  • 如果属性有值则不覆盖。
  • 如果填充值为null则不填充。
  • 其次,给相应实体类设置注解

注解:指定该属性在对应情况下必有值,如果无值则入库会是null

字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段

原理:判断注入的 insert 和 update 的 sql 脚本是否在对应情况下忽略掉字段的 if 标签生成

@Data
@EqualsAndHashCode(callSuper = false)
public class Stake implements Serializable {
    
    
    private Long roadId;
    private String stakeName;

    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String operator;

}

整体原理

  • 当发生insert或者updatesql脚本时候
  • 看下当前发生相关sql 的实体中相应字段的注解
    • 注解FieldFill.INSERT,即动态添加<if test="...">......</if>insert相关字段
    • 注解FieldFill.UPDATE,即动态添加<if test="...">......</if>update相关字段
    • 注解FieldFill.UPDATE,即动态添加<if test="...">......</if>insert和update相关字段

自定义字段类型

类型处理器,用于 JavaType 与 JdbcType 之间的转换,用于 PreparedStatement 设置参数值和从 ResultSet 或 CallableStatement 中取出一个值,本文讲解 mybaits-plus 内置常用类型处理器如何通过TableField注解快速注入到 mybatis 容器中。

如果报xml中五自定义handler的错误,把xml删除,或者在xml中也配置上

自动映射Json数据

@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    
    
    private Long id;

    /**
     * 注意!! 必须开启映射注解
     *
     * @TableName(autoResultMap = true)
     *
     * 以下两种类型处理器,二选一 也可以同时存在
     *
     * 注意!!选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    // @TableField(typeHandler = FastjsonTypeHandler.class)
    private OtherInfo otherInfo;

}

该注解对应了 XML 中写法为

<result column="other_info" jdbcType="VARCHAR" property="otherInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />

自动映射空间数据格式

可以看我的另一篇很详细 从零搭建开发脚手架 mybatis自定义字段类型 以Mysql空间数据存储为例

@Data
@EqualsAndHashCode(callSuper = false)
@TableName( autoResultMap = true)
public class ServiceArea implements Serializable {
    
    
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 经纬度    格式:X,Y
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private double[] location;

    @TableField(typeHandler = GeoPointTypeHandler.class)
    private GeoPoint coordinate;

}

自定义Controller模板

自定义代码模板

//指定自定义模板路径, 位置:/resources/templates/entity2.java.ftl(或者是.vm)
//注意不要带上.ftl(或者是.vm), 会根据使用的模板引擎自动识别
TemplateConfig templateConfig = new TemplateConfig()
    .setEntity("templates/entity2.java");

AutoGenerator mpg = new AutoGenerator();
//配置自定义模板
mpg.setTemplate(templateConfig);

自定义属性注入

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);
    }
};
AutoGenerator mpg = new AutoGenerator();
//配置自定义属性注入
mpg.setCfg(injectionConfig);
entity2.java.ftl
自定义属性注入abc=${cfg.abc}

entity2.java.vm
自定义属性注入abc=$!{cfg.abc}

框架自带的可用参数

Github AbstractTemplateEngine 类中方法 getObjectMap 返回 objectMap 的所有值都可用。

/**
     * 渲染对象 MAP 信息
     *
     * @param tableInfo 表信息对象
     * @return ignore
     */
    public Map<String, Object> getObjectMap(TableInfo tableInfo) {
    
    
        Map<String, Object> objectMap;
        ConfigBuilder config = getConfigBuilder();
        if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
    
    
            objectMap = CollectionUtils.newHashMapWithExpectedSize(33);
            objectMap.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
            objectMap.put("controllerMappingHyphen", StringUtils.camelToHyphen(tableInfo.getEntityPath()));
        } else {
    
    
            objectMap = CollectionUtils.newHashMapWithExpectedSize(31);
        }
        objectMap.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
        objectMap.put("config", config);
        objectMap.put("package", config.getPackageInfo());
        GlobalConfig globalConfig = config.getGlobalConfig();
        objectMap.put("author", globalConfig.getAuthor());
        objectMap.put("idType", globalConfig.getIdType() == null ? null : globalConfig.getIdType().toString());
        objectMap.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
        objectMap.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
        objectMap.put("activeRecord", globalConfig.isActiveRecord());
        objectMap.put("kotlin", globalConfig.isKotlin());
        objectMap.put("swagger2", globalConfig.isSwagger2());
        objectMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        objectMap.put("table", tableInfo);
        objectMap.put("enableCache", globalConfig.isEnableCache());
        objectMap.put("baseResultMap", globalConfig.isBaseResultMap());
        objectMap.put("baseColumnList", globalConfig.isBaseColumnList());
        objectMap.put("entity", tableInfo.getEntityName());
        objectMap.put("entitySerialVersionUID", config.getStrategyConfig().isEntitySerialVersionUID());
        objectMap.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
        objectMap.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
        objectMap.put("chainModel", config.getStrategyConfig().isChainModel());
        objectMap.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
        objectMap.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
        objectMap.put("superEntityClass", getSuperClassName(config.getStrategyConfig().getSuperEntityClass()));
        objectMap.put("superMapperClassPackage", config.getStrategyConfig().getSuperMapperClass());
        objectMap.put("superMapperClass", getSuperClassName(config.getStrategyConfig().getSuperMapperClass()));
        objectMap.put("superServiceClassPackage", config.getStrategyConfig().getSuperServiceClass());
        objectMap.put("superServiceClass", getSuperClassName(config.getStrategyConfig().getSuperServiceClass()));
        objectMap.put("superServiceImplClassPackage", config.getStrategyConfig().getSuperServiceImplClass());
        objectMap.put("superServiceImplClass", getSuperClassName(config.getStrategyConfig().getSuperServiceImplClass()));
        objectMap.put("superControllerClassPackage", verifyClassPacket(config.getStrategyConfig().getSuperControllerClass()));
        objectMap.put("superControllerClass", getSuperClassName(config.getStrategyConfig().getSuperControllerClass()));
        return Objects.isNull(config.getInjectionConfig()) ? objectMap : config.getInjectionConfig().prepareObjectMap(objectMap);
    }

模板修改

  • ${table.serviceName?substring(1)} - 删除首字母
  • ${table.serviceName?uncap_first} - 首字母大写变小写
package ${
    
    package.Controller};

import org.springframework.web.bind.annotation.RequestMapping;
import ${
    
    package.Entity}.${
    
    entity};
import ${
    
    package.Service}.${
    
    table.serviceName};
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
import com.laker.map.ext.framework.Response;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
<#if superControllerClassPackage??>
import ${
    
    superControllerClassPackage};
</#if>

/**
* <p>
    * ${table.comment!} 前端控制器
    * </p>
*
* @author ${author}
* @since ${date}
*/
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName?? && 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
    ${
    
    table.serviceName} ${
    
    table.serviceName?substring(1)?uncap_first};

    @GetMapping
    @ApiOperation(value = "${table.comment!}分页查询")
    public Response pageAll(@RequestParam(required = false, defaultValue = "1") long current,
                            @RequestParam(required = false, defaultValue = "10") long size) {
    
    
        Page roadPage = new Page<>(current, size);
        LambdaQueryWrapper<${
    
    table.entityName}> queryWrapper = new QueryWrapper().lambda();
        Page pageList = ${
    
    table.serviceName?substring(1)?uncap_first}.page(roadPage, queryWrapper);
        return Response.ok(pageList);
    }

    @PostMapping
    @ApiOperation(value = "新增或者更新${table.comment!}")
    public Response saveOrUpdate(${
    
    table.entityName} param) {
    
    
        return Response.ok(${
    
    table.serviceName?substring(1)?uncap_first}.saveOrUpdate(param));
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "根据id查询${table.comment!}")
    public Response get(@PathVariable Long id) {
    
    
        return Response.ok(${
    
    table.serviceName?substring(1)?uncap_first}.getById(id));
    }

    @DeleteMapping("/{id}")
    @ApiOperation(value = "根据id删除${table.comment!}")
    public Response delete(@PathVariable Long id) {
    
    
        return Response.ok(${
    
    table.serviceName?substring(1)?uncap_first}.removeById(id));
    }
}

猜你喜欢

转载自blog.csdn.net/abu935009066/article/details/114598146
今日推荐