最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用@Validated注解進行參數(shù)驗證的方法

 更新時間:2019年08月14日 10:41:27   作者:spring&fans  
這篇文章主要介紹了Java使用@Validated注解進行參數(shù)驗證的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

目前項目中大部分代碼進行參數(shù)驗證都是寫代碼進行驗證,為了提升方便性和代碼的簡潔性,所以整理了下使用注解進行參數(shù)驗證。使用效果如下:

// 要驗證的實體類
@Data
public class User implements Serializable {
  @NotBlank(message = "id不能為空!",groups = Update.class)
  protected String id = "";
  @NotBlank(message = "商戶id不能為空!")
  protected String tenantId;
  @NotBlank(message = "名稱不能為空!")
  protected String name = "";
}
// controller
// 在要驗證的參數(shù)上添加@Validated注解即可
@PostMapping("add")
public boolean addUser(@Validated @RequestBody User user) {
    ProdAllotStandard info = allotStandardService.getProdAllotStandardWithDetailById(id);
    return info;
}
// 修改則需要比添加的基礎(chǔ)上多驗證一個id,可以通過group的方式進行區(qū)分
// 實體類上不設(shè)置groups,默認(rèn)會是Default,所以修改的時候,我們需要指定Update和Default這兩個組
// group是可以自定義的,我默認(rèn)定義了Add,Update,Delete,Search這四個組
@PostMapping("update")
public boolean updateUser(@Validated({Update.class, Default.class}) @RequestBody User user) {
    ProdAllotStandard info = allotStandardService.getProdAllotStandardWithDetailById(id);
    return info;
}
// 當(dāng)然該注解也支持service上實現(xiàn),同樣的使用方法,在service的實現(xiàn)類的參數(shù)上加上對應(yīng)注解即可,如:
public boolean addUser(@Validated User user) {
     
}
// 通過不同group的搭配,我們就可以靈活的在實體類上配置不同場景的驗證了
// group為一個接口,用以下方式創(chuàng)建
public interface Add {
}

下面看一下具體的實現(xiàn),驗證框架的核心實現(xiàn)采用的是hibernate-validator,我采用的是5.4.3.Final版本。

controller和service的實現(xiàn)方式不同,下面分別介紹下。

不管哪種實現(xiàn),我們都需要先定義一個異常和一個異常攔截器,當(dāng)參數(shù)校驗出現(xiàn)問題時,我們就拋出對應(yīng)異常。

// 為了簡短,省略了部分代碼
public class ParamsException extends RuntimeException{
  private String code;
  public BusinessException() {
  }
  public ParamsException(String code,String message) {
    super(message);
    this.code = code;
  }
  public ParamsException(String message) {
    super(message);
  }
}
// 定義異常處理類
@ControllerAdvice
public class ExceptionAdvice {
 
  private static Logger L = LoggerFactory.getLogger(ExceptionAdvice.class);
 
  // 對所有的ParamsException統(tǒng)一進行攔截處理,如果捕獲到該異常,則封裝成MessageBody返回給前端
  @ExceptionHandler(value = ParamsException.class)
  @ResponseStatus(HttpStatus.OK)
  @ResponseBody
  public MessageBody handleParamsException(HttpServletRequest request, BusinessException e){
    L.error(e.getMessage(),e);
    return getErrorMessageBody(e.getData(),e.getMessage(),e.getMessage(),
        StringUtils.isEmpty(e.getCode())?ResponseCode.BUSINESS_ERROR:e.getCode());
  }
  private MessageBody getErrorMessageBody(Object data,String message,String errorInfo,String code){
    MessageBody body = new MessageBody();
    body.setCode(code);
    body.setData(data);
    body.setErrorCode(Integer.parseInt(code));
    body.setErrorInfo(errorInfo);
    body.setMessage(message);
    body.setSuccess(false);
    return body;
  }
}

controller的驗證的實現(xiàn):

主要是通過實現(xiàn)spring mvc給我們留下的接口進行實現(xiàn)的,該方案沒有用到反射和代理。

1.  實現(xiàn)spring提供的SmartValidator接口

public class ParamsValidator implements SmartValidator {
 
  private javax.validation.Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
 
  @Override
  public boolean supports(Class<?> clazz) {
    return true;
  }
  // 注解上沒有有g(shù)roup的驗證邏輯
  @Override
  public void validate(Object target, Errors errors) {
    validate(target,errors,null);
  }
  // 注解上帶有g(shù)roup的驗證邏輯
  // 第一個參數(shù)為我們要驗證的參數(shù),第二個不用管,第三個為注解上設(shè)置個groups
  @Override
  public void validate(Object target, Errors errors, Object... validationHints) {
    // 這里面為驗證實現(xiàn),可以根據(jù)自己的需要進行完善與修改
    if (target == null) {
      throw new ParamsException("參數(shù)不能為空!");
    } else {
      if(target instanceof String) {
        if(StringUtils.isEmpty(target)) {
          throw new ParamsException("參數(shù)不能為空!");
        }
      }else if(target instanceof Collection) {
        for(Object o:(Collection)target){
          validate(o,validationHints);
        }
      }else {
        validate(target,validationHints);
      }
 
    }
 
  }
  private void validate(Object target,Object ... objs) {
    Set<ConstraintViolation<Object>> violations;
    // 沒有g(shù)roups的驗證
    if(objs==null || objs.length==0) {
      violations = validator.validate(target);
    } else {
    // 基于groups的驗證
      Set<Class<?>> groups = new LinkedHashSet<Class<?>>();
      for (Object hint : objs) {
        if (hint instanceof Class) {
          groups.add((Class<?>) hint);
        }
      }
      violations = validator.validate(target, ClassUtils.toClassArray(groups));
    }
    // 若為空,則驗證通過
    if(violations==null||violations.isEmpty()) {
      return;
    }
    // 驗證不通過則拋出ParamsException異常。
    for(ConstraintViolation item:violations) {
      throw new ParamsException(item.getMessage());
    }
  }
}

2. 配置并設(shè)置Validator驗證器

@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter{
  // 我們在這里重寫spring的一個方法,返回我們自定義的驗證器
  @Override
  public Validator getValidator() {
    return createValidator();
  }
  @Bean
  public ParamsValidator createValidator(){
    return new ParamsValidator();
  }
}

非常簡單,通過上面配置,就可以在controller上使用注解了。

spring mvc對這個注解的處理主要是在RequestResponseBodyMethodProcessor這個類中的resolveArgument方法實現(xiàn)的,該類主要處理方法的參數(shù)和返回值。

spring mvc調(diào)用的一段代碼。

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
  Annotation[] annotations = parameter.getParameterAnnotations();
  for (Annotation ann : annotations) {
    Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
    if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
      Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
      Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
      binder.validate(validationHints);
      break;
    }
  }
}

service的驗證的實現(xiàn):

該方案主要通過aop進行攔截處理的。如下配置:

@Component
@Aspect
public class ParamsValidateAdvice {
  // 這里重用上面定義的那個validator
  private ParamsValidator validator = new ParamsValidator();
  /**
   * 攔截參數(shù)上加了@Validated的注解的方法
   * 排除掉controller,因為controller有自己的參數(shù)校驗實現(xiàn) 不需要aop
   */
  @Pointcut("execution(* com.choice..*(..,@org.springframework.validation.annotation.Validated (*), ..)) && " +
      "!execution(* com.choice..api..*(..)) && " +
      "!execution(* com.choice..controller..*(..)) ")
  public void pointCut(){}
 
  @Before("pointCut()")
  public void doBefore(JoinPoint joinPoint){
    Object[] params=joinPoint.getArgs();
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    Parameter[] parameters = method.getParameters();
    // 驗證參數(shù)上的注解
    for(int i=0;i<parameters.length;i++) {
      Parameter p = parameters[i];
      // 獲取參數(shù)上的注解
      Validated validated = p.getAnnotation(Validated.class);
      if(validated==null) {
        continue;
      }
      // 如果設(shè)置了group
      if(validated.value()!=null && validated.value().length>0) {
        validator.validate(params[i],null,validated.value());
      } else {
        validator.validate(params[i],null);
      }
    }
  }
}

