Controller 层参数校验方案

作者: 后端技术学习分享 | 来源:发表于2018-08-10 14:51 被阅读22次

    思路

    Controller层有两种校验场景

    1. 单个参数的校验
    // 用户登录 Controller 方法
    @PostMapping("/login")
    public Message login(String verifyCode,String account,String password){
      //....       
      return null;
    }
    
    1. 实体类的校验
      实体类User里,有多个字段需要校验,比如用户名不能为空,密码不能为空等等
    // 添加用户 Controller 方法
    @PostMapping("/add")
    public Message addUser(User user){
      //....       
      return null;
    }
    

    对于第一种场景,我们可以使用GET参数校验(@RequestParam参数校验)来方便校验参考:
    GET参数校验(@RequestParam参数校验)
    第二种场景,则结合AOP使用请求参数校验。参考:
    [Spring] Web层AOP方式进行参数校验
    [SpringMVC] Web层注解式参数校验

    下面介绍GET参数校验的实现方法。

    环境

    注意,Spring boot 内已经集成了Hibernate validator

    • Spring boot
    • Hibernate validator
    • lombok

    Hibernate 参数校验 - GET参数校验模式 的实现

    • 编写配置类
    package com.spz.demo.security.config;
    
    import lombok.extern.slf4j.Slf4j;
    import org.hibernate.validator.HibernateValidator;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
    import javax.validation.Validation;
    import javax.validation.Validator;
    import javax.validation.ValidatorFactory;
    
    /**
     * 配置 Hibernate 参数校验
     * 参考:https://blog.csdn.net/u010454030/article/details/53009327
     */
    @Slf4j(topic = "SYSTEM_LOG")//日志模块
    @Configuration
    @EnableAutoConfiguration
    public class ValidatorConfig {
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
            postProcessor.setValidator(validator());//快速校验,只要有错马上返回
            return postProcessor;
        }
    
        @Bean
        public Validator validator(){
            ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                    .configure()
                    .addProperty( "hibernate.validator.fail_fast", "true" )
                    .buildValidatorFactory();
            Validator validator = validatorFactory.getValidator();
            return validator;
        }
    
    }
    
    
    • 编写验证错误信息提示
      校验未通过时,将抛出ConstraintViolationException异常,此时需要在异常处理方法里获取错误信息,并进行返回
    package com.spz.demo.security.config;
    
    import com.spz.demo.security.bean.Message;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.ResponseStatus;
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import javax.validation.ValidationException;
    import java.util.Set;
    
    @ControllerAdvice
    @Component
    public class GlobalExceptionHandler {
    
        /**
         * hibernate 参数校验出错会抛出 ConstraintViolationException 异常
         * 在此方法中处理,将错误信息输出
         * @param exception
         * @return
         */
        @ExceptionHandler
        @ResponseBody
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public Object handle(ValidationException exception) {
            String errorInfo = "";
            if(exception instanceof ConstraintViolationException){
                ConstraintViolationException exs = (ConstraintViolationException) exception;
    
                Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
    
                for (ConstraintViolation<?> item : violations) {
                    errorInfo = errorInfo + "[" + item.getMessage() + "]";
                }
            }
            return new Message().setErrorMessage(errorInfo);
        }
    }
    
    
    • Message类是包装请求返回,一般在Controller层使用,用于返回json格式数据
    package com.spz.demo.security.bean;
    
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.spz.demo.security.common.MessageCode;
    import lombok.Data;
    import java.io.Serializable;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 请求响应Bean
     * 使用JSON包装请求返回,使用jackson库
     *
     * @author spz
     */
    @Data
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class Message implements Serializable {
        private int code ;
        private String message ;
        private Map<String,Object> data = new HashMap<String, Object>();
    
        /**
         * 自定义返回
         * @param code
         * @param message
         * @return
         */
        public Message setMessage(int code, String message){
            this.code = code;
            this.message = message;
            return this;
        }
    
        /**
         * 返回成功
         * @return
         */
        public Message setSuccessMessage(){
            this.code = MessageCode.SUCCESS ;
            this.message = "操作成功" ;
            return this;
        }
    
        /**
         * 返回成功
         * @param message
         * @return
         */
        public Message setSuccessMessage(String message){
            this.code = MessageCode.SUCCESS ;
            this.message = message ;
            return this;
        }
    
        /**
         * 返回错误
         * @param message
         * @return
         */
        public Message setErrorMessage(String message){
            this.code = MessageCode.ERROR ;
            this.message = message ;
            return this;
        }
    
        /**
         * 返回警告
         * @param message
         * @return
         */
        public Message setWarnMessage(String message){
            this.code = MessageCode.WARN ;
            this.message = message ;
            return this;
        }
    
        /**
         * 返回未登录
         * @param message
         * @return
         */
        public Message setNoLoginMessage(String message){
            this.code = MessageCode.NO_LOGIN ;
            this.message = message ;
            return this;
        }
    
        /**
         * 返回没有权限
         * @param message
         * @return
         */
        public Message setPermissionDeniedMessage(String message){
            this.code = MessageCode.PERMISSION_DENIED ;
            this.message = message ;
            return this;
        }
    }
    
    
    • Controller 层使用校验
    package com.spz.demo.security.controller;
    
    import com.spz.demo.security.bean.Message;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.validation.constraints.NotEmpty;
    
    /**
     * 用户控制器
     *
     * @author spz
     */
    @Slf4j(topic = "USER_LOG")
    @RestController
    @RequestMapping("/user")
    @Validated//需要使用Hibernate非实体类参数校验,需要加入此注解
    public class UserController {
    
        @Autowired
        StringRedisTemplate redis;
    
        /**
         * 用户登录
         * @return
         */
        @PostMapping("/login")
        public Message login(@NotEmpty(message = "账号不能为空") String account,
                             @NotEmpty(message = "密码不能为空") String password,
                             @NotEmpty(message = "验证码不能为空") String verifyCode){
            //....
            return new Message().setSuccessMessage();
        }
    
    }
    
    

    使用时,发送用户登录请求,如果参数校验失败,将返回错误信息:

    {
      "code": 5000,
      "message": "[验证码不能为空]",
      "data": { }
    }
    

    Hibernate 参数校验 - 实体类校验模式的实现

    [Spring] Web层AOP方式进行参数校验
    [SpringMVC] Web层注解式参数校验

    相关文章

      网友评论

      本文标题:Controller 层参数校验方案

      本文链接:https://www.haomeiwen.com/subject/aqgkbftx.html