Browse Source

【升级】强化TableUniqueValue功能,可以增加逻辑删除的数据排除

fengshuonan 4 năm trước cách đây
mục cha
commit
d35c002cf9

+ 10 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/consts/CommonConstant.java

@ -52,6 +52,16 @@ public interface CommonConstant {
     */
    String VALUE = "value";
    /**
     * 默认标识状态的字段名称
     */
    String STATUS = "status";
    /**
     * 默认逻辑删除的状态值
     */
    String DEFAULT_LOGIC_DELETE_VALUE = "2";
    /**
     * 用户代理
     */

+ 4 - 10
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/context/system/SystemContext.java

@ -25,6 +25,7 @@ Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意
package cn.stylefeng.guns.core.context.system;
import cn.hutool.core.lang.Dict;
import cn.stylefeng.guns.core.pojo.base.validate.UniqueValidateParam;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import java.util.List;
@ -109,6 +110,7 @@ public interface SystemContext {
    /**
     * 根据字典类型获取字典的code值
     *
     * @param dictTypeCodes 字典类型编码值
     * @return 字典的code值
     * @author fengshuonan
@ -121,19 +123,11 @@ public interface SystemContext {
     * <p>
     * 一般用于唯一code校验
     *
     * @param tableName            表名
     * @param columnName           列名
     * @param value                值
     * @param excludeCurrentRecord 排除当前的值
     * @param id                   id字段的值
     * @param uniqueValidateParam 被校验的参数
     * @return true-是唯一的值,false-不是唯一的
     * @author fengshuonan
     * @date 2020/8/9 21:41
     */
    boolean tableUniValueFlag(String tableName,
                              String columnName,
                              String value,
                              Boolean excludeCurrentRecord,
                              Long id);
    boolean tableUniValueFlag(UniqueValidateParam uniqueValidateParam);
}

+ 56 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/pojo/base/validate/UniqueValidateParam.java

@ -0,0 +1,56 @@
package cn.stylefeng.guns.core.pojo.base.validate;
import lombok.Builder;
import lombok.Data;
/**
 * 校验参数时用的方法参数
 *
 * @author fengshuonan
 * @date 2020/8/17 21:43
 */
@Data
@Builder
public class UniqueValidateParam {
    /**
     * 表名称
     */
    String tableName;
    /**
     * 列名称
     */
    String columnName;
    /**
     * 被参数校验时候的字段的值
     */
    String value;
    /**
     * 校验时,是否排除当前的记录
     */
    Boolean excludeCurrentRecord;
    /**
     * 当前记录的主键id
     */
    Long id;
    /**
     * 排除所有被逻辑删除的记录的控制
     */
    Boolean excludeLogicDeleteItems;
    /**
     * 逻辑删除的字段名
     */
    String logicDeleteFieldName;
    /**
     * 逻辑删除的字段的值
     */
    String logicDeleteValue;
}

+ 21 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/validation/unique/TableUniqueValue.java

@ -28,6 +28,8 @@ import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
import static cn.stylefeng.guns.core.consts.CommonConstant.DEFAULT_LOGIC_DELETE_VALUE;
import static cn.stylefeng.guns.core.consts.CommonConstant.STATUS;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
@ -58,6 +60,25 @@ public @interface TableUniqueValue {
     */
    String columnName();
    /**
     * 是否开启状态校验,默认是关闭的
     * <p>
     * 关于为何开启状态校验:
     * <p>
     * 若项目中某个表包含控制逻辑删除的字段,我们在进行唯一值校验的时候要排除这种状态的记录,所以需要用到这个功能
     */
    boolean excludeLogicDeleteItems() default false;
    /**
     * 标识状态的字段名
     */
    String logicDeleteFieldName() default STATUS;
    /**
     * 逻辑删除的值(默认2是删除),用string是为了更通用
     */
    String logicDeleteValue() default DEFAULT_LOGIC_DELETE_VALUE;
    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RUNTIME)
    @Documented

+ 49 - 3
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/validation/unique/TableUniqueValueValidator.java

@ -28,6 +28,7 @@ import cn.stylefeng.guns.core.context.group.RequestGroupContext;
import cn.stylefeng.guns.core.context.group.RequestParamIdContext;
import cn.stylefeng.guns.core.context.system.SystemContextHolder;
import cn.stylefeng.guns.core.pojo.base.param.BaseParam;
import cn.stylefeng.guns.core.pojo.base.validate.UniqueValidateParam;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@ -44,10 +45,19 @@ public class TableUniqueValueValidator implements ConstraintValidator<TableUniqu
    private String columnName;
    private boolean excludeLogicDeleteItems;
    private String logicDeleteFieldName;
    private String logicDeleteValue;
    @Override
    public void initialize(TableUniqueValue constraintAnnotation) {
        this.tableName = constraintAnnotation.tableName();
        this.columnName = constraintAnnotation.columnName();
        this.excludeLogicDeleteItems = constraintAnnotation.excludeLogicDeleteItems();
        this.logicDeleteFieldName = constraintAnnotation.logicDeleteFieldName();
        this.logicDeleteValue = constraintAnnotation.logicDeleteValue();
    }
    @Override
@ -56,15 +66,51 @@ public class TableUniqueValueValidator implements ConstraintValidator<TableUniqu
        // 如果属于add group,则校验库中所有行
        if (BaseParam.add.class.equals(validateGroupClass)) {
            return SystemContextHolder.me().tableUniValueFlag(tableName, columnName, fieldValue, Boolean.FALSE, null);
            return SystemContextHolder.me().tableUniValueFlag(createAddParam(fieldValue));
        }
        // 如果属于edit group,校验时需要排除当前修改的这条记录
        if (BaseParam.edit.class.equals(validateGroupClass)) {
            return SystemContextHolder.me().tableUniValueFlag(tableName, columnName, fieldValue, Boolean.TRUE, RequestParamIdContext.get());
            return SystemContextHolder.me().tableUniValueFlag(createEditParam(fieldValue));
        }
        // 默认校验所有的行
        return SystemContextHolder.me().tableUniValueFlag(tableName, columnName, fieldValue, Boolean.FALSE, null);
        return SystemContextHolder.me().tableUniValueFlag(createAddParam(fieldValue));
    }
    /**
     * 创建校验新增的参数
     *
     * @author fengshuonan
     * @date 2020/8/17 21:55
     */
    private UniqueValidateParam createAddParam(String fieldValue) {
        return UniqueValidateParam.builder()
                .tableName(tableName)
                .columnName(columnName)
                .value(fieldValue)
                .excludeCurrentRecord(Boolean.FALSE)
                .excludeLogicDeleteItems(excludeLogicDeleteItems)
                .logicDeleteFieldName(logicDeleteFieldName)
                .logicDeleteValue(logicDeleteValue).build();
    }
    /**
     * 创建修改的参数校验
     *
     * @author fengshuonan
     * @date 2020/8/17 21:56
     */
    private UniqueValidateParam createEditParam(String fieldValue) {
        return UniqueValidateParam.builder()
                .tableName(tableName)
                .columnName(columnName)
                .value(fieldValue)
                .excludeCurrentRecord(Boolean.TRUE)
                .id(RequestParamIdContext.get())
                .excludeLogicDeleteItems(excludeLogicDeleteItems)
                .logicDeleteFieldName(logicDeleteFieldName)
                .logicDeleteValue(logicDeleteValue).build();
    }
}

