文章目录
接上篇
《从零搭建开发脚手架 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
或者update
的sql脚本时候 - 看下当前发生相关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));
}
}