SpringBoot整合MyBatis-Plus进阶(自动填充,SQL注入)

SSpringBoot整合MyBatis-Plus进阶

  • 前期准备
  • 1.自动填充
    • 1.1 实体类修改
    • 1.2 自定义填充实现类
    • 1.3 测试
  • 2.SQL注入
    • 2.1 定义方法
    • 2.2 添加方法
    • 2.3 添加配置
    • 2.4 dao层添加方法
    • 2.5 service层添加方法
    • 2.6 controller层添加方法
    • 2.7 测试

前期准备

首先完成MyBatis-Plus基础整合。可以参考上一篇文章SpringBoot整合MyBatis-Plus

1.自动填充

1.1 实体类修改

需要自动填充的字段添加属性

@Data
@TableName("salesbill")
public class Salesbill {
    @TableId(value = "billId",type = IdType.AUTO)
    private long billId;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date date;
    @TableField("customerID")
    private long customerID;
    @TableField("categoryID")
    private long categoryID;
    private double price;
    private double grossWeight;
    private double tareWeight;
    private String remack;
    private long address;
    // 注意!这里需要标记为填充字段
    @TableField(fill = FieldFill.INSERT)
    private String createName;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    // 注意!这里需要标记为填充字段
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
}

1.2 自定义填充实现类

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
        this.strictInsertFill(metaObject, "createName", ()->"fgrapp", String.class);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "createName", ()->"fgrapp", String.class);
        this.strictUpdateFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
    }
}

1.3 测试

POST /Salesbill HTTP/1.1
Host: localhost:8000
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 3a10c096-052c-0ae5-7c44-08018aa14f00

{
    "date": "2020-11-21",
    "customerID": 2,
    "categoryID": 2,
    "price": 2,
    "grossWeight": 10,
    "tareWeight": 2,
    "remack": "测试",
    "address": 1
}
{
    "billId": 24,
    "date": "2020-11-21",
    "customerID": 2,
    "categoryID": 2,
    "price": 2,
    "grossWeight": 10,
    "tareWeight": 2,
    "remack": "测试",
    "address": 1,
    "createName": "fgrapp",
    "createTime": "2021-09-06 10:32:55"
}

根据返回结果可以看到,createName,createTime两个字段在没有传值的情况下填充了值

2.SQL注入

MyBatis-Plus默认是没有提供批量新增的方法,我们可以通过SQL注入的方式添加批量新增的方法。

2.1 定义方法

public class InsertBatch extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        final String sql = "";
        final String fieldSql = prepareFieldSql(tableInfo);
        final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
        final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, new NoKeyGenerator(), null, null);
    }

    private String prepareFieldSql(TableInfo tableInfo) {
        StringBuilder fieldSql = new StringBuilder();
        tableInfo.getFieldList().forEach(x -> fieldSql.append(x.getColumn()).append(","));
        fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
        fieldSql.insert(0, "(");
        fieldSql.append(")");
        return fieldSql.toString();
    }

    private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
        final StringBuilder valueSql = new StringBuilder();
        valueSql.append("");
        tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
        valueSql.delete(valueSql.length() - 1, valueSql.length());
        valueSql.append("");
        return valueSql.toString();
    }
}

2.2 添加方法

public class MyLogicSqlInjector extends DefaultSqlInjector {
    /**
     * 如果只需增加方法,保留MP自带方法
     * 可以super.getMethodList() 再add
     * @return
     */
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new InsertBatch());
        return methodList;
    }
}

2.3 添加配置

@Configuration
@MapperScan("com.fgrapp.learn.dao")
public class MybatisPlusConfig {
    /**
     * 新的分页插件,一缓和二缓遵循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);
    }
    
    /**
     * 自定义 SqlInjector
     * 里面包含自定义的全局方法
     */
    @Bean
    public MyLogicSqlInjector myLogicSqlInjector() {
        return new MyLogicSqlInjector();
    }
}

2.4 dao层添加方法

    /**
     * 批量插入
     * @param batchList 插入列表
     * @return 插入数量
     */
    int insertBatch(@Param("list") List<Salesbill> batchList);

2.5 service层添加方法

    public void insertBatch(List<Salesbill> list){
        baseMapper.insertBatch(list);
    }

2.6 controller层添加方法

    @PostMapping("batch")
    public void insertBatch(@RequestBody List<Salesbill> list){
        service.insertBatch(list);
    }

2.7 测试

POST /Salesbill/batch HTTP/1.1
Host: localhost:8000
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 552371ff-3342-1aa3-37e9-19f585f7b318

[
	{ 
		"date": "2020-11-21",
    "customerID": 2,
    "categoryID": 2,
    "price": 2,
    "grossWeight": 10,
    "tareWeight": 2,
    "remack": "测试",
    "address": 1
	
},
    {
    	"date": "2020-11-21",
    "customerID": 2,
    "categoryID": 2,
    "price": 2,
    "grossWeight": 10,
    "tareWeight": 2,
    "remack": "测试",
    "address": 1
    	
    }
    ]

我这里为了方便就把批量插入的方法直接写在了具体的Mapper接口内,这样的话,在多个业务类需要批量插入的情况下,就需要在多处添加批量插入的方法。
更进一步的方式可以选择定义一个项目内所有Mapper接口的父接口。如下所示:

public interface FgrMapper<T> extends BaseMapper<T> {
    /**
     * 批量插入
     * @param batchList 插入列表
     * @return 插入数量
     */
    int insertBatch(@Param("list") List<T> batchList);
}

这样的话,具体的业务类就继承这个接口,这样就可以令项目中所有Mapper接口都包含批量插入的方法。

public interface FileMapper extends FgrMapper<FileResponse> {
}

你可能感兴趣的:(SpringBoot,MySQL,java,sql,spring,boot,MyBatis-Plus,自动填充)