SpringBoot+Hibernate實(shí)現(xiàn)自定義數(shù)據(jù)驗(yàn)證及異常處理
前言
在進(jìn)行 SpringBoot 項(xiàng)目開發(fā)中,經(jīng)常會碰到屬性合法性問題,而面對這個(gè)問題通常的解決辦法就是通過大量的 if 和 else 判斷來解決的,例如:
@PostMapping("/verify")
@ResponseBody
public Object verify(@Valid User user){
if (StringUtils.isEmpty(user.getName())){
return "姓名不能為空";
}
if (StringUtils.isEmpty(user.getAge())){
return "姓名不能為空";
}
if (!StringUtils.isEmpty(user.getSex())&&user.getSex().equals("男")&&user.getSex().equals("女")){
return "性別有誤";
}
return user;
}
這種代碼寫法十分麻煩,試想一下如果你有10個(gè)、20個(gè)字段屬性,你也要跟著寫十幾二十幾個(gè) if 和 else 判斷?

So,本文講解一下使用Hibernate框架來去驗(yàn)證字段屬性,使用相應(yīng)的注解即可實(shí)現(xiàn)字段合法性校驗(yàn),以及如何自定義注解進(jìn)行校驗(yàn),包括出現(xiàn)異常的幾種處理方式。
Hibernate實(shí)現(xiàn)字段校驗(yàn)
Maven依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
常用的校驗(yàn)注解
| 注解 | 釋義 |
|---|---|
| @Null | 必須為null |
| @NotNull | 不能為null |
| @AssertTrue | 必須為true |
| @AssertFalse | 必須為false |
| @Min | 必須為數(shù)字,其值大于或等于指定的最小值 |
| @Max | 必須為數(shù)字,其值小于或等于指定的最大值 |
| @DecimalMin | 必須為數(shù)字,其值大于或等于指定的最小值 |
| @DecimalMax | 必須為數(shù)字,其值小于或等于指定的最大值 |
| @Size | 集合的長度 |
| @Digits | 必須為數(shù)字,其值必須再可接受的范圍內(nèi) |
| @Past | 必須是過去的日期 |
| @Future | 必須是將來的日期 |
| @Pattern | 必須符合正則表達(dá)式 |
| 必須是郵箱格式 | |
| @Length | 長度范圍 |
| @NotEmpty | 不能為null,長度大于0 |
| @Range | 元素的大小范圍 |
| @NotBlank | 不能為null,字符串長度大于0(限字符串) |
定義User實(shí)體類
@Data
public class User {
@NotBlank(message = "姓名不能為空")
private String name;
@NotBlank(message = "年齡不能為空")
private String age;
}
定義UserController
@Controller
public class UserController {
@PostMapping("/verify")
@ResponseBody
public Object verify(@Valid User user, BindingResult result){
//字段校驗(yàn)有錯(cuò)誤
if (result.hasErrors()){
//獲取錯(cuò)誤字段信息
List<FieldError> fieldErrors = result.getFieldErrors();
if (fieldErrors!=null){
//創(chuàng)建一個(gè)map用來封裝字段錯(cuò)誤信息
HashMap<String, String> map = new HashMap<>();
//遍歷錯(cuò)誤字段
fieldErrors.forEach(x->{
//獲取字段名稱
String field = x.getField();
//獲取字段錯(cuò)誤提示信息
String msg = x.getDefaultMessage();
//存入map
map.put(field, msg);
});
return map;
}
}
return user;
}
}
啟動項(xiàng)目進(jìn)行測試

可以看到name和age的錯(cuò)誤信息已經(jīng)封裝好傳回來了
自定義校驗(yàn)注解
自定義一個(gè)校驗(yàn)性別的注解Sex
/**
* 性別約束
* @Target用于指定使用范圍,該處限定只能在字段上使用
* @Retention(RetentionPolicy.RUNTIME)表示注解在運(yùn)行時(shí)可以通過反射獲取到
* @Constraint(validatedBy = xxx.class)指定該注解校驗(yàn)邏輯
*/
@Target({ ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SexConstraintValidator.class)
public @interface Sex {
String message() default "性別有誤";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
創(chuàng)建SexConstraintValidator校驗(yàn)邏輯類
/**
* 性別約束邏輯判斷
*/
public class SexConstraintValidator implements ConstraintValidator<Sex, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && (value.equals("男") || value.equals("女"));
}
}
修改User實(shí)體類
@Data
public class User {
@NotBlank(message = "姓名不能為空")
private String name;
@NotBlank(message = "年齡不能為空")
private String age;
@Sex(message = "性別不能為空或有誤")
private String sex;
}
重啟項(xiàng)目測試效果

