【Spring】自定义多时间参数校验注解

最近做参数判断的时候发现原有的参数校验无法判断多时间关系。

啥叫多时间关系?举个栗子

早餐时间必须在午餐时间之前,晚餐必须在午餐之前(你们要想成今天的早餐昨天的午餐我就没办法了...)

理想的办法是增加一个自定义校验注解,在注解里设定哪个时间参数要在我这个时间之前,哪个时间参数要在我的时间之后,一通研究之后发现实现接口ConstraintValidator只能拿到当前注解的属性或者类以及当前的注解信息。

最后说下处理的思路,我定义了两个注解,一个注解类,一个注解类属性,有大神有其它好的解决办法非常希望能留言提醒,提前感谢。

下面说下处理步骤:

1、定义类注解

2、定义属性注解

3、增加校验处理

另外:校验处理类实际是是spring调用对类注解进行处理,验证不通过返回false会调用类注解的message信息,但是我这里会有很多时间验证信息,所以我处理里面直接通过我的业务异常抛出验证不通过的信息,然后通过异常处理统一处理返回客户端。

贴代码:

类注解和校验处理类


/**
 * 自定义日期校验
 * @Author:mfkarj
 * @Date: 2020/3/30 16:07
 * @Version 1.0
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateTime.DateTimeHandle.class)
public @interface DateTime {

    // 提示内容
    String message() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    /**
     * 自定义验证处理类
     */
    class  DateTimeHandle implements ConstraintValidator<DateTime, Object> {
        private DateTime dateTime;

        @Override
        public void initialize(DateTime dateTime) {
            this.dateTime = dateTime;
        }
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            Class<?> valueClass = value.getClass();
            List<Field> fields =  getDateTimeAnnotationField(valueClass);
            BeanWrapper beanWrapper = new BeanWrapperImpl(value);
            for (Field field : fields) {
                //不为空的验证,为空的使用@NotBlank @NotNull等进行验证
                //当前属性的值
                Object currentDateValue = beanWrapper.getPropertyValue(field.getName());
                if(ObjectHelper.isNotEmpty(currentDateValue)){
                    DateTimeValidator dateTimeValidator =  field.getAnnotation(DateTimeValidator.class);
                    String format = dateTimeValidator.format();
                    String beforeField = dateTimeValidator.before();
                    String afterField = dateTimeValidator.after();
                    boolean identicalBefore = dateTimeValidator.identicalBefore();
                    boolean identicalAfter = dateTimeValidator.identicalAfter();

                    //验证时间格式
                    if(ObjectHelper.isNotEmpty(format)&&!dateFormatValidator(currentDateValue,format)) {
                        throw new BusinessException(ResultEnum.PARAM_ERROR.getCode(),dateTimeValidator.formatmessage());
                    }

                    //验证前面时间是否成立
                    if(ObjectHelper.isNotEmpty(beforeField)){
                        Object beforeDateValue = beanWrapper.getPropertyValue(beforeField);
                        if(!compareTime(beforeDateValue,currentDateValue,identicalBefore,format)){
                            throw new BusinessException(ResultEnum.PARAM_ERROR.getCode(),dateTimeValidator.beforemessage());
                        }
                    }

                    //验证后面时间是否成立
                    if(ObjectHelper.isNotEmpty(afterField)){
                        Object afterDateValue = beanWrapper.getPropertyValue(afterField);
                        if(!compareTime(currentDateValue,afterDateValue,identicalAfter,format)){
                            throw new BusinessException(ResultEnum.PARAM_ERROR.getCode(),dateTimeValidator.aftermessage());
                        }
                    }
                }
            }
            return true;
        }

        /**
         * 比较两个时间,afterTime是否在beforeTime之后
         * @param beforeTime 较早时间
         * @param afterTime 较晚时间
         * @param identical 是否允许相等
         * @param format ******时间格式,这里约定两个时间格式相同 ,如果时间格式不同需要分别取出两个时间的时间格式传进来再比较
         * @return 是否成立
         */
        private static boolean compareTime(Object beforeTime,Object afterTime,boolean identical,String format){

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            try {
                Date beforDate = simpleDateFormat.parse(beforeTime.toString());
                Date afterDate = simpleDateFormat.parse(afterTime.toString());
                int i = afterDate.compareTo(beforDate);
                switch(i){
                    case 0: return identical;
                    case 1: return Boolean.TRUE.booleanValue();
                    case -1: return Boolean.FALSE.booleanValue();
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return false;
        }


        /**
         * 时间格式校验
         * @param currentDateValue 验证的时间
         * @param format 时间格式
         * @return 是否成立
         */
        private boolean dateFormatValidator(Object currentDateValue,String format){
            if (currentDateValue.toString().length() != format.length()) {
                return false;
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            try {
                simpleDateFormat.parse(currentDateValue.toString());
            } catch (Exception e){
                return false;
            }
            return true;
        }

        /**
         * 获取有时间校验的字段
         * @param valueClass 获取字段提供的类
         * @return 是否成立
         */
        private List<Field> getDateTimeAnnotationField(Class<?> valueClass){
            Field[] fields = valueClass.getDeclaredFields();
            if(ObjectHelper.isNotEmpty(fields)){
                return  Arrays.stream(fields).filter(fls -> ObjectHelper.isNotEmpty(fls.getAnnotation(DateTimeValidator.class))).collect(toList());
            }
            return null;
        }
    }
}

 

属性标记类

/**
 * 自定义日期校验配置
 * @Author:mfkarj
 * @Date: 2020/3/30 16:07
 * @Version 1.0
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DateTimeValidator {

    /**
     * 日期格式错误错误描述
     * @return
     */
    String formatmessage() default "日期格式错误";

    /**
     * 日期先后错误错误描述
     * @return
     */
    String beforemessage() default "日期先后顺序不正确";

    /**
     * 日期先后错误错误描述
     * @return
     */
    String aftermessage() default "日期先后顺序不正确";

    /**
     * 验证日期格式
     * @return
     */
    String format() default "yyyyMMdd";

    /**
     * 验证当前日期值是否在该参数日期之前
     * @return
     */
    String before() default "";

    /**
     * 是否允许与before时间相同
     * @return
     */
    boolean identicalBefore() default true;

    /**
     * 验证当前日期值是否在该参数日期之后
     * @return
     */
    String after() default "";

    /**
     * 是否允许与after时间相同
     * @return
     */
    boolean identicalAfter() default true;
}

 