這樣就可以在service使用驗證注解了,具體的Pointcut可以自己進行配置。

個人覺得參數(shù)校驗在controller或者對外暴露的服務(wù)中去做就好了,因為這些都是對外提供服務(wù)的,controller層也應(yīng)該去做這些,所以參數(shù)需要校驗好。

沒必要在自己內(nèi)部調(diào)用的service中加校驗。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java使用DateTimeFormatter實現(xiàn)格式化時間

    Java使用DateTimeFormatter實現(xiàn)格式化時間

    這篇文章主要介紹了Java使用DateTimeFormatter實現(xiàn)格式化時間,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Java中自增和自減操作符(++/--)的那些事

    Java中自增和自減操作符(++/--)的那些事

    這篇文章主要給大家介紹了關(guān)于Java中自增和自減操作符(++/--)的那些事,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • 詳解spring cloud Feign使用中遇到的問題總結(jié)

    詳解spring cloud Feign使用中遇到的問題總結(jié)

    本篇文章主要介紹了詳解spring cloud Feign使用中遇到的問題總結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 結(jié)合Service層講解DAO層的異常處理操作

    結(jié)合Service層講解DAO層的異常處理操作

    這篇文章主要介紹了結(jié)合Service層講解DAO層的異常處理操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java實現(xiàn)并查集

    Java實現(xiàn)并查集

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)并查集,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • springboot中spring.profiles.include的妙用分享

    springboot中spring.profiles.include的妙用分享

    這篇文章主要介紹了springboot中spring.profiles.include的妙用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • JavaWeb入門教程之分頁查詢功能的簡單實現(xiàn)

    JavaWeb入門教程之分頁查詢功能的簡單實現(xiàn)

    這篇文章主要介紹了JavaWeb入門教程之分頁查詢功能的簡單實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Sharding-jdbc報錯:Missing the data source name:‘m0‘解決方案

    Sharding-jdbc報錯:Missing the data source 

    在使用MyBatis-plus進行數(shù)據(jù)操作時,新增Order實體屬性后,出現(xiàn)了數(shù)據(jù)源缺失的提示錯誤,原因是因為userId屬性值使用了隨機函數(shù)生成的Long值,這與sharding-jdbc的路由規(guī)則計算不匹配,導(dǎo)致無法找到正確的數(shù)據(jù)源,通過調(diào)整userId生成邏輯
    2024-11-11
  • SpringBoot項目注入?traceId?追蹤整個請求的日志鏈路(過程詳解)

    SpringBoot項目注入?traceId?追蹤整個請求的日志鏈路(過程詳解)

    本文介紹了如何在單體SpringBoot項目中通過手動實現(xiàn)過濾器或攔截器來注入traceId,以追蹤整個請求的日志鏈路,通過使用MDC和配置日志格式,可以在日志中包含traceId,便于問題排查,同時,還在返回的包裝類中注入traceId,以便用戶反饋問題,感興趣的朋友一起看看吧
    2025-02-02
  • Java的MybatisPlus詳解

    Java的MybatisPlus詳解

    這篇文章主要介紹了Java的MybatisPlus詳解,MyBatis-Plus是一個 MyBatis的增強工具,在MyBatis的基礎(chǔ)上只做增強不做改變,為簡化開發(fā)、提高效率而生,需要的朋友可以參考下
    2023-07-07

最新評論

石林| 巴彦县| 陕西省| 康乐县| 虹口区| 柘荣县| 前郭尔| 霸州市| 嘉兴市| 崇州市| 湘潭县| 东乌| 永城市| 依兰县| 安新县| 保定市| 余姚市| 宁陕县| 综艺| 文山县| 容城县| 汉沽区| 延吉市| 盖州市| 湛江市| 玛曲县| 泰兴市| 凌海市| 太和县| 额济纳旗| 丽水市| 南雄市| 通州市| 桐城市| 上栗县| 朝阳县| 正镶白旗| 桂平市| 鄱阳县| 芜湖县| 雅安市|