思路
Controller层有两种校验场景
- 单个参数的校验
// 用户登录 Controller 方法
@PostMapping("/login")
public Message login(String verifyCode,String account,String password){
//....
return null;
}
- 实体类的校验
实体类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": { }
}
网友评论