新聞中心
- 一種是用 Hibernate Validator 來處理
- 一種是用全局異常來處理
兩種方式,我們一一來實(shí)踐體驗(yàn)一下。

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、東莞ssl等。為上千多家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的東莞網(wǎng)站制作公司
一、Hibernate Validator
Spring Boot 已經(jīng)內(nèi)置了 Hibernate Validator 校驗(yàn)框架,這個(gè)可以通過 Spring Boot 官網(wǎng)查看和確認(rèn)。
第一步,進(jìn)入 Spring Boot 官網(wǎng),點(diǎn)擊 learn 這個(gè)面板,點(diǎn)擊參考文檔。
第二步,在參考文檔頁點(diǎn)擊「依賴的版本」。
第三步,在依賴版本頁就可以查看到所有的依賴了,包括版本號。
PS:如果發(fā)現(xiàn)沒有起效,可能是依賴版本沖突了,手動(dòng)把 Hibernate Validator 依賴添加到 pom.xml 文件就可以了。
org.hibernate.validator
hibernate-validator
6.0.17.Final
javax.validation
validation-api
2.0.1.Final
通過 Hibernate Validator 校驗(yàn)框架,我們可以直接在請求參數(shù)的字段上加入注解來完成校驗(yàn)。
具體該怎么做呢?
第一步,在需要驗(yàn)證的字段上加上 Hibernate Validator 提供的校驗(yàn)注解。
比如說我現(xiàn)在有一個(gè)用戶名和密碼登錄的請求參數(shù) UsersLoginParam 類:
@Data
@ApiModel(value="用戶登錄", description="用戶表")
public class UsersLoginParam implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "登錄名")
@NotBlank(message="登錄名不能為空")
private String userLogin;
@ApiModelProperty(value = "密碼")
@NotBlank(message="密碼不能為空")
private String userPass;
}
就可以通過 @NotBlank 注解來對用戶名和密碼進(jìn)行判空校驗(yàn)。除了 @NotBlank 注解,Hibernate Validator 還提供了以下常用注解:
- @NotNull:被注解的字段不能為 null;
- @NotEmpty:被注解的字段不能為空;
- @Min:被注解的字段必須大于等于其value值;
- @Max:被注解的字段必須小于等于其value值;
- @Size:被注解的字段必須在其min和max值之間;
- @Pattern:被注解的字段必須符合所定義的正則表達(dá)式;
- @Email:被注解的字段必須符合郵箱格式。
第二步,在對應(yīng)的請求接口(UsersController.login())中添加 @Validated 注解,并注入一個(gè) BindingResult 參數(shù)。
@Controller
@Api(tags="用戶")
@RequestMapping("/users")
public class UsersController {
@Autowired
private IUsersService usersService;
@ApiOperation(value = "登錄以后返回token")
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public ResultObject login(@Validated UsersLoginParam users, BindingResult result) {
String token = usersService.login(users.getUserLogin(), users.getUserPass());
if (token == null) {
return ResultObject.validateFailed("用戶名或密碼錯(cuò)誤");
}
MaptokenMap = new HashMap<>();
tokenMap.put("token", token);
tokenMap.put("tokenHead", tokenHead);
return ResultObject.success(tokenMap);
}
}
第三步,為控制層(UsersController)創(chuàng)建一個(gè)切面,將通知注入到 BindingResult 對象中,然后再判斷是否有校驗(yàn)錯(cuò)誤,有錯(cuò)誤的話返回校驗(yàn)提示信息,否則放行。
@Aspect
@Component
@Order(2)
public class BindingResultAspect {
@Pointcut("execution(public * com.codingmore.controller.*.*(..))")
public void BindingResult() {
}
@Around("BindingResult()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
if (arg instanceof BindingResult) {
BindingResult result = (BindingResult) arg;
if (result.hasErrors()) {
FieldError fieldError = result.getFieldError();
if(fieldError!=null){
return ResultObject.validateFailed(fieldError.getDefaultMessage());
}else{
return ResultObject.validateFailed();
}
}
}
}
return joinPoint.proceed();
}
}
這里涉及到了 SpringBoot AOP 的知識,我在前面的文章里講解過了,戳這個(gè)鏈接可以直達(dá):SpringBoot AOP 掃盲
第四步,訪問登錄接口,用戶名和密碼都不傳入的情況下,就會(huì)返回“用戶名不能為空”的提示信息。
通過 debug 的形式,體驗(yàn)一下整個(gè)工作流程。
可以看得出,Hibernate Validator 帶來的優(yōu)勢有這些:
- 驗(yàn)證邏輯與業(yè)務(wù)邏輯進(jìn)行了分離,降低了程序耦合度;
- 統(tǒng)一且規(guī)范的驗(yàn)證方式,無需再次編寫重復(fù)的驗(yàn)證代碼。
不過,也帶來一些弊端,比如說:
- 需要在請求接口的方法中注入 BindingResult 對象
- 只能校驗(yàn)一些非常簡單的邏輯,涉及到數(shù)據(jù)查詢就無能為力了。
二、全局異常處理
使用全局異常處理的優(yōu)點(diǎn)就是比較靈活,可以處理比較復(fù)雜的邏輯校驗(yàn),在校驗(yàn)失敗的時(shí)候直接拋出異常,然后進(jìn)行捕獲處理就可以了。
第一步,新建一個(gè)自定義異常類 ApiException。
public class ApiException extends RuntimeException {
private IErrorCode errorCode;
public ApiException(IErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
public ApiException(String message) {
super(message);
}
public ApiException(Throwable cause) {
super(cause);
}
public ApiException(String message, Throwable cause) {
super(message, cause);
}
public IErrorCode getErrorCode() {
return errorCode;
}
}
第二步,新建一個(gè)斷言處理類 Asserts,簡化拋出 ApiException 的步驟。
public class Asserts {
public static void fail(String message) {
throw new ApiException(message);
}
public static void fail(IErrorCode errorCode) {
throw new ApiException(errorCode);
}
}
第三步,新建一全局異常處理類 GlobalExceptionHandler,對異常信息進(jìn)行解析,并封裝到統(tǒng)一的返回對象 ResultObject 中。
@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = ApiException.class)
public ResultObject handle(ApiException e) {
if (e.getErrorCode() != null) {
return ResultObject.failed(e.getErrorCode());
}
return ResultObject.failed(e.getMessage());
}
}
全局異常處理類用到了兩個(gè)注解,@ControllerAdvice 和 @ExceptionHandler。
@ControllerAdvice 是一個(gè)特殊的@Component(可以通過源碼看得到),用于標(biāo)識一個(gè)類,這個(gè)類中被以下三種注解標(biāo)識的方法:@ExceptionHandler,@InitBinder,@ModelAttribute,將作用于所有@Controller 類的接口上。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
}
@ExceptionHandler 注解的作用就是標(biāo)識統(tǒng)一異常處理,它可以指定要統(tǒng)一處理的異常類型,比如說我們自定義的 ApiException。
第四步,在需要校驗(yàn)的地方通過 Asserts 類拋出異常 ApiException。還拿用戶登錄這個(gè)接口來說明吧。
@Controller
@Api(tags="用戶")
@RequestMapping("/users")
public class UsersController {
@ApiOperation(value = "登錄以后返回token")
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public ResultObject login(@Validated UsersLoginParam users, BindingResult result) {
String token = usersService.login(users.getUserLogin(), users.getUserPass());
MaptokenMap = new HashMap<>();
tokenMap.put("token", token);
tokenMap.put("tokenHead", tokenHead);
return ResultObject.success(tokenMap);
}
}
該接口需要查詢數(shù)據(jù)庫驗(yàn)證密碼是否正確,如果密碼不正確就拋出校驗(yàn)信息“密碼不正確”。
@Service
public class UsersServiceImpl extends ServiceImplimplements IUsersService {
public String login(String username, String password) {
String token = null;
//密碼需要客戶端加密后傳遞
UserDetails userDetails = loadUserByUsername(username);
if (!passwordEncoder.matches(password, userDetails.getPassword())) {
Asserts.fail("密碼不正確");
}
// 其他代碼省略
return token;
}
}
第五步,通過 ApiPost 來測試一下接口,故意把密碼輸錯(cuò)。
也可以通過 debug 的形式,體驗(yàn)一下整個(gè)工作流程。
三、總結(jié)
實(shí)際開發(fā)中把兩者結(jié)合在一起用,就可以彌補(bǔ)彼此的短板了,簡單校驗(yàn)用 Hibernate Validator,復(fù)雜一點(diǎn)的邏輯校驗(yàn),比如說需要數(shù)據(jù)庫查詢用全局異常處理來實(shí)現(xiàn)。
源碼地址:https://github.com/itwanger/coding-more
本文名稱:SpringBoot中處理校驗(yàn)邏輯的兩種方式,真的很機(jī)智!
本文路徑:http://fisionsoft.com.cn/article/coehoje.html


咨詢
建站咨詢
