SpringBoot+Hibernate實(shí)現(xiàn)自定義數(shù)據(jù)驗(yàn)證及異常處理
前言
在進(jìn)行 SpringBoot 項(xiàng)目開(kāi)發(fā)中,經(jīng)常會(huì)碰到屬性合法性問(wèn)題,而面對(duì)這個(gè)問(wèn)題通常的解決辦法就是通過(guò)大量的 if 和 else 判斷來(lái)解決的,例如:
@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框架來(lái)去驗(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 | 集合的長(zhǎng)度 |
@Digits | 必須為數(shù)字,其值必須再可接受的范圍內(nèi) |
@Past | 必須是過(guò)去的日期 |
@Future | 必須是將來(lái)的日期 |
@Pattern | 必須符合正則表達(dá)式 |
必須是郵箱格式 | |
@Length | 長(zhǎng)度范圍 |
@NotEmpty | 不能為null,長(zhǎng)度大于0 |
@Range | 元素的大小范圍 |
@NotBlank | 不能為null,字符串長(zhǎng)度大于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用來(lái)封裝字段錯(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; } }
啟動(dòng)項(xiàng)目進(jìn)行測(cè)試
可以看到name和age的錯(cuò)誤信息已經(jīng)封裝好傳回來(lái)了
自定義校驗(yàn)注解
自定義一個(gè)校驗(yàn)性別的注解Sex
/** * 性別約束 * @Target用于指定使用范圍,該處限定只能在字段上使用 * @Retention(RetentionPolicy.RUNTIME)表示注解在運(yùn)行時(shí)可以通過(guò)反射獲取到 * @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)目測(cè)試效果
使用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無(wú)法獲取錯(cuò)誤信息,導(dǎo)致AOP無(wú)法處理異常。
@Controller public class UserController { @PostMapping("/verify") @ResponseBody @BindingResultAnnotation public Object verify(@Valid User user, BindingResult result) { return user; } }
重啟項(xiàng)目查看效果
全局異常類處理異常
創(chuàng)建GlobelExceptionHandler來(lái)處理全局異常,使用@ExceptionHandle來(lái)攔截指定異常,由于參數(shù)校驗(yàn)拋出的異常是BindException,所以我們需要攔截BindException異常,而B(niǎo)indException內(nèi)部封裝這錯(cuò)誤信息,這樣就可以用全局異常處理類來(lái)封裝字段錯(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)椴蝗サ舻脑?,出現(xiàn)錯(cuò)誤信息不會(huì)拋出異常,會(huì)被收集起來(lái)封裝到BindingResult中去,所以要想使用全局異常處理類來(lái)處理校驗(yàn)異常,就必須去掉BindingResult參數(shù),讓其拋出異常,我們?cè)偈褂萌之惓L幚眍愡M(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一分鐘掌握J(rèn)ava?ElasticJob分布式定時(shí)任務(wù)
ElasticJob?是面向互聯(lián)網(wǎng)生態(tài)和海量任務(wù)的分布式調(diào)度解決方案,本文主要通過(guò)簡(jiǎn)單的示例帶大家深入了解ElasticJob分布式定時(shí)任務(wù)的相關(guān)知識(shí),需要的可以參考一下2023-05-05SpringBoot?@GroupSequenceProvider注解實(shí)現(xiàn)bean多屬性聯(lián)合校驗(yàn)的示例代碼
這篇文章主要介紹了SpringBoot?@GroupSequenceProvider注解實(shí)現(xiàn)bean多屬性聯(lián)合校驗(yàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08SpringCloud Zuul網(wǎng)關(guān)功能實(shí)現(xiàn)解析
這篇文章主要介紹了SpringCloud Zuul網(wǎng)關(guān)功能實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03Java下載遠(yuǎn)程服務(wù)器文件到本地(基于http協(xié)議和ssh2協(xié)議)
這篇文章主要介紹了Java下載遠(yuǎn)程服務(wù)器文件到本地的方法(基于http協(xié)議和ssh2協(xié)議),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01Java中兩個(gè)大數(shù)之間的相關(guān)運(yùn)算及BigInteger代碼示例
這篇文章主要介紹了Java中兩個(gè)大數(shù)之間的相關(guān)運(yùn)算及BigInteger代碼示例,通過(guò)biginteger類實(shí)現(xiàn)大數(shù)的運(yùn)算代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11Spring配置多數(shù)據(jù)源導(dǎo)致事物無(wú)法回滾問(wèn)題
這篇文章主要介紹了Spring配置多數(shù)據(jù)源導(dǎo)致事物無(wú)法回滾問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01Java+mysql本地圖片上傳數(shù)據(jù)庫(kù)及下載示例
本篇文章主要介紹了Java+mysql本地圖片上傳數(shù)據(jù)庫(kù)及下載示例,具有一定的參加價(jià)值,有興趣的可以了解一下。2017-01-01