JSR303
* 1)、給Bean添加校驗註解:javax.validation.constraints,並定義自己的message提示
* 2)、開啓校驗功能@Valid
* 效果:校驗錯誤以後會有默認的響應;
* 3)、給校驗的bean後緊跟一個BindingResult,就可以獲取到校驗的結果
* 4)、分組校驗(多場景的複雜校驗)
* 1)、 @NotBlank(message = "品牌名必須提交",groups = {AddGroup.class,UpdateGroup.class})
* 給校驗註解標註什麼情況需要進行校驗
* 2)、@Validated({AddGroup.class})
* 3)、默認沒有指定分組的校驗註解@NotBlank,在分組校驗情況@Validated({AddGroup.class})下不生效,只會在@Validated生效;
*
* 5)、自定義校驗
* 1)、編寫一個自定義的校驗註解
* 2)、編寫一個自定義的校驗器 ConstraintValidator
* 3)、關聯自定義的校驗器和自定義的校驗註解
* @Documented
* @Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多個不同的校驗器,適配不同類型的校驗】 })
* @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
* @Retention(RUNTIME)
* public @interface ListValue {
*
* 4、統一的異常處理
* @ControllerAdvice
* 1)、編寫異常處理類,使用@ControllerAdvice。
* 2)、使用@ExceptionHandler標註方法可以處理的異常。
1.導入maven依賴
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
2.controller層
@RestController public class BrandController { /** * 保存 */ @RequestMapping("/save") public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){ return R.ok(); } /** * 修改 */ @RequestMapping("/update") public R update(@Validated({UpdateGroup.class}) @RequestBody BrandEntity brand){ return R.ok(); } /** * 修改狀態 */ @RequestMapping("/update/status") public R updateStatus(@Validated(UpdateStatusGroup.class) @RequestBody BrandEntity brand){ return R.ok(); } }
3.全局捕獲異常
/** * 集中處理所有異常 */ @Slf4j @RestControllerAdvice public class MyExceptionControllerAdvice { @ExceptionHandler(value= MethodArgumentNotValidException.class) public R handleVaildException(MethodArgumentNotValidException e){ log.error("數據校驗出現問題{},異常類型:{}",e.getMessage(),e.getClass()); BindingResult bindingResult = e.getBindingResult(); Map<String,String> errorMap = new HashMap<>(); bindingResult.getFieldErrors().forEach((fieldError)->{ errorMap.put(fieldError.getField(),fieldError.getDefaultMessage()); }); return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap); } @ExceptionHandler(value = Throwable.class) public R handleException(Throwable throwable){ log.error("錯誤:",throwable); return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg()); }
public enum BizCodeEnume { UNKNOW_EXCEPTION(10000,"系統未知異常"), VAILD_EXCEPTION(10001,"參數格式校驗失敗"); private int code; private String msg; BizCodeEnume(int code,String msg){ this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
4.自定義返回的結果集
/** * 返回數據 * * @author Mark [email protected] */ public class R extends HashMap<String, Object> { private static final long serialVersionUID = 1L; public R() { put("code", 0); put("msg", "success"); } public static R error() { return error(40001, "未知異常,請聯繫管理員"); } public static R error(String msg) { return error(40001, msg); } public static R error(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put("msg", msg); return r; } public static R ok(Map<String, Object> map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } public R put(String key, Object value) { super.put(key, value); return this; } public Integer getCode() { return (Integer) this.get("code"); } }
5.javabean對象
@Data public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; @NotNull(message = "修改必須指定品牌id",groups = {UpdateGroup.class}) @Null(message = "新增不能指定id",groups = {AddGroup.class}) private Long brandId; /** * 品牌名 */ @NotBlank(message = "品牌名必須提交") private String name; /** * 品牌logo地址 */ @URL(message = "logo必須是一個合法的url地址") private String logo; /** * 介紹 */ private String descript; /** * 顯示狀態[0-不顯示;1-顯示] */ @NotNull(groups = {AddGroup.class, UpdateStatusGroup.class}) @ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class}) private Integer showStatus; /** * 檢索首字母 */ @NotEmpty(message = "首字母不允許爲空") @Pattern(regexp="^[a-zA-Z]$",message = "檢索首字母必須是一個字母") private String firstLetter; /** * 排序 */ @NotNull @Min(value = 0,message = "排序必須大於等於0") @Max(value = 100,message = "排序必須小於等於100") private Integer sort; }
6.校驗的類
public interface AddGroup { }
public interface UpdateGroup { }
public interface UpdateStatusGroup { }
7.自定義校驗器
@Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { String message() default "{com.hourui.valid.ListValue.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; int[] vals() default { }; }
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> { private Set<Integer> set = new HashSet<>(); //初始化方法 @Override public void initialize(ListValue constraintAnnotation) { int[] vals = constraintAnnotation.vals(); for (int val : vals) { set.add(val); } } //判斷是否校驗成功 /** * * @param value 需要校驗的值 * @param context * @return */ @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); } }
ValidationMessages.properties
com.hourui.valid.ListValue.message=必須提交指定的值