【java】实现自定义注解校验——方法二

爱被打了一巴掌 2024-02-19 09:40 68阅读 0赞

自定义注解校验的实现步骤:

1.创建注解类,编写校验注解,即类似@NotEmpty注解
2.编写自定义校验的逻辑实体类,编写具体的校验逻辑。(这个类可以实现ConstraintValidator这个接口,让注解用来校验)
3.开启使用自定义注解进行校验。

第一种实现自定义注解的方式:https://blog.csdn.net/m0_46459413/article/details/134257302?spm=1001.2014.3001.5502

第二种实现自定义注解的方式:

一、创建注解类:

1、创建类时,选择Annotation类型

在这里插入图片描述

2、编写注解类

在这里插入图片描述

如图是我们自定义的一个年龄注解,message是该注解校验失败时的提示信息,default是默认值,我们可以重写该提示信息。下面两行代码是自定义注解需要加上的,这里不作研究。

二、自定义注解校验逻辑的实现:

这里有两种实现方式,
一种是当注解仅仅作用在字段(属性)上生效时:可以在工具类中编写方法进行逻辑校验;
另一种:使用@Constraint注解,指明了校验类,进行校验,这里只实现第二种。

第二种:使用@Constraint注解,指明校验类,进行校验

EX:自定的Age注解上面有一个@Constraint注解,该注解指明了校验类,我们点进MyAnnoationValidator类看一下
在这里插入图片描述

可以看到校验类都必须要实现ConstraintValidator接口,并且重写接口中的两个方法。

接口上是有泛型的,第一个泛型代表了我们这个校验类是哪个注解的校验类,第二个泛型代表该注解校验的参数是什么类型,第二个注解默认是Object类型,我们改成了Integer类型,
initialize方法 是该校验类的初始化方法,在这个方法里,我们可以对传进来的参数作一些处理。
isValid方法 就是注解类型的核心校验方法,校验通过与否就是看该方法的返回值是true还是false,true就代表校验通过,false就代表校验失败

三、使用自定义注解:

自定义校验注解在代码中的应用

1、在dto中使用:

定义一个实体类User
在这里插入图片描述

2、在代码中使用:

定义一个Controller,使用@Valid注解我们的User类,@Valid注解没有实际的注解体,这个注解的作用就是使我们的@Age注解起作用。
后面的BindingResult类的作用是当注解校验失败时,我们可以手动去处理。如果不加这个类的话,注解校验失败,会直接返回http的400错误码。加上这个类,我们可以自己自定义错误信息,然后返回,此时的http状态码为200
在这里插入图片描述

3、@valid注解

1、@valid注解作用

@valid注解主要用于数据校验,在接口的入参实体类前添加@Valid注解,这时实体类会开启一个校验的功能;然后在入参实体类中的属性上,添加不同的注解(例如@NotBlank注解)来完成不同的校验规则。

2、@valid注解的使用
a、在实体类中添加@valid相关注解

使用@Valid相关注解非常简单,只需要在参数的实体类属性上添加如@NotBlank,@Max,@Min等注解对字段进行限制。如下:

  1. public class User{
  2. @NotBlank(message = "姓名不为空")
  3. private String username;
  4. @NotBlank(message = "密码不为空")
  5. private String password;
  6. }

如果嵌套了实体对象,则需要在最外层属性上添加@Valid注解,否则嵌套实体对象中的验证不生效

  1. public class User{
  2. @NotBlank(message = "姓名不为空")
  3. private String username;
  4. @NotBlank(message = "密码不为空")
  5. private String password;
  6. //嵌套必须加@Valid,否则嵌套中的验证不生效
  7. @Valid
  8. @NotNull(message = "用户信息不能为空")
  9. private UserInfo userInfo;
  10. }
  11. public class UserInfo {
  12. @NotBlank(message = "年龄不为空")
  13. @Max(value = 18,message = "不超过18岁")
  14. private String age;
  15. @NotBlank(message = "性别不为空")
  16. private String gender;
  17. }
b、在接口中添加@valid注解

在controller类中添加接口,POST方法中接收设置了@Valid相关注解的实体对象,然后再参数中添加@Valid注解来开启效验功能,需要注意的是,@Valid对Get请求中接收的平面参数请求无效。

  1. @RestController
  2. public class TestController {
  3. @PostMapping("/user")
  4. public String addUserInfo(@Valid @RequestBody User user){
  5. return "调用成功";
  6. }
  7. }

参考链接:https://blog.csdn.net/weixin_43400432/article/details/126159450

四、观察仿照 @NotEmpty注解,编写自定义校验注解