业务异常处理:

/**
 * 业务异常处理
 */
@Order(-2)
@ControllerAdvice
public class BaseExceptionHandler {

    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ResultVO handlerSellerException(BusinessException e) {
        return ResultVOUtil.error(e.getExceptionCode(), e.getExceptionMessage());
    }
}

 

最后是使用示范(代码临时改名,忽略变量名):

/**
 * 自定义日期校验配置模拟使用
 * @Author:mfkarj
 * @Date: 2020/3/30 16:07
 * @Version 1.0
 */
@DateTime
@Data
@Entity
@Table(name = "SYSTEM_POST")
public class Post extends BaseEntity{
     /**
     * 早餐时间
     */
    @NotEmpty(message = "早餐时间必填")
    @DateTimeValidator(format = "yyyyMMdd",after = "postName",formatmessage = "日期格式错误",aftermessage = "早餐时间应该早于午餐时间")
    @Column(name = "postNo", length = 20)
    private String postNo;

    /**
     * 午餐时间
     */
    @NotEmpty(message = "午餐时间必填")
    @DateTimeValidator(format = "yyyyMMdd",before = "postNo",after = "postMembersNum",
            formatmessage = "日期格式错误",beforemessage = "早餐时间应该早于午餐时间",aftermessage = "午餐时间应该早于晚餐时间")
    @Column(name = "postName", length = 200)
    private String postName;


    /**
     * 晚餐时间
     */
    @DateTimeValidator(format = "yyyyMMdd",before = "postName",formatmessage = "日期格式错误",beforemessage = "午餐时间应该早于早餐时间")
    @Column(name = "postMembersNum", length = 10)
    private int postMembersNum = 0;

    //.....
}

前端页面示范(只是示范,当然你也可以说我是用js做的效果):

 

使用上,个人觉得还是比较简单,如果一个注解能解决肯定是最好的~~~~

 

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用自定义注解校验请求参数。下面是一个示例: 首先,创建一个自定义注解类,例如 `@RequestParamValid`: ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface RequestParamValid { String value() default ""; } ``` 然后,在你的控制器方法中使用 `@RequestParamValid` 注解来标记需要校验参数: ```java @PostMapping("/example") public String exampleMethod(@RequestParam @RequestParamValid String parameter) { // ... } ``` 接下来,你可以创建一个切面来处理参数校验逻辑。切面可以使用 Spring 提供的 `HandlerMethodArgumentResolver` 接口来实现: ```java import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; @Component public class RequestParamValidResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestParamValid.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 在这里进行参数校验逻辑,可以使用各种方式来校验参数 // 例如,你可以使用 Hibernate Validator 进行校验 // 如果参数校验失败,可以抛出异常或返回错误信息 // 如果参数校验通过,可以返回参数的值 // 这里只是一个示例,假设参数不能为空 Object argumentValue = webRequest.getParameter(parameter.getParameterName()); if (argumentValue == null || argumentValue.toString().isEmpty()) { throw new IllegalArgumentException("参数校验失败"); } return argumentValue; } } ``` 最后,将切面注册到 Spring 容器中,以便生效。你可以在配置类中使用 `@EnableWebMvc` 注解来开启 Spring MVC 的相关功能: ```java import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { private final RequestParamValidResolver requestParamValidResolver; public WebConfig(RequestParamValidResolver requestParamValidResolver) { this.requestParamValidResolver = requestParamValidResolver; } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(requestParamValidResolver); } } ``` 现在,当请求进入控制器方法时,会自动触发参数校验逻辑。如果参数校验失败,将会抛出异常或返回错误信息。如果校验通过,控制器方法将会正常执行。 这只是一个简单的示例,你可以根据实际需求进行更复杂的参数校验逻辑。希望对你有帮助!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值