溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java中的@Valid,@Validated和@PathVariable怎么用

發(fā)布時間:2022-04-27 13:45:51 來源:億速云 閱讀:259 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Java中的@Valid,@Validated和@PathVariable怎么用”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Java中的@Valid,@Validated和@PathVariable怎么用”文章能幫助大家解決問題。

    @Valid和@Validated

    @Valid和@Validated比較

    • 相同點:

      • @Valid注解和 @Validated注解都是開啟校驗功能的注解

    • 不同點:

      • @Valid注解 : 可以使用在方法,構(gòu)造函數(shù),方法參數(shù)和成員屬性上

      • @Validated注解 : 可以用在類型,方法和方法參數(shù)上. 但是不能用在成員屬性上

      • @Validated注解是Spring基于 @Valid注解的進(jìn)一步封裝,并提供比如分組,分組順序的高級功能

      • 使用位置不同:

    @Valid高級使用

    @Valid級聯(lián)校驗
    • 級聯(lián)校驗: 也叫嵌套檢測.嵌套就是一個實體類包含另一個實體類

    • @Valid和可以用在成員屬性的字段上,因此 @Valid可以提供級聯(lián)校驗

    • 示例:

      @Data
      public class Hair {
      	
      	@NotBlank(message = "頭發(fā)長度必須提交!")
      	private Double length;
      
        	@NotBlank(message = "頭發(fā)顏色必須提交!")
        	private String color;
      }
      
      @Data
      public class Person {
      	
      	@NotBlank(message = "用戶姓名必須提交!")
      	@Size(min=2, max=8)
      	private String userName;
      
        	// 添加@Valid注解實現(xiàn)嵌套檢測
        	@Valid
          @NotEmpty(message = "用戶要有頭發(fā)!")
          private List<Hair> hairs;
      }
       
      @PostMapping("/person")
      public Result addPerson(@Valid @RequestBody Person person) {
      	return Result.buildSuccess(person);
      }
      • 只是在方法參數(shù)前面添加 @Valid@Validated注解,不會對嵌套的實體類進(jìn)行校驗.要想實現(xiàn)對嵌套的實體類進(jìn)行校驗,需要在嵌套的實體類屬性上添加 @Valid注解

    @Validated高級使用

    @Validated分組校驗
    • 分組校驗:

      • 對指定的組開啟校驗,可以分別作用于不同的業(yè)務(wù)場景中

      • 分組校驗是由 @Validated注解中的value提供的

    • groups:

      @Data
      public class PersonGroup {
      	
      	public interface AddGroup {}
        
        	public interface UpdateGroup {}
      
        	// @Validated注解value方法指定分組UpdateGroup.class時校驗
        	@NotBlank(message = "用戶ID必須提交!", groups = UpdateGroup.class)
        	private String id;
      
        	// @Validated注解value方法指定分組AddGroup.class或者分組UpdateGroup.class時校驗
        	@NotBlank(message = "用戶的姓名必須提交!", groups = {AddGroup.class, UpdateGroup.class}) 
        	private String name;
      
        	// @Validated注解value方法未指定分組時校驗
        	@Range(min = 1, max = 200, message = "用戶的年齡必須提交!")
        	private int age;
      }
      • JSR 303校驗注解中的分組方法groups

      • 示例:

    • 開啟分組校驗: 通過 @Validated注解的value方法對指定的分組開啟校驗

    @RestController
    @RequestMapping("/person")
    public class PersonGroupController {
    	
    	// 不指定分組時校驗
    	@GetMapping("/person")
    	public Result getPerson(@Validated @RequestBody PersonGroup person) {
    		return Result.buildSuccess(person);
    	}
    
    	// 指定AddGroup分組校驗
    	@PostMapping("/person")
    	public Result addPerson(@Validated(value = PersonGroup.AddGroup.class) @RequestBody PersonGroup person) {
    		return Result.buildSuccess(person);
    	}
    
    	// 指定UpdateGroup分組校驗
    	@PutMapping("/person")
    	public Result updatePerson(@Validated(value = PersonGroup.updateGroup.class) @RequestBody PersonGroup person) {
    		return Result.buildSuccess(person);
    	}
    }
    • 校驗方法添加groups的值來指定分組,只有使用 @Validated注解的value的值指定這個分組時,開會開啟注解的校驗數(shù)據(jù)的功能

    @Validated分組校驗順序
    • 默認(rèn)情況下,分組間的約束是無序的,但是在一些特殊的情況下可能對分組間的校驗有一定的順序

      • 比如第二組的分組的約束的校驗需要依賴第一組的穩(wěn)定狀態(tài)來進(jìn)行,此時,要求分組間的約束校驗一定要有順序

    • 分組校驗順序通過使用 @GroupSequence注解實現(xiàn)

    • 示例:

    @Data
    public class UserGroupSequence {
    	
    	public interface FirstGroup {}
    
    	public interface SecondGroup {}
    
    	// 使用GroupSequence定義分組校驗順序:按照FirstGroup,SecondGroup分組順序進(jìn)行校驗
    	@GroupSequence({FirstGroup.class, SecondGroup.class})
    	public interface Group {}
    
    	@NotEmpty(message = "用戶ID必須提交!", group = FirstGroup.class)
    	private String userId;
    
    	@NotEmpty(message = "用戶姓名必須提交!", group = FirstGroup.class)
    	@Size(min = 2, max = 8, message = "用戶姓名的長度在2~8之間", goup = Second.class)
    	private String userName;
    }
    @RestController
    @RequestMapping("/user")
    public class UserGroupSequenceController {
    	// 這里方法中@Validated注解value的值是Group.class
    	@PostMapping("/user")
    	public Result addGroup(@Validated(value = Group.class) @RequestBody UserGroupSequence user) {
    		return Result.buildSuccess(user);
    	}
    }
    • 使用 @GroupSequence注解指定分組校驗順序后,第一組分組的約束的校驗沒有通過后,就不會進(jìn)行第二組分組的約束的校驗

    @Validated非實體類校驗
    • 在非實體類上添加 @Validated注解對非實體類進(jìn)行校驗

    @Validated
    public class AnnotationController {
    	
    	@GetMapping("/person")
    	public Result getAge(@Range(min = 2, max = 8, message = "年齡在3~8歲!") @RequestParam int age) {
    		return Result.buildSuccess(age);
    	}
    }
    • GlobalExceptionHandler中添加全局統(tǒng)一異常處理方法:

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Result resolveConstraintViolationException(ConstraintVilationException exception) {
    	Set<ConstraintVilation<?>> constraintVilations = exception.getConstraintVilations();
    	// 處理異常信息
    	if (!CollectionUtils.isEmpty(constraintVilations)) {
    		StringBuilder messageBuilder = new StringBuilder();
    		for (ConstraintVilation constraintViolation : constraintVilations) {
    			messageBuilder.append(constraintVilation.getMessage()).append(",");
    		}
    		String errorMessage = messageBuilder.toString();
    		if (errorMessage.length() > 1) {
    			errorMessage.substring(0, errorMessage.length() - 1);
    		}
    		return Result.builderFailure(ErrorStatus.ILLEGAL_DATA.getCode(), errorMessage);
    	} 
    	return Result.builderFailure(ErrorStatus.ILLEGAL_DATA.getCode(), exception.getMessage())
    }

    @PathVariable

    • @PathVariable的作用: 用來指定請求URL路徑里面的變量

    • @PathVariable@RequestParam的區(qū)別:

      • @PathVariable用來指定請求URL中的變量

      • @RequestParam用來獲取靜態(tài)的URL請求入?yún)?/p>

    正則表達(dá)式校驗

    • 使用正則表達(dá)式校驗 @PathVariable指定的路徑變量

    // 請求路徑中的id必須是數(shù)字,否則尋找不到這個路徑404
    @GetMapping("/user/{id:\\d+}")
    public Result getId(@PathVariable(name="id") String userId) {
    	return Result.buildSuccess(userId);
    }

    繼承BasicErrorController類

    • @ControllerAdvice注解只能處理進(jìn)入控制器方法拋出的異常

    • BasicErrorController接口可以處理全局異常

    • @PathVariable路徑校驗異常不是控制器方法拋出的,此時還沒有進(jìn)入控制器方法:

      • BasicErrorController處理異常,比如404異常時,會跳轉(zhuǎn)到 /error路徑,此時會返回錯誤的html頁面

      • 為了保證返回結(jié)果統(tǒng)一,繼承BasicErrorController類,重寫BasicErrorController接口中的錯誤處理方法

    @RestController
    public class PathErrorController extends BasicErrorController {
    	
    	@Autowired
    	public PathErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties, List<ErrorViewResolver> errorViewResolvers) {
    		super(errorAttributes, serverProperties.getError(), errorViewResolvers);
    	}
    
    	/**
    	 * 處理html請求
    	 */
    	@Override
    	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
    		HttpStatus status = getStatus(request);
    		Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
    		ModelAndView modelAndView = new ModelAndView("pathErrorPage", model, status);
    		return modelAndView;
    	}
    	
    	/**
    	 * 處理json請求
    	 */
    	@Override
    	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    		Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
    		
    		Map<String, Object> responseBody = new HashMap<>(8);
    		responseBody.put("success", false);
    		responseBody.put("code", body.get("status"));
    		responseBody.put("message", body.get("error")); 
    		
    		return new ResponseEntity<>(responseBody, HttpStatus.OK);
    	}
    }

    自定義校驗注解

    • 使用場景:

      • 對某一個只能輸入指定值的字段進(jìn)行校驗. 此時需要使用自定義注解實現(xiàn)

    • 定義自定義的注解 @Show :

    @Documented
    @Constraint(validateBy = {Show.ShowConstraintValidator.class})
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Rentation(RUNTIME)
    public @interface Show {
    	String message() default "{com.oxford.annotation.Show.message}";
    
    	Class<?>[] groups() default {};
    
    	Class<? extends Payload>[] payload() default {};
    	
    	int[] value();
    
    	class ShowConstraintValidator implements ConstraintValidator<Show, Integer> {
    		
    		private Set<Integer> set = new HashSet<>();
    
    		/**
    		 * 初始化操作
    		 * 獲取value屬性指定的數(shù)字,保存到Set集合中
    		 */
    		@Override
    		public void initilize(Show constraintAnnotation) {
    			int[] value = constraintAnnotation.value();
    			for (int v : value) {
    				set.add(i);
    			}
    		}	
    
    		@Override
    		public boolean isValid(Integer value, ConstraintValidatorContext context) {
    			return set.contains(value);
    		}
    	} 
    }
    • 注意點:

      • 實現(xiàn)自定義的校驗邏輯

      • 返回boolean類型的校驗結(jié)果

      • 獲取到自定義注解中的相關(guān)的數(shù)據(jù)

      • 接口中第一個泛型參數(shù)表示的是自定義注解類

      • 接口中第二個泛型參數(shù)表示的是校驗的屬性的值的類型

      • 將自定義的注解和實現(xiàn)的校驗類聯(lián)系起來

      • @Constraint注解:

      • 自定義校驗注解類需要實現(xiàn)ConstraintValidator<A extends Annotation, T> 接口

      • initialize() 方法:

      • isValid() 方法:

    • 自定義注解的使用:

    @Data
    public class AnnotationQuery {
    	
    	@Show(value = {0, 1}, message = "數(shù)值只能是0或者1")
    	private Integer isShow;
    }
    @PostMapping("/annotation")
    public Result addAnnotation(@Validated @RequestBody AnnotationQuery annotation) {
    	return Result.buildSuccess(annotation);
    }

    關(guān)于“Java中的@Valid,@Validated和@PathVariable怎么用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI