ホームページ >Java >&#&チュートリアル >Java コードの例と @Valid、@Validated、@PathVariable の使用方法

Java コードの例と @Valid、@Validated、@PathVariable の使用方法

WBOY
WBOY転載
2023-04-23 14:25:07702ブラウズ

    @Valid和@Validated

    @Valid和@Validated比较

    • 相同点:

      • @Valid注解和 @Validated注解都是开启校验功能的注解

    • 不同点:

      • @Valid注解 : 可以使用在方法,构造函数,方法参数和成员属性上

      • @Validated注解 : 可以用在类型,方法和方法参数上. 但是不能用在成员属性上

      • @Validated注解是Spring基于 @Valid注解的进一步封装,并提供比如分组,分组顺序的高级功能

      • 使用位置不同:

    @Valid高级使用

    @Valid级联校验
    • 级联校验: 也叫嵌套检测.嵌套就是一个实体类包含另一个实体类

    • @Valid和可以用在成员属性的字段上,因此 @Valid可以提供级联校验

    • 示例:

      @Data
      public class Hair {
      	
      	@NotBlank(message = "头发长度必须提交!")
      	private Double length;
      
        	@NotBlank(message = "头发颜色必须提交!")
        	private String color;
      }
      
      @Data
      public class Person {
      	
      	@NotBlank(message = "用户姓名必须提交!")
      	@Size(min=2, max=8)
      	private String userName;
      
        	// 添加@Valid注解实现嵌套检测
        	@Valid
          @NotEmpty(message = "用户要有头发!")
          private List<Hair> hairs;
      }
       
      @PostMapping("/person")
      public Result addPerson(@Valid @RequestBody Person person) {
      	return Result.buildSuccess(person);
      }
      • 只是在方法参数前面添加 @Valid@Validated注解,不会对嵌套的实体类进行校验.要想实现对嵌套的实体类进行校验,需要在嵌套的实体类属性上添加 @Valid注解

    @Validated高级使用

    @Validated分组校验
    • 分组校验:

      • 对指定的组开启校验,可以分别作用于不同的业务场景中

      • 分组校验是由 @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的值指定这个分组时,开会开启注解的校验数据的功能

    @Validated分组校验顺序
    • 默认情况下,分组间的约束是无序的,但是在一些特殊的情况下可能对分组间的校验有一定的顺序

      • 比如第二组的分组的约束的校验需要依赖第一组的稳定状态来进行,此时,要求分组间的约束校验一定要有顺序

    • 分组校验顺序通过使用 @GroupSequence注解实现

    • 示例:

    @Data
    public class UserGroupSequence {
    	
    	public interface FirstGroup {}
    
    	public interface SecondGroup {}
    
    	// 使用GroupSequence定义分组校验顺序:按照FirstGroup,SecondGroup分组顺序进行校验
    	@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注解指定分组校验顺序后,第一组分组的约束的校验没有通过后,就不会进行第二组分组的约束的校验

    @Validated非实体类校验
    • 在非实体类上添加 @Validated注解对非实体类进行校验

    @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中添加全局统一异常处理方法:

    @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的区别:

      • @PathVariable用来指定请求URL中的变量

      • @RequestParam用来获取静态的URL请求入参

    正则表达式校验

    • 使用正则表达式校验 @PathVariable指定的路径变量

    // 请求路径中的id必须是数字,否则寻找不到这个路径404
    @GetMapping("/user/{id:\\d+}")
    public Result getId(@PathVariable(name="id") String userId) {
    	return Result.buildSuccess(userId);
    }

    继承BasicErrorController类

    • @ControllerAdvice注解只能处理进入控制器方法抛出的异常

    • BasicErrorController接口可以处理全局异常

    • @PathVariable路径校验异常不是控制器方法抛出的,此时还没有进入控制器方法:

      • BasicErrorController处理异常,比如404异常时,会跳转到 /error路径,此时会返回错误的html页面

      • 为了保证返回结果统一,继承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);
    	}
    }

    自定义校验注解

    • 使用场景:

      • 对某一个只能输入指定值的字段进行校验. 此时需要使用自定义注解实现

    • 定义自定义的注解 @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属性指定的数字,保存到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);
    		}
    	} 
    }
    • 注意点:

      • 实现自定义的校验逻辑

      • 返回boolean类型的校验结果

      • 获取到自定义注解中的相关的数据

      • 接口中第一个泛型参数表示的是自定义注解类

      • 接口中第二个泛型参数表示的是校验的属性的值的类型

      • 将自定义的注解和实现的校验类联系起来

      • @Constraint注解:

      • 自定义校验注解类需要实现ConstraintValidator130d6b6bf61f2c5a8065b67380683d7b 接口

      • initialize() 方法:

      • isValid() 方法:

    • 自定义注解的使用:

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

    以上がJava コードの例と @Valid、@Validated、@PathVariable の使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。