Mybatis-plus 自动装配

image.png

Mysql 分页

image.png

mybatis-plus 自动填充数据(默认开启)

image.png
image.png

多租户自动配置

image.png

  1. package com.np.pm.common.core.properties;
  2. import lombok.Getter;
  3. import lombok.Setter;
  4. import org.springframework.boot.context.properties.ConfigurationProperties;
  5. import org.springframework.cloud.context.config.annotation.RefreshScope;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. /**
  9. * 多租户配置
  10. *
  11. * @author tangxingpeng
  12. * @date 2021/1/26 23:32
  13. */
  14. @Setter
  15. @Getter
  16. @ConfigurationProperties(prefix = "pm.tenant")
  17. @RefreshScope
  18. public class TenantProperties {
  19. /**
  20. * 是否开启多租户
  21. */
  22. private Boolean enable = false;
  23. /**
  24. * 配置不进行多租户隔离的表名
  25. */
  26. private List<String> ignoreTables = new ArrayList<>();
  27. /**
  28. * 配置不进行多租户隔离的sql
  29. * 需要配置mapper的全路径如:com.central.user.mapper.SysUserMapper.findList
  30. */
  31. private List<String> ignoreSqls = new ArrayList<>();
  32. }

image.png

  1. package com.np.pm.common.datasource.configure;
  2. import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
  3. import com.np.pm.common.core.context.TenantContextHolder;
  4. import com.np.pm.common.core.properties.TenantProperties;
  5. import net.sf.jsqlparser.expression.Expression;
  6. import net.sf.jsqlparser.expression.NullValue;
  7. import net.sf.jsqlparser.expression.StringValue;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  10. import org.springframework.context.annotation.Bean;
  11. /**
  12. * 多租户自动配置
  13. *
  14. * @author tangxingpeng
  15. * @date 2021/1/27 14:17
  16. */
  17. @EnableConfigurationProperties(TenantProperties.class)
  18. public class TenantAutoConfigure {
  19. @Autowired
  20. private TenantProperties tenantProperties;
  21. @Bean
  22. public TenantLineHandler tenantHandler() {
  23. return new TenantLineHandler() {
  24. /**
  25. * 获取租户id
  26. */
  27. @Override
  28. public Expression getTenantId() {
  29. String tenant = TenantContextHolder.getTenant();
  30. if (tenant != null) {
  31. return new StringValue(TenantContextHolder.getTenant());
  32. }
  33. return new NullValue();
  34. }
  35. /**
  36. * 获取租户列名
  37. */
  38. @Override
  39. public String getTenantIdColumn() {
  40. return "tenant_id";
  41. }
  42. /**
  43. * 过滤不需要根据租户隔离的表
  44. * @param tableName 表名
  45. */
  46. @Override
  47. public boolean ignoreTable(String tableName) {
  48. return tenantProperties.getIgnoreTables().stream().anyMatch(
  49. (e) -> e.equalsIgnoreCase(tableName)
  50. );
  51. }
  52. };
  53. }
  54. }

update增强

项目的mybatis-plus默认的所有策略都是NOT_NULL(见pm-configure)

image.png

如果遇到向导更新null值时会忽略更新的问题

  1. 方式一(手动更新null):

         UpdateWrapper<T> tLambdaUpdateWrapper = new UpdateWrapper<T>();
         tLambdaUpdateWrapper.set("field", null);
         tLambdaUpdateWrapper.eq(idTableFeild.value(), id);
         return SqlHelper.retBool(baseMapper.update(null, tLambdaUpdateWrapper));
    
  2. 方式二(前端传全部数据,后端全更新):

官方文档:https://mp.baomidou.com/guide/sql-injector.html

public void updateEntity(SysMenu entity) {
    entity = this.beforeTreeSave(entity);
    baseMapper.updateAllById(entity);
}

image.png
image.png

package com.np.pm.common.datasource.inteceptor;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.np.pm.common.datasource.inteceptor.methods.UpdateAllById;

import java.util.List;

/**
 * @author tangxingpeng
 * @date 2021/8/3 10:14
 */
public class UpdateSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new UpdateAllById());
        return methodList;
    }

}
package com.np.pm.common.datasource.inteceptor.methods;

import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

import java.util.Objects;

import static java.util.stream.Collectors.joining;

/**
 * 根据 ID 更新所有字段
 *
 * @author tangxingpeng
 * @date 2021/8/3 10:19
 */
public class UpdateAllById extends AbstractMethod {

    public UpdateAllById() {
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.UPDATE_BY_ID;
        final String additional = optlockVersion(tableInfo) + tableInfo.getLogicDeleteSql(true, true);
        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(),
                sqlSet(tableInfo.isWithLogicDelete(), false, tableInfo, false, ENTITY, ENTITY_DOT),
                tableInfo.getKeyColumn(), ENTITY_DOT + tableInfo.getKeyProperty(), additional);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return addUpdateMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource);
    }


    /**
     * SQL 更新 set 语句
     *
     * @param logic  是否逻辑删除注入器
     * @param ew     是否存在 UpdateWrapper 条件
     * @param table  表信息
     * @param alias  别名
     * @param prefix 前缀
     * @return sql
     */
    @Override
    protected String sqlSet(boolean logic, boolean ew, TableInfo table, boolean judgeAliasNull, final String alias,
                            final String prefix) {
        String sqlScript = getAllSqlSet(table, logic, prefix);
        if (judgeAliasNull) {
            sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", alias), true);
        }
        if (ew) {
            sqlScript += NEWLINE;
            sqlScript += SqlScriptUtils.convertIf(SqlScriptUtils.unSafeParam(U_WRAPPER_SQL_SET),
                    String.format("%s != null and %s != null", WRAPPER, U_WRAPPER_SQL_SET), false);
        }
        sqlScript = SqlScriptUtils.convertSet(sqlScript);
        return sqlScript;
    }


    /**
     * 获取所有的 sql set 片段
     *
     * @param ignoreLogicDelFiled 是否过滤掉逻辑删除字段
     * @param prefix              前缀
     * @return sql 脚本片段
     */
    public String getAllSqlSet(TableInfo table, boolean ignoreLogicDelFiled, final String prefix) {
        final String newPrefix = prefix == null ? EMPTY : prefix;
        return table.getFieldList().stream()
                .filter(i -> {
                    if (ignoreLogicDelFiled) {
                        return !(table.isWithLogicDelete() && i.isLogicDelete());
                    }
                    return true;
                }).map(i -> i.getSqlSet(true, newPrefix)).filter(Objects::nonNull).collect(joining(NEWLINE));
    }

    @Override
    public String getMethod(SqlMethod sqlMethod) {
        return "updateAllById";
    }

}
package com.np.pm.common.springboot.starter.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;

/**
 * <p>mapper 基础接口</p>
 *
 * @Author: zhaojiwei
 * @Versions 1.0
 * @Date: 2021/7/26 下午12:48
 */
public interface PMBaseMapper<T> extends BaseMapper<T> {

    /**
     * 根据 ID 全部修改
     *
     * @param entity 实体对象
     */
    int updateAllById(@Param(Constants.ENTITY) T entity);

}
  1. 方式三(手写xml来更新复杂业务需求)

    数据权限(未完成)