+ 83 - 15
guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/core/context/SystemContextImpl.java

@ -26,8 +26,10 @@ package cn.stylefeng.guns.sys.core.context;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.stylefeng.guns.core.context.system.SystemContext;
import cn.stylefeng.guns.core.pojo.base.validate.UniqueValidateParam;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import cn.stylefeng.guns.sys.modular.auth.service.AuthService;
import cn.stylefeng.guns.sys.modular.dict.service.SysDictDataService;
@ -117,27 +119,93 @@ public class SystemContextImpl implements SystemContext {
    }
    @Override
    public boolean tableUniValueFlag(String tableName,
                                     String columnName,
                                     String value,
                                     Boolean excludeCurrentRecord,
                                     Long id) {
        int resultCount;
        // 如果排除当前这条记录
        if (excludeCurrentRecord) {
            if (id == null) {
                throw new IllegalArgumentException("当前table字段值唯一性校验失败,id为null");
            }
    public boolean tableUniValueFlag(UniqueValidateParam uniqueValidateParam) {
        int resultCount = 0;
        // 参数校验
        paramValidate(uniqueValidateParam);
        // 不排除当前记录,不排除逻辑删除的内容
        if (!uniqueValidateParam.getExcludeCurrentRecord()
                && !uniqueValidateParam.getExcludeLogicDeleteItems()) {
            resultCount = SqlRunner.db().selectCount(
                    "select count(*) from " + uniqueValidateParam.getTableName() + " where " + uniqueValidateParam.getColumnName() + " = {0}",
                    uniqueValidateParam.getValue());
        }
        // 不排除当前记录,排除逻辑删除的内容
        if (!uniqueValidateParam.getExcludeCurrentRecord()
                && uniqueValidateParam.getExcludeLogicDeleteItems()) {
            resultCount = SqlRunner.db().selectCount(
                    "select count(*) from " + tableName + " where " + columnName + " = {0} and id <> {1}", value, id);
        } else {
                    "select count(*) from " + uniqueValidateParam.getTableName()
                            + " where " + uniqueValidateParam.getColumnName() + " = {0} "
                            + " and "
                            + uniqueValidateParam.getLogicDeleteFieldName() + " <> " + uniqueValidateParam.getLogicDeleteValue(),
                    uniqueValidateParam.getValue());
        }
        // 排除当前记录,不排除逻辑删除的内容
        if (uniqueValidateParam.getExcludeCurrentRecord()
                && !uniqueValidateParam.getExcludeLogicDeleteItems()) {
            // id判空
            paramIdValidate(uniqueValidateParam);
            resultCount = SqlRunner.db().selectCount(
                    "select count(*) from " + uniqueValidateParam.getTableName()
                            + " where " + uniqueValidateParam.getColumnName() + " = {0} "
                            + " and id <> {1}",
                    uniqueValidateParam.getValue(), uniqueValidateParam.getId());
        }
        // 排除当前记录,排除逻辑删除的内容
        if (uniqueValidateParam.getExcludeCurrentRecord()
                && uniqueValidateParam.getExcludeLogicDeleteItems()) {
            // id判空
            paramIdValidate(uniqueValidateParam);
            resultCount = SqlRunner.db().selectCount(
                    "select count(*) from " + tableName + " where " + columnName + " = {0}", value);
                    "select count(*) from " + uniqueValidateParam.getTableName()
                            + " where " + uniqueValidateParam.getColumnName() + " = {0} "
                            + " and id <> {1} "
                            + " and "
                            + uniqueValidateParam.getLogicDeleteFieldName() + " <> " + uniqueValidateParam.getLogicDeleteValue(),
                    uniqueValidateParam.getValue(), uniqueValidateParam.getId());
        }
        // 如果大于0,代表不是唯一的当前校验的值
        return resultCount <= 0;
    }
    /**
     * 几个参数的为空校验
     *
     * @author fengshuonan
     * @date 2020/8/17 22:00
     */
    private void paramValidate(UniqueValidateParam uniqueValidateParam) {
        if (StrUtil.isBlank(uniqueValidateParam.getTableName())) {
            throw new IllegalArgumentException("当前table字段值唯一性校验失败,tableName为空");
        }
        if (StrUtil.isBlank(uniqueValidateParam.getColumnName())) {
            throw new IllegalArgumentException("当前table字段值唯一性校验失败,columnName为空");
        }
        if (StrUtil.isBlank(uniqueValidateParam.getValue())) {
            throw new IllegalArgumentException("当前table字段值唯一性校验失败,字段值value为空");
        }
    }
    /**
     * id参数的为空校验
     *
     * @author fengshuonan
     * @date 2020/8/17 22:00
     */
    private void paramIdValidate(UniqueValidateParam uniqueValidateParam) {
        if (uniqueValidateParam.getId() == null) {
            throw new IllegalArgumentException("当前table字段值唯一性校验失败,id为空");
        }
    }
}