1、观察下@NotEmpty 注解:

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by Fernflower decompiler)
  4. //
  5. package org.hibernate.validator.constraints;
  6. import java.lang.annotation.Documented;
  7. import java.lang.annotation.ElementType;
  8. import java.lang.annotation.Retention;
  9. import java.lang.annotation.RetentionPolicy;
  10. import java.lang.annotation.Target;
  11. import javax.validation.Constraint;
  12. import javax.validation.Payload;
  13. import javax.validation.ReportAsSingleViolation;
  14. import javax.validation.constraints.NotNull;
  15. import javax.validation.constraints.Size;
  16. import javax.validation.constraintvalidation.SupportedValidationTarget;
  17. import javax.validation.constraintvalidation.ValidationTarget;
  18. @Documented
  19. @Constraint(
  20. validatedBy = {
  21. }
  22. )
  23. @SupportedValidationTarget({
  24. ValidationTarget.ANNOTATED_ELEMENT})
  25. @Target({
  26. ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
  27. @Retention(RetentionPolicy.RUNTIME)
  28. @ReportAsSingleViolation
  29. @NotNull
  30. @Size(
  31. min = 1
  32. )
  33. public @interface NotEmpty {
  34. String message() default "{org.hibernate.validator.constraints.NotEmpty.message}";
  35. Class<?>[] groups() default {
  36. };
  37. Class<? extends Payload>[] payload() default {
  38. };
  39. @Target({
  40. ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
  41. @Retention(RetentionPolicy.RUNTIME)
  42. @Documented
  43. public @interface List {
  44. NotEmpty[] value();
  45. }
  46. }

2、编写身份证校验自定义注解类,也必须有message、groups、payload.

  1. package com.zzidc.web.validator;
  2. import javax.validation.Constraint;
  3. import javax.validation.Payload;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8. /*
  9. * @Description //TODO
  10. * @Date 2019/3/29 17:22
  11. * @Param
  12. * @return
  13. **/
  14. //注解是指定当前自定义注解可以使用在哪些地方,这里仅仅让他可以使用在方法上和属性上;
  15. @Target({
  16. ElementType.METHOD,ElementType.FIELD})
  17. //指定当前注解保留到运行时;
  18. @Retention(RetentionPolicy.RUNTIME)
  19. //指定了当前注解使用哪个类来进行校验。
  20. @Constraint(validatedBy = IdCardValidator.class) //
  21. public @interface IsIdCard {
  22. String message();
  23. // default 关键字 接口中被default修饰的方法,在类实现这个接口时不必必须实现这个方法
  24. Class<?>[] groups() default {
  25. };
  26. // Class<?> 表示不确定的java类型
  27. // Class<T> 表示java类型
  28. // Class<K,V> 分别代表java键值中的key value
  29. // Class<E> 代表Element
  30. Class<? extends Payload>[] payload() default {
  31. };
  32. }

3. 编写校验注解的逻辑类:IdCardValidator.class,该类必须实现ConstraintValidator

  1. package com.zzidc.web.validator;
  2. import com.zzidc.web.service.IdCardValidatorService;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import javax.validation.ConstraintValidator;
  5. import javax.validation.ConstraintValidatorContext;
  6. /**
  7. * @ClassName IdCardValidator
  8. * @Description 校验注解的校验逻辑
  9. * @Date 2019/3/29 17:23
  10. **/
  11. public class IdCardValidator implements ConstraintValidator<IsIdCard,String>{
  12. @Autowired
  13. private IdCardValidatorService idCardValidatorService;
  14. /*
  15. * @Description 校验前的初始化工作
  16. * @Date 2019/3/29 17:27
  17. * @Param [isIdCard]
  18. * @return void
  19. **/
  20. @Override
  21. public void initialize(IsIdCard isIdCard) {
  22. String message = isIdCard.message();
  23. System.out.println("自定义的message信息是:".concat(message));
  24. }
  25. /*
  26. * @Description 具体的校验逻辑
  27. * @Date 2019/3/29 17:29
  28. * @Param [s, constraintValidatorContext]
  29. * @return boolean
  30. **/
  31. @Override
  32. public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
  33. return idCardValidatorService.volid(s);
  34. }
  35. }

我们将具体校验逻辑抽出来,抽成一个service:

  1. package com.zzidc.web.service;
  2. /**
  3. * @ClassName IdCardValidatorService
  4. * @Description TODO
  5. * @Date 2019/3/29 17:34
  6. **/
  7. public interface IdCardValidatorService {
  8. boolean volid(String value);
  9. }

service实现类:

  1. package com.zzidc.web.service.impl;
  2. import com.zzidc.web.service.IdCardValidatorService;
  3. import com.zzidc.web.utils.IdCardUtils;
  4. import org.springframework.stereotype.Service;
  5. /**
  6. * @ClassName IdCardValidatorServiceImpl
  7. * @Description TODO
  8. * @Date 2019/3/29 17:35
  9. **/
  10. @Service
  11. public class IdCardValidatorServiceImpl implements IdCardValidatorService {
  12. @Override
  13. public boolean volid(String value) {
  14. return IdCardUtils.isValidIdCard(value);
  15. }
  16. }

身份证工具校验类:

  1. package com.zzidc.web.utils;
  2. import org.apache.commons.lang3.StringUtils;
  3. /**
  4. * @ClassName IdCardUtils
  5. * @Description TODO
  6. * @Date 2019/3/29 17:37
  7. **/
  8. public class IdCardUtils {
  9. public static boolean isValidIdCard(String value){
  10. String regex = "^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$";
  11. if (StringUtils.isBlank(value)) {
  12. return false;
  13. }
  14. return value.matches(regex);
  15. }
  16. }

发表评论

表情:
评论列表 (有 0 条评论,68人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java定义校验注解

    随着业务的日趋复杂。我们对客户端传来的参数校验也越来越多。这么多的校验如果都写在业务逻辑中,业务代码看起来会很乱。 找时间学习了一下java的注解。特在此记录一下学习过程。