• 使用@Constraint和自定义注解校验接口入参


    1.一般的参数校验怎么做的?

    我们在POST请求接受一个对象参数的时候可以使用 @Valid 去验证,然后通过统一异常处理,直接返回给前端,不用在业务代码中对这些参数进行校验。

    且约束的类型也有很多,比如:
    @Null 被注释的元素必须为 null
    @NotNull 被注释的元素必须不为 null
    @AssertTrue 被注释的元素必须为 true
    @AssertFalse 被注释的元素必须为 false
    @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @Size(max, min) 被注释的元素的大小必须在指定的范围内
    @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
    @Past 被注释的元素必须是一个过去的日期
    @Future 被注释的元素必须是一个将来的日期
    @Pattern(value) 被注释的元素必须符合指定的正则表达式
    上面注解实现的约束是spring官方给我们定义好的,好处就是可以直接拿来使用,坏处就是我们自己无法修改,当不满足需求时无法再使用。

    2.更加优雅的自定义注解验证接口入参方案

    更加优雅的检验方式,我们一般需要结合hibernate-validator包提供的@Constraint这个官方注解,首先我们需要定义了一个自定义注解,然后该注解的逻辑使用@Constraint这个注解帮我们处理
    首先引入依赖
    <dependency>
        <groupId>org.hibernate.validatorgroupId>
        <artifactId>hibernate-validatorartifactId>
    dependency>
    
    编写自己的自定义注解校验逻辑
    package com.example.demo.annotation;
    
    
    import javax.validation.Constraint;
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import javax.validation.Payload;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author ghl
     * @version 1.0
     * @date 2022/9/21 10:17
     * @description 测试实体
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
    @Constraint(validatedBy = ColumnLengthValid.ColumnLengthValidator.class)
    @Inherited
    public @interface ColumnLengthValid {
    
        int maxLength() default 0;
    
        String message() default "字段超长!";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        class ColumnLengthValidator implements ConstraintValidator<ColumnLengthValid, Object> {
    
            private int maxLength;
    
            @Override
            public void initialize(ColumnLengthValid constraintAnnotation) {
                maxLength = constraintAnnotation.maxLength();
            }
    
            @Override
            public boolean isValid(Object obj, ConstraintValidatorContext constraintValidatorContext) {
                return obj == null || obj.toString().length() <= maxLength;
            }
    
        }
    
    }
    
    
    使用方式
    package com.example.demo.dto;
    
    import com.example.demo.annotation.ColumnLengthValid;
    
    import javax.validation.constraints.NotBlank;
    import java.io.Serializable;
    
    /**
     * @author ghl
     * @version 1.0
     * @date 2022/9/21 10:17
     * @description 测试实体
     */
    public class Person implements Serializable {
    
        @ColumnLengthValid(maxLength = 5, message = "名称超长")
        @NotBlank(message = "名称不能为空")
        private String name;
    
        @NotBlank(message = "地址不能为空")
        private String address;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
    
    重写Validated验证List集合入参
    package com.example.demo.other;
    
    import javax.validation.Valid;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.List;
    import java.util.ListIterator;
    
    /**
     * @author ghl
     * @version 1.0.0
     * @description 重写Validated验证List集合入参
     * @date 2022-01-12 10:32:49
     */
    public class ValidList<E> implements List<E> {
    
        @Valid
        private List<E> list = new ArrayList<>();
    
        public List<E> getList() {
            return list;
        }
    
        public void setList(List<E> list) {
            this.list = list;
        }
    
        @Override
        public int size() {
            return list.size();
        }
    
        @Override
        public boolean isEmpty() {
            return list.isEmpty();
        }
    
        @Override
        public boolean contains(Object o) {
            return list.contains(o);
        }
    
        @Override
        public Iterator<E> iterator() {
            return list.iterator();
        }
    
        @Override
        public Object[] toArray() {
            return list.toArray();
        }
    
        @Override
        public <T> T[] toArray(T[] a) {
            return list.toArray(a);
        }
    
        @Override
        public boolean add(E e) {
            return list.add(e);
        }
    
        @Override
        public boolean remove(Object o) {
            return list.remove(o);
        }
    
        @Override
        public boolean containsAll(Collection<?> c) {
            return list.containsAll(c);
        }
    
        @Override
        public boolean addAll(Collection<? extends E> c) {
            return list.addAll(c);
        }
    
        @Override
        public boolean addAll(int index, Collection<? extends E> c) {
            return list.addAll(index, c);
        }
    
        @Override
        public boolean removeAll(Collection<?> c) {
            return list.removeAll(c);
        }
    
        @Override
        public boolean retainAll(Collection<?> c) {
            return list.retainAll(c);
        }
    
        @Override
        public void clear() {
            list.clear();
        }
    
        @Override
        public E get(int index) {
            return list.get(index);
        }
    
        @Override
        public E set(int index, E element) {
            return list.set(index, element);
        }
    
        @Override
        public void add(int index, E element) {
            list.add(index, element);
        }
    
        @Override
        public E remove(int index) {
            return list.remove(index);
        }
    
        @Override
        public int indexOf(Object o) {
            return list.indexOf(o);
        }
    
        @Override
        public int lastIndexOf(Object o) {
            return list.lastIndexOf(o);
        }
    
        @Override
        public ListIterator<E> listIterator() {
            return list.listIterator();
        }
    
        @Override
        public ListIterator<E> listIterator(int index) {
            return list.listIterator(index);
        }
    
        @Override
        public List<E> subList(int fromIndex, int toIndex) {
            return list.subList(fromIndex, toIndex);
        }
    }
    
    
    封装全局异常处理
    package com.example.demo.exception;
    
    import com.example.demo.core.ResultDTO;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.validation.BindException;
    import org.springframework.validation.FieldError;
    import org.springframework.web.HttpMediaTypeNotSupportedException;
    import org.springframework.web.HttpRequestMethodNotSupportedException;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseStatus;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import javax.validation.Path;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @author ghl
     * @version 1.0
     * @date 2022/9/21 12:14
     * @description 全局异常处理
     */
    @RestControllerAdvice
    public class BaseExceptionHandle {
    
        private static final Logger logger = LoggerFactory.getLogger(BaseExceptionHandle.class);
    
    
        /**
         * 统一处理请求参数校验(实体对象传参)
         *
         * @param e BindException
         * @return FebsResponse
         */
        @ExceptionHandler(BindException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public ResultDTO handleBindException(BindException e) {
            StringBuilder message = new StringBuilder();
            List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
            for (FieldError error : fieldErrors) {
                message.append(error.getField()).append(error.getDefaultMessage()).append(",");
            }
            message = new StringBuilder(message.substring(0, message.length() - 1));
            logger.error(message.toString());
            ResultDTO<String> resultDTO = new ResultDTO<String>();
            resultDTO.setSuccess(false);
            resultDTO.setMessage(e.getMessage());
            return resultDTO;
        }
    
        /**
         * 统一处理请求参数校验(普通传参)
         *
         * @param e ConstraintViolationException
         * @return FebsResponse
         */
        @ExceptionHandler(value = ConstraintViolationException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public ResultDTO handleConstraintViolationException(ConstraintViolationException e) {
            StringBuilder message = new StringBuilder();
            Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
            for (ConstraintViolation<?> violation : violations) {
                Path path = violation.getPropertyPath();
                String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), ".");
                message.append(pathArr[1]).append(violation.getMessage()).append(",");
            }
            message = new StringBuilder(message.substring(0, message.length() - 1));
            logger.error(message.toString());
    
            ResultDTO<String> resultDTO = new ResultDTO<String>();
            resultDTO.setSuccess(false);
            resultDTO.setMessage(message.toString());
            return resultDTO;
        }
    
        /**
         * 统一处理请求参数校验(json)
         *
         * @param e MethodArgumentNotValidException
         * @return FebsResponse
         */
        @ExceptionHandler(MethodArgumentNotValidException.class)
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public ResultDTO handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
            logger.error(e.getMessage(), e);
            StringBuilder message = new StringBuilder();
            for (FieldError error : e.getBindingResult().getFieldErrors()) {
                String defaultMessage = error.getDefaultMessage();
                if (!message.toString().contains(defaultMessage)) {
                    message.append(error.getDefaultMessage()).append("!");
                }
            }
            logger.error(message.toString());
            ResultDTO<String> resultDTO = new ResultDTO<String>();
            resultDTO.setSuccess(false);
            resultDTO.setMessage(message.toString());
            return resultDTO;
        }
    
        @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public ResultDTO handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
            String message = "该方法不支持" + StringUtils.substringBetween(e.getMessage(), "'", "'") + "媒体类型";
            logger.error(message);
    
            ResultDTO<String> resultDTO = new ResultDTO<String>();
            resultDTO.setSuccess(false);
            resultDTO.setMessage(message.toString());
            return resultDTO;
        }
    
        @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public ResultDTO handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
            String message = "该方法不支持" + StringUtils.substringBetween(e.getMessage(), "'", "'") + "请求方法";
            logger.error(message);
            ResultDTO<String> resultDTO = new ResultDTO<String>();
            resultDTO.setSuccess(false);
            resultDTO.setMessage(message.toString());
            return resultDTO;
        }
    
    
    }
    
    
    附上完整的源码

    码云地址

  • 相关阅读:
    强化学习基础(1)- 理论和算法
    ZEMAX | 在OpticStudio中通过几何光线追迹来模拟杨氏双缝干涉实验
    进博会期间,多地政府领导密集考察深兰科技
    代数曲线和曲面的拓扑研究
    Lucene数据写入流程
    NLP实践——以T5模型为例训练seq2seq模型
    更新电脑显卡驱动的操作方法有哪些?
    轻量级神经网络算法-SqueezeNet
    为什么RIP使用UDP,OSPF使用IP,而BGP使用TCP?为什么RIP周期性地和邻站交换路由信息而BGP却不这样做?
    Linux 网络编程
  • 原文地址:https://blog.csdn.net/a654540233/article/details/126973415