javascript
JSR303注解字段校验
JSR303是一套JavaBean參數校驗的標準,定義了很多常用的校驗注解
可以直接將這些注解加在我們JavaBean的屬性上面就可以在需要校驗的時候進行校驗了
依賴
<!-- 屬性效驗--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>一、JSR303定義的校驗類型
| @Null | 傳參不包括該字段,或者傳參該字段值為null |
| @NotNull | 字段必傳,且字段值不能為null,String可為空字符串,Interger不能為空字符串(表單值為 “” 時,可以轉換:Stirng為"",Integer為Null),一般加在Interger類型上 |
| @NotBlank | 字段必傳,且字段值不能為null,去掉前后空格長度大于0(trim()),一般加在字符串上 |
| @NotEmpty | 字段必傳,且字段值不能為null,加在字符串上效果同@NotBlank,也可以加在(Array,Collection,Map)上,判斷不能null,一般加在集合、列表、Map上 |
| @AssertTrue | Boolean 成員變量的值只能為 true |
| @AssertFalse | Boolean 成員變量的值只能為 false |
| @Size(min=, max=) | 校驗對象(Array,Collection,Map,String)長度是否在給定的范圍之內,一般加在列表、集合、Map上 |
| @Length(min=, max=) | 校驗字符串長度是否在指定范圍內,只能加在字符串上 |
| @Past | 驗證 Date 和 Calendar 對象是否在當前時間之前 |
| @Future | 驗證 Date 和 Calendar 對象是否在當前時間之后 |
| @Pattern | 驗證 String 對象是否符合正則表達式的規則 |
| @Min | Number 和 String 對象值大于等于指定的值 |
| @Max | Number 和 String 對象值小于等于指定的值 |
| @DecimalMax | 被標注的值必須不大于約束中指定的最大值. 這個約束的參數是一個通過BigDecimal定義的最大值的字符串表示.小數存在精度 |
| @DecimalMin | 被標注的值必須不小于約束中指定的最小值. 這個約束的參數是一個通過BigDecimal定義的最小值的字符串表示.小數存在精度 |
| @Digits | 驗證 Number 和 String 的構成是否合法 |
| @Digits(integer=,fraction=) | 驗證字符串是否是符合指定格式的數字,interger指定整數精度,fraction指定小數精度。 |
| @Range(min=10000,max=50000,message=“range.bean.wage”) | private BigDecimal wage; |
| @CreditCardNumber | 信用卡驗證 |
| 驗證是否是郵件地址,如果為null,不進行驗證,算通過驗證。 | |
| @ScriptAssert(lang= ,script=, alias=) | |
| @URL(protocol=,host=, port=,regexp=, flags=) |
場景一:前端傳過來的字段如何在后臺做效驗,最老的方法就是if else顯得不是很靈活。如果前端傳來100個字段就得寫許多多余的代碼。
第一個場景就是在后臺創建的實體和前端傳來的字段做對應映射,加上JSR303注解來做靈活的效驗
1:給Bean實體添加校驗注解:javax.validation.constraints(大部分注解都在這個包下),并定義自己的message提示如下:
二、在Springboot項目中使用
2.1、編寫需要校驗的Bean
package com.example.jsr.entity;import com.example.jsr.Constant; import lombok.Data; import org.hibernate.validator.constraints.Length;import javax.validation.constraints.*; import java.io.Serializable; import java.util.List;/*** @author Deyou Kong* @description 品牌實體類* @date 2023/2/25 9:16 上午*/@Data public class Brand implements Serializable {/*** ID*/private Integer id;/*** 品牌名稱*/@NotBlank(message = Constant.NAME_NOT_NULL)@Length(min = 2, max = 32, message = "品牌長度為2-32")private String name;/*** 描述*/@NotNull(message = "描述不能為空NotNull")private String description;/*** 排序*/@Min(value = 1, message = "不能小于1")@Max(value = 10, message = "不能大于10")@NotNull(message = "排序不能為空")private Integer sort;@NotEmpty(message = "關聯應用不能為空")@Size(min = 1, message = "品牌最少關聯一個應用")private List<Integer> appList;}2.2、Controller方法中增加校驗注解
@RestController @RequestMapping("/brand") public class BrandController {@Resourceprivate BrandService brandService;@PostMapping("/save")public JsonResult saveBrand(@Validated @RequestBody Brand brand, BindingResult bindingResult) {System.out.println("進入controller的save方法");if (bindingResult.hasErrors()) {//1.出現參數非法情況Map<String, String> map = new HashMap<>();bindingResult.getFieldErrors().forEach(fieldError -> {map.put(fieldError.getField(), fieldError.getDefaultMessage());});JsonResult jsonResult = JsonResult.fail("參數不正確,請檢查");jsonResult.setData(map);return jsonResult;} else {//2.參數驗證通過, 執行正常邏輯brandService.saveBrand(brand);return JsonResult.commonSuccess();}} }備注:這里一個@Validated (org.springframework.validation.annotation.Validated;)的參數后必須緊挨著一個BindingResult 參數接收參數效驗的結果,否則spring會在校驗不通過時直接拋出異常
2.3、統一異常處理
添加BindingResult參數后,雖然可以使后臺在出現異常時,進行處理并返回統一的結果。但是我們會發現,我們寫了許多與業務不相關的代碼,為了解決這個問題,我們可以通過@ControllerAdvice進行異常的統一處理。
1、編寫統一異常處理類
package com.example.jsr.advice;import com.example.jsr.entity.JsonResult; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.BindingResult; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap; import java.util.Map;/*** @author Deyou Kong* @description 全局異常捕獲處理器* @date 2023/2/25 10:57 下午*/@RestControllerAdvice @Slf4j public class GlobalExceptionControllerAdvice {/*** 出現參數非法情況,拋出MethodArgumentNotValidException異常,在此捕獲處理* @param e* @return*/@ExceptionHandler(MethodArgumentNotValidException.class)public JsonResult handlerMethodArgumentNotValidException(MethodArgumentNotValidException e){BindingResult bindingResult = e.getBindingResult();Map<String, String> map = new HashMap<>();bindingResult.getFieldErrors().forEach(fieldError -> {map.put(fieldError.getField(), fieldError.getDefaultMessage());});JsonResult jsonResult = JsonResult.fail("參數不正確,請檢查");jsonResult.setData(map);return jsonResult;}/**兜底* @param e* @return*/@ExceptionHandler(Exception.class)public JsonResult handlerException(Exception e){JsonResult jsonResult = JsonResult.fail("未知的系統異常");jsonResult.setData(e.getMessage());return jsonResult;} }2、把之前加的BindingResult去掉,還原成原先最干凈的代碼
@RestController @RequestMapping("/brand") public class BrandController {@Resourceprivate BrandService brandService;@PostMapping("/save")public JsonResult saveBrand(@Validated @RequestBody Brand brand) {System.out.println("進入controller的save方法");brandService.saveBrand(brand);return JsonResult.commonSuccess();} }三、分組效驗
在簡單的數據驗證中,我們使用完成了數據驗證。但是還存在一些問題,如在添加品牌的時候Id為null,但在修改品牌的時候Id不能為null,這樣的話,就沖突了。
那怎么辦呢?我們可以給他們分個組,添加操作使用一組驗證規則,修改操作使用一組驗證規則。這就是分組驗證的功能。
以@NotNull注解為例
@Constraint(validatedBy = { }) public @interface NotNull {String message() default "{javax.validation.constraints.NotNull.message}";//分組驗證時使用Class<?>[] groups() default { };...我們通過@NotNul注解的groups指定屬于哪個組
實現步驟:
1、創建AddGroup和UpdateGroup接口分別表示添加組和更新組
//這倆個接口只是用來標記的,不需要實現 public interface AddGroup { }public interface UpdateGroup { }2、實體類中使用注解時,標明該驗證規則屬于哪個組
@Data public class Brand implements Serializable {/*** ID*/@NotNull(message = "ID不能為空", groups = {UpdateGroup.class})private Integer id;/*** 品牌名稱*/@NotBlank(message = Constant.NAME_NOT_NULL, groups = {AddGroup.class, UpdateGroup.class})@Length(min = 2, max = 32, message = "品牌長度為2-32", groups = {AddGroup.class, UpdateGroup.class})private String name;/*** 描述*/@NotNull(message = "描述不能為空NotNull")private String description;/*** 排序*/@Min(value = 1, message = "不能小于1")@Max(value = 10, message = "不能大于10")@NotNull(message = "排序不能為空")private Integer sort;@NotEmpty(message = "關聯應用不能為空")@Size(min = 1, message = "品牌最少關聯一個應用")private List<Integer> appList; }3、Controller中嬌艷注解必須為@Validated
注意:
使用分組功能時,必須使用 @Validated 替代 @Valid,它支持分組效驗功能
4、測試
1、上面實體類中 name 字段的@NotBlank、@Length兩個注解對AddGroup、UpdateGroup兩個分組都生效,所以測試結果中都有錯誤提示
2、ID字段只針對UpdateGroup分組生效,測試結果顯示只針對update接口進行判斷
3、其他字段的注解均未指定分組,那么在Controller指定分組的情況下,這些字段上面的校驗注解不生效
四、自定義效驗注解
步驟:
1、編寫一個自定義的效驗注解
2、編寫一個自定義的效驗器
3、關聯自定義的效驗器和自定義的效驗注解
1、Brand實體類中增加一個字段
private String logo; // 需要判斷logo地址是否以http開頭2、、自定義 IsUrl 注解類
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @Constraint(validatedBy = {IsUrlValidator.class }) public @interface IsUrl {//JSR303規范中,要求必須有message、groups、payload這三個方法//default: 當message為null時,默認會到ValidationMessages.properties配置文件中找com.fcp.common.valid.ListValue.message的值String message() default "{com.fcp.common.valid.ListValue.message}";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };// 注解中用戶配置的字段值,如我指定url的規則存放哪個字段,這里存放在value字段中String value() default ""; }3、編寫一個自定義的效驗器IsUrlValidator.class
校驗器的類名與注解類中Constraint中類名一致
4、在實體類中使用注解
@IsUrl(value = "https:", message = "URL地址不正確", groups = {AddGroup.class, UpdateGroup.class})@NotBlank(message = "logo不能為空")private String logo;5、測試
五、校驗順序
在測試過程中,發現多個注解校驗順序不定,這里還不知道怎么解決
看到一篇文章https://blog.csdn.net/qq_41762594/article/details/109326971,等后面有空在研究
總結
以上是生活随笔為你收集整理的JSR303注解字段校验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android仿朋友圈照片定点放大和滑动
- 下一篇: JSP前三章测试改错