• springboot参数校验的三种方式


    springboot参数校验的三种方式

    springboot对请求参数拦截校验,业务代码可保持纯净。

    1.JSR303校验

    ①导包
     <dependency>
       <groupId>org.springframework.bootgroupId>
       <artifactId>spring-boot-starter-validationartifactId>
     dependency>
    
    • 1
    • 2
    • 3
    • 4
    ②在要校验的字段上加上校验注解

    例如:(其他注解校验会泽参考另一篇博客JSR303参数校验与commons-lang3的常见验证

    @Max(value = 3,message = "超过最大值3")
    private Integer appLevel;
    
    • 1
    • 2
    ③在请求参数处要加@Valid
     public RespResult<Void> add(@RequestBody @Valid AppInfoDTO appInfoDTO){
            return idsAppInfoService.add(appInfoDTO);
        }
    
    • 1
    • 2
    • 3
    ④自定义异常捕获

    JSR303抛出的异常是MethodArgumentNotValidException,为了格式复合代码风格,自己定义抛出的异常格式
    RespResult是自己项目的公共返回类(略)

    @RestControllerAdvice
    @Slf4j
    public class IDAASExceptionAdvice {
    
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public RespResult handleError(MethodArgumentNotValidException e){
            log.warn("Method Argument Not Valid",e);
            BindingResult bindingResult = e.getBindingResult();
            FieldError fieldError = bindingResult.getFieldError();
            String message = String.format("%s",fieldError.getDefaultMessage());
            return RespResult.error(ComErrorCode.PARAM_VALID_ERROR.getCode(),message);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.AOP切面

    采用一个切面来且所有controller,这样就可以拿到请求参数,做校验,这里没有定义注解,直接且所有controller

    import com.alibaba.fastjson.JSON;
    import com.atpingan.sunflower.commonutils.exception.IdaasException;
    import com.atpingan.sunflower.commonutils.pingan.enums.ComErrorCode;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    import java.util.Map;
    
    @Slf4j
    @Aspect
    @Component
    public class ReqParamValidateAop {
    
        @Pointcut("execution(* com.atpingan.sunflower.idaas.controller..*.*(..))")
        public void executeControllerAop(){
    
        }
        @Around("executeControllerAop()")
        public Object doExecuteControllerAop(ProceedingJoinPoint joinPoint) throws Throwable {
            Map<String,Object> map = JSON.parseObject(JSON.toJSONString(joinPoint.getArgs()[0]),Map.class);
            System.out.println(map);
            Integer appLevel = map.get("appLevel")==null?null:(Integer) map.get("appLevel");
            if(appLevel>5){
                throw new IdaasException(ComErrorCode.PARAM_VALID_ERROR.getCode(),ComErrorCode.PARAM_VALID_ERROR.getMessage());
            }
            Object proceed = joinPoint.proceed();
            return proceed;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.拦截器

    拦截器使用request.getReader()获取到请求参数,做校验,但是这种方式获取只能获取一次,所以必须把流再塞回去,否则controller获取不到数据
    流程是:定义拦截器---->注册拦截器---->重新获取数据流---->把数据流塞回请求request

    ①写一个拦截器,获取参数并校验
    import com.alibaba.fastjson.JSONObject;
    import com.atpingan.sunflower.commonutils.exception.IdaasException;
    import com.atpingan.sunflower.commonutils.pingan.enums.ComErrorCode;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.util.Map;
    
    @Component
    @Slf4j
    public class KmsParamValidateInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            Map<String,Object> postReqParam = getPostReqParam(request,Map.class);
            if(null != postReqParam && postReqParam.size() !=0){
            Integer appLevel = postReqParam.get("appLevel")==null?null:(Integer)postReqParam.get("appLevel");
            if(appLevel !=null && appLevel>6){
                throw new IdaasException(ComErrorCode.PARAM_VALID_ERROR.getCode(),ComErrorCode.PARAM_VALID_ERROR.getMessage());
            }
            }
            return true;
        }
        /**
         * 从请求request获取参数
         * @param request
         * @param tClass
         * @param 
         * @return
         */
        private <T> T getPostReqParam(HttpServletRequest request, Class<T> tClass) {
            StringBuffer sb = new StringBuffer();
            String line = null;
            BufferedReader br = null;
            try {
                br = request.getReader();
                while (null != (line=br.readLine())){
                    sb.append(line);
                }
                String s = sb.toString();
                T t = JSONObject.parseObject(s,tClass);
                return t;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }finally {
                if(br !=null){
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    ②注册拦截器
    @Configuration
    public class WebConfig extends WebMvcConfigurationSupport {
        @Override
        protected void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new KmsParamValidateInterceptor()).addPathPatterns("/**").order(10);
            super.addInterceptors(registry);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    ③ 写一个HttpServletRequestWrapper 获取流
    import org.apache.commons.io.IOUtils;
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.*;
    
    public class RequestWrapper extends HttpServletRequestWrapper {
    
        //参数字节数组
        private byte[] requestBody;
        //Http请求对象
        private HttpServletRequest request;
        public RequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            this.request = request;
        }
        /**
         * @return
         * @throws IOException
         */
        @Override
        public ServletInputStream getInputStream() throws IOException {
            /**
             * 每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中
             * 解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题
             */
            if (null == this.requestBody) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                IOUtils.copy(request.getInputStream(), baos);
                this.requestBody = baos.toByteArray();
            }
            final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
            return new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return false;
                }
                @Override
                public boolean isReady() {
                    return false;
                }
                @Override
                public void setReadListener(ReadListener listener) {
    
                }
                @Override
                public int read() {
                    return bais.read();
                }
            };
        }
        public byte[] getRequestBody() {
            return requestBody;
        }
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    ④写一个过滤器把流塞回去
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    @Component
    @WebFilter(filterName = "HttpServletRequestFilter",urlPatterns = "/")
    @Order(100)
    public class HttpServletRequestFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            ServletRequest requestWrapper = null;
            if(request instanceof HttpServletRequest){
                requestWrapper = new RequestWrapper(request);
            }
            if(null == requestWrapper){
                filterChain.doFilter(request,response);
            }else {
                filterChain.doFilter(requestWrapper,response);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    基于Python的书籍数据采集与可视化分析系统
    基于JAVA物业管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
    Visual Studio复制、拷贝C++项目与第三方库配置信息到新的项目中
    TypeScript 数组
    uniapp iOS 真机调试
    ROS学习笔记(六)---服务通信机制
    .NET应用开发之SQLServer常见问题分析
    SQL实现自定义排序
    SVN学习
    Ubuntu 添加 GitLab 官方仓库报错“curl is unable to connect to packagecloud.io over TLS”
  • 原文地址:https://blog.csdn.net/m0_37635053/article/details/126313365