思路
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": { }
}