使用AOP處理校驗(yàn)異常
Maven依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
這里我們用注解作為AOP的切入點(diǎn),新建一個(gè)注解 BindingResultAnnotation
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BindingResultAnnotation {
}
定義參數(shù)校驗(yàn)切面類
/**
* 參數(shù)校驗(yàn)切面類
*/
@Aspect
@Component
public class BindingResultAspect {
/**
* 校驗(yàn)切入點(diǎn)
*/
@Pointcut("@annotation(com.hsqyz.hibernate.config.aop.BindingResultAnnotation)")
public void BindingResult() {
}
/**
* 環(huán)繞通知
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("BindingResult()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("參數(shù)校驗(yàn)切面...");
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
if (arg instanceof BindingResult) {
BindingResult result = (BindingResult) arg;
if (result.hasErrors()){
List<FieldError> fieldErrors = result.getFieldErrors();
if (fieldErrors!=null){
HashMap<String, String> map = new HashMap<>();
fieldErrors.forEach(x->{
String field = x.getField();
String msg = x.getDefaultMessage();
map.put(field, msg);
});
return map;
}
}
}
}
return joinPoint.proceed();
}
}
修改UserController
注意:這里將新建的切面注解添加到方法上@BindingResultAnnotation,必須攜帶BindingResult result在參數(shù)后面,否則AOP無法獲取錯(cuò)誤信息,導(dǎo)致AOP無法處理異常。
@Controller
public class UserController {
@PostMapping("/verify")
@ResponseBody
@BindingResultAnnotation
public Object verify(@Valid User user, BindingResult result) {
return user;
}
}
重啟項(xiàng)目查看效果

全局異常類處理異常
創(chuàng)建GlobelExceptionHandler來處理全局異常,使用@ExceptionHandle來攔截指定異常,由于參數(shù)校驗(yàn)拋出的異常是BindException,所以我們需要攔截BindException異常,而BindException內(nèi)部封裝這錯(cuò)誤信息,這樣就可以用全局異常處理類來封裝字段錯(cuò)誤信息返回。
/**
* 全局異常處理
*/
@ControllerAdvice
public class GlobelExceptionHandler {
/**
* 參數(shù)驗(yàn)證異常處理
* @param result
* @return
*/
@ResponseBody
@ExceptionHandler(BindException.class)
public Object bindExceptionHandler(BindingResult result) {
System.out.println("參數(shù)驗(yàn)證異常處理...");
if (result.hasErrors()){
List<FieldError> fieldErrors = result.getFieldErrors();
if (fieldErrors!=null){
HashMap<String, String> map = new HashMap<>();
fieldErrors.forEach(x->{
String field = x.getField();
String msg = x.getDefaultMessage();
map.put(field, msg);
});
return map;
}
}
return result.getAllErrors();
}
}
修改UserController
注意:這個(gè)時(shí)候我們就需要去掉verify()方法中的BindingResult result參數(shù),因?yàn)椴蝗サ舻脑挘霈F(xiàn)錯(cuò)誤信息不會拋出異常,會被收集起來封裝到BindingResult中去,所以要想使用全局異常處理類來處理校驗(yàn)異常,就必須去掉BindingResult參數(shù),讓其拋出異常,我們再使用全局異常處理類進(jìn)行異常處理,封裝異常信息并返回。
@Controller
public class UserController {
@PostMapping("/verify")
@ResponseBody
public Object verify(@Valid User user) {
return user;
}
}
重啟項(xiàng)目查看運(yùn)行效果

到此這篇關(guān)于SpringBoot+Hibernate實(shí)現(xiàn)自定義數(shù)據(jù)驗(yàn)證及異常處理的文章就介紹到這了,更多相關(guān)SpringBoot Hibernate數(shù)據(jù)驗(yàn)證 異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring-mybatis與原生mybatis使用對比分析
這篇文章主要介紹了spring-mybatis與原生mybatis使用對比分析,需要的朋友可以參考下2017-11-11
Java實(shí)戰(zhàn)之基于swing的QQ郵件收發(fā)功能實(shí)現(xiàn)
這篇文章主要介紹了Java實(shí)戰(zhàn)之基于swing的QQ郵件收發(fā)功能實(shí)現(xiàn),文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
Java HashTable的原理與實(shí)現(xiàn)
Java中的HashTable是一種線程安全的哈希表實(shí)現(xiàn),它可以高效地存儲和快速查找數(shù)據(jù),本文將介紹Java中的HashTable的實(shí)現(xiàn)原理、常用方法和測試用例,需要的小伙伴可以參考一下2023-09-09
SpringCloud分布式項(xiàng)目下feign的使用示例詳解
這篇文章主要介紹了SpringCloud分布式項(xiàng)目下feign的使用,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07
java 通過cmd 調(diào)用命令啟動tomcat的操作
這篇文章主要介紹了java 通過cmd 調(diào)用命令啟動tomcat的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11

