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

Springboot 使用 JSR 303 對(duì) Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn) 使用消息資源文件對(duì)消息國(guó)際化

 更新時(shí)間:2017年12月18日 11:30:11   作者:曾玉飛  
這篇文章主要介紹了Springboot 使用 JSR 303 對(duì) Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn) 使用消息資源文件對(duì)消息國(guó)際化的相關(guān)知識(shí),需要的朋友可以參考下

導(dǎo)包和配置

導(dǎo)入 JSR 303 的包、hibernate valid 的包

<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>6.0.5.Final</version>
</dependency>
<dependency>
  <groupId>javax.validation</groupId>
  <artifactId>validation-api</artifactId>
  <version>2.0.0.Final</version>
</dependency>

springboot 配置

resources/application.yml 消息資源文件國(guó)際化處理配置

spring:
  messages:
    basename: base,todo # 資源文件 base.properties 和 todo.properties,多個(gè)用逗號(hào)隔開

    encoding: UTF-8 # 必須指定解析編碼,否則中文亂碼

在 springboot 啟動(dòng)類里面配置

@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
  @Value("${spring.messages.basename}")
  private String basename;
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
  @Bean
  @Primary
  public MessageSource messageSource() {
    ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
    resourceBundleMessageSource.setUseCodeAsDefaultMessage(false);
    resourceBundleMessageSource.setDefaultEncoding("UTF-8"); // 重復(fù)定義
    resourceBundleMessageSource.setBasenames(basename.split(","));
    return resourceBundleMessageSource;
  }
  @Bean
  @Primary
  public LocalValidatorFactoryBean validator() {
    LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
    validatorFactoryBean.setProviderClass(HibernateValidator.class);
    validatorFactoryBean.setValidationMessageSource(messageSource());
    return validatorFactoryBean;
  }
  @Override
  public Validator getValidator() {
    return validator();
  }
  /**
   * 方法級(jí)別的單個(gè)參數(shù)驗(yàn)證開啟
   */
  @Bean
  public MethodValidationPostProcessor methodValidationPostProcessor() {
    return new MethodValidationPostProcessor();
  }
}

我們對(duì)于校驗(yàn)參數(shù)通過不了拋出的異常進(jìn)行處理,是通過統(tǒng)一異常捕捉。

@ControllerAdvice
@Component
public class BindValidExceptionHandler {
  @ResponseStatus(value = HttpStatus.OK)
  @ExceptionHandler(ConstraintViolationException.class)
  public @ResponseBody
  Msg handleConstraintViolationException(ConstraintViolationException e) {
    String messageTemplate = e.getConstraintViolations().iterator().next().getMessageTemplate();
    return Msg.error(messageTemplate);
  }
  @ResponseStatus(value = HttpStatus.OK)
  @ExceptionHandler(BindException.class)
  public @ResponseBody
  Msg handleBindException(BindException e) {
    BindingResult bindingResult = e.getBindingResult();
    String className = bindingResult.getTarget().getClass().getName();
    FieldError next = bindingResult.getFieldErrors().iterator().next();
    String fieldName = next.getField();
    String defaultMessage = next.getDefaultMessage();
    if (Pattern.compile("IllegalArgumentException: No enum").matcher(defaultMessage).find()) {
      Matcher matcher = Pattern.compile("for value '(.*?)'").matcher(defaultMessage);
      if (matcher.find()) {
        defaultMessage = "找不到枚舉類型【" + matcher.group(1) + "】";
      }
    }
    return Msg.error(defaultMessage);
  }
  @ResponseStatus(value = HttpStatus.OK)
  @ExceptionHandler(ValidError.class)
  public @ResponseBody
  Msg handleValidError(ValidError e) {
    return Msg.error(e.getMessage());
  }
}

resources/base.propertie

creatorId=創(chuàng)建者 id 不能為小于 {value}。

modifierId=修改者 id 不能為小于 {value}。

resources/todo.properties

todo.privateId.min=私有 id 不能為小于 {value}。

在 bean 字段上使用注解,其中 group 中的 C 和 S 接口是指 Controller 和 Service 的叫法簡(jiǎn)稱,里面分別有 Insert 接口、Update 接口等等,都是自定義約定的東西。

/**
 * 私有 id,是代表項(xiàng)目任務(wù)/非項(xiàng)目任務(wù)/風(fēng)險(xiǎn)/問題/評(píng)審待辦問題等多張表的外鍵
 */
@Min(value = 1, message = "{todo.privateId.min}", groups = {C.Insert.class, C.Update.class, S.Insert.class, S.Update.class})
private long privateId;
/**
 * 創(chuàng)建者id
 */
@Min(value = 1, message = "{creatorId}", groups = {S.Insert.class})
private long creatorId;

Controller 控制層驗(yàn)證

@Validated
@RestController
@RequestMapping("todo")
public class TodoController {
  @Autowired
  private TodoService todoService;
  @GetMapping("getVo")
  public Msg getVo(
    @Min(value = 1, message = "待辦 id 不能小于 1。")
    @RequestParam(required = false, defaultValue = "0")
    long id
  ) {
    return this.todoService.getVo(id);
  }
  @PostMapping("add")
  public Msg add(@Validated({C.Insert.class}) Todo todo) {
    return this.todoService.add(todo);
  }
}

@Validated({C.Insert.class}) 聲明啟用 bean 注解上的驗(yàn)證組,其他驗(yàn)證組不會(huì)進(jìn)行驗(yàn)證,這樣可以區(qū)別開來進(jìn)行單獨(dú)驗(yàn)證。

而像沒有實(shí)體,只有一個(gè)基礎(chǔ)數(shù)據(jù)類型的,可以進(jìn)行驗(yàn)證,但是需要滿足三個(gè)條件:

  • 在啟動(dòng)類配置方法級(jí)別驗(yàn)證啟用類
  • 在 Controller 類上注解 @Validated
  • 在方法參數(shù)里使用驗(yàn)證注解如 @Min,@NotNull 等等

自行驗(yàn)證。

Service 服務(wù)層 AOP 驗(yàn)證

ValidUtil 工具類

需要被 springboot 掃描并注冊(cè)為單例

@Component
public class ValidUtil {
  @Autowired
  private Validator validator;
  public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
    return validator.validate(object, groups);
  }
  public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
    return validator.validateValue(beanType, propertyName, value, groups);
  }
  /**
   * 校驗(yàn)參數(shù),并返回第一個(gè)錯(cuò)誤提示
   * @param t   驗(yàn)證的對(duì)象
   * @param groups 驗(yàn)證的組別
   * @param <T>  對(duì)象擦除前原類型
   * @return 第一個(gè)錯(cuò)誤提示
   */
  public <T> void validAndReturnFirstErrorTips(T t, Class<?>... groups) {
    Set<ConstraintViolation<T>> validate = validator.validate(t, groups);
    if (validate.size() > 0) {
      ConstraintViolation<T> next = validate.iterator().next();
      String message = next.getRootBeanClass().getName() + "-" + next.getPropertyPath() + "-" + next.getMessage();
      throw new ValidError(message);
    }
  }
  /**
   * 校驗(yàn)參數(shù),并返回第一個(gè)錯(cuò)誤提示
   * @param targetClass 驗(yàn)證的對(duì)象的 class 類型
   * @param fieldName  需要驗(yàn)證的名字
   * @param obj     需要屬性值
   * @param groups   驗(yàn)證的組別
   * @param <T>     對(duì)象擦除前原類型
   * @return 第一個(gè)錯(cuò)誤提示
   */
  public <T> void validAndReturnFirstErrorTips(Class targetClass, String fieldName, Object obj, Class<?>... groups) {
    Set<ConstraintViolation<T>> validate = validator.validateValue(targetClass, fieldName, obj, groups);
    if (validate.size() > 0) {
      String message = targetClass.getName() + "-" + fieldName + "-" + validate.iterator().next().getMessage();
      throw new ValidError(message);
    }
  }
}

AOP 配置

主要原理是利用 aop 攔截方法執(zhí)行參數(shù),對(duì)參數(shù)獲取注解。再利用工具類來驗(yàn)證參數(shù),如果驗(yàn)證不通過,直接拋出自定義錯(cuò)誤,自定義錯(cuò)誤已經(jīng)全局統(tǒng)一處理了。

@Aspect
@Component
public class ValidatorAOP {
  @Autowired
  private ValidUtil validUtil;
  /**
   *  定義攔截規(guī)則:攔截 com.servic  包下面的所有類中,有 @Service 注解的方法。
   */
  @Pointcut("execution(* com.service..*(..)) and @annotation(org.springframework.stereotype.Service)")
  public void controllerMethodPointcut() {
  }
  /**
   *  攔截器具體實(shí)現(xiàn)
   */
  @Around("controllerMethodPointcut()") // 指定攔截器規(guī)則;也可以直接把 “execution(* com.xjj.........)” 寫進(jìn)這里
  public Object Interceptor(ProceedingJoinPoint pjp) {
    MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
    Method method = methodSignature.getMethod();
    Annotation[][] argAnnotations = method.getParameterAnnotations();
    Object[] args = pjp.getArgs();
    for (int i = 0; i < args.length; i++) {
      for (Annotation annotation : argAnnotations[i]) {
        if (Validated.class.isInstance(annotation)) {
          Validated validated = (Validated) annotation;
          Class<?>[] groups = validated.value();
          validUtil.validAndReturnFirstErrorTips(args[i], groups);
        }
      }
    }
    try {
      return pjp.proceed(args);
    } catch (Throwable throwable) {
      throwable.printStackTrace();
    }
    return true;
  }
}

驗(yàn)證注解 @Min @NotNull 使用方法

不能寫在實(shí)現(xiàn)類上,只能在接口中使用注解

與 Controller 使用方式基本一樣

@Validated
public interface TodoService {
  /**
   * 查詢 單個(gè)待辦
   * @param id 序號(hào)
   * @return 單個(gè)待辦
   */
  Msg getVo(@Min(value = 1, message = "待辦 id 不能小于 1。") long id);
  /**
   * 添加數(shù)據(jù)
   * @param todo 對(duì)象
   */
  Msg add(@Validated({S.Insert.class}) Todo todo);
}

分享幾個(gè)自定義驗(yàn)證注解

字符串判空驗(yàn)證

package javax.validation.constraints;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
 * 字符串判空驗(yàn)證,hibernate 自帶的可能有問題,使用不了,需要重寫,package 是不能變的。
 */
@Documented
@Constraint(
    validatedBy = {NotBlank.NotBlankValidator.class}
)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotBlank {
  Class<?>[] groups() default {};
  String message() default "{notBlank}";
  Class<? extends Payload>[] payload() default {};
  class NotBlankValidator implements ConstraintValidator<NotBlank, Object> {
    public NotBlankValidator() {
    }
    @Override
    public void initialize(NotBlank constraintAnnotation) {
    }
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
      return value != null && !value.toString().isEmpty();
    }
  }
}

類型判斷,判斷 type 是否為其中一個(gè)值,可以根據(jù)驗(yàn)證組自定義判斷

resources/todo.properties

todo.todoType.insert=新增時(shí),待辦類型只能是 非項(xiàng)目任務(wù)、項(xiàng)目任務(wù)、問題 之中一。
todo.todoType.update=修改時(shí),待辦類型只能是風(fēng)險(xiǎn)、評(píng)審待辦問題 之中一。
bean
/**
 * 待辦類型0非項(xiàng)目任務(wù)1項(xiàng)目任務(wù)2問題3風(fēng)險(xiǎn)4評(píng)審待辦問題
 */
@TodoTypeValid(value = {"0", "1", "2"}, message = "{todo.todoType.insert}", groups = {C.Insert.class, S.Insert.class})
@TodoTypeValid(value = {"3", "4"}, message = "{todo.todoType.update}", groups = {C.Update.class, S.Update.class})
private String todoType;

自定義注解

@Documented
@Constraint(validatedBy = {TodoTypeValid.TodoTypeValidFactory.class})
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TodoTypeValid.List.class)
public @interface TodoTypeValid {
  String message() default "請(qǐng)輸入正確的類型";
  String[] value() default {};
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
  class TodoTypeValidFactory implements ConstraintValidator<TodoTypeValid, String> {
    private String[] annotationValue;
    @Override
    public void initialize(TodoTypeValid todoStatusValid) {
      this.annotationValue = todoStatusValid.value();
    }
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
      if (Arrays.asList(annotationValue).contains(value))
        return true;
      return false;
    }
  }
  @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  @interface List {
    TodoTypeValid[] value();
  }
}

@Repeatable(TodoTypeValid.List.class) 是 JDK8 支持的同一注解多次特性。

根據(jù)上面的同樣也可以用在枚舉類上

resources/todo.properties
todo.todoStatus.insert=新增時(shí),狀態(tài)只能是未開始。
todo.todoStatus.update=修改時(shí),狀態(tài)只能是進(jìn)行中或已完成。
bean
/**
 * 待辦狀態(tài)0未開始1進(jìn)行中2已完成
 */
@TodoStatusValid(enums = {TodoStatus.NOT_STARTED}, message = "{todo.todoStatus.insert}", groups = {C.Insert.class, S.Insert.class})
@TodoStatusValid(enums = {TodoStatus.PROCESSING, TodoStatus.COMPLETED}, message = "{todo.todoStatus.update}", groups = {C.Update.class, S.Update.class})
private TodoStatus todoStatus;

自定義注解

@Documented
@Constraint(validatedBy = {TodoStatusValid.TodoStatusValidFactory.class})
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TodoStatusValid.List.class)
public @interface TodoStatusValid {
  String message() default "請(qǐng)輸入正確的狀態(tài)";
  TodoStatus[] enums() default {};
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
  class TodoStatusValidFactory implements ConstraintValidator<TodoStatusValid, TodoStatus> {
    private TodoStatus[] enums;
    @Override
    public void initialize(TodoStatusValid todoStatusValid) {
      this.enums = todoStatusValid.enums();
    }
    @Override
    public boolean isValid(TodoStatus value, ConstraintValidatorContext context) {
      TodoStatus[] values = TodoStatus.values();
      if (enums != null && enums.length != 0) {
        values = enums;
      }
      if (Arrays.asList(values).contains(value))
        return true;
      return false;
    }
  }
  @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  @interface List {
    TodoStatusValid[] value();
  }
}

總結(jié)

以上所述是小編給大家介紹的Springboot 使用 JSR 303 對(duì) Controller 控制層校驗(yàn)及 Service 服務(wù)層 AOP 校驗(yàn) 使用消息資源文件對(duì)消息國(guó)際化,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java中如何正確遍歷刪除List中的元素

    Java中如何正確遍歷刪除List中的元素

    刪除List中元素這個(gè)場(chǎng)景很場(chǎng)景,很多人可能直接在循環(huán)中直接去刪除元素,這樣做對(duì)嗎?下面小編就來和大家一起討論如何正確遍歷刪除List中的元素,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2023-11-11
  • JavaWeb?Servlet技術(shù)及其應(yīng)用實(shí)踐

    JavaWeb?Servlet技術(shù)及其應(yīng)用實(shí)踐

    這篇文章主要介紹了JavaWeb?Servlet技術(shù),Servlet指在服務(wù)器端執(zhí)行的一段Java代碼,可以接收用戶的請(qǐng)求和返回給用戶響應(yīng)結(jié)果,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • MyBatis類型處理器TypeHandler的作用及說明

    MyBatis類型處理器TypeHandler的作用及說明

    這篇文章主要介紹了MyBatis類型處理器TypeHandler的作用及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • ScheduledExecutorService任務(wù)定時(shí)代碼示例

    ScheduledExecutorService任務(wù)定時(shí)代碼示例

    這篇文章主要介紹了ScheduledExecutorService任務(wù)定時(shí)代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Java基礎(chǔ)之SpringBoot整合knife4j

    Java基礎(chǔ)之SpringBoot整合knife4j

    Swagger現(xiàn)在已經(jīng)成了最流行的接口文檔生成與管理工具,但是你是否在用的時(shí)候也在吐槽,它是真的不好看,接口測(cè)試的json數(shù)據(jù)沒法格式化,測(cè)試地址如果更改了還要去改配置,接口測(cè)試時(shí)增加token驗(yàn)證是真的麻煩…針對(duì)Swagger的種種缺點(diǎn),Knife4j就呼之欲出了.需要的朋友可以參考下
    2021-05-05
  • Java開發(fā)人員最常犯的5個(gè)錯(cuò)誤總結(jié)

    Java開發(fā)人員最常犯的5個(gè)錯(cuò)誤總結(jié)

    作為一名java開發(fā)程序員,不知道大家有沒有遇到過一些匪夷所思的bug。這些錯(cuò)誤通常需要您幾個(gè)小時(shí)才能解決。今天,小編總結(jié)一些常見的編碼錯(cuò)誤,然后給出解決方案。希望大家在日常編碼中能夠避免這樣的問題
    2022-12-12
  • 關(guān)于MyBatis的foreach標(biāo)簽常用方法

    關(guān)于MyBatis的foreach標(biāo)簽常用方法

    這篇文章主要介紹了關(guān)于MyBatis的foreach標(biāo)簽常用方法,foreach 標(biāo)簽可以用來遍歷數(shù)組、列表和 Map 等集合參數(shù),實(shí)現(xiàn)批量操作或一些簡(jiǎn)單 SQL 操作,需要的朋友可以參考下
    2023-05-05
  • springboot 防止重復(fù)請(qǐng)求防止重復(fù)點(diǎn)擊的操作

    springboot 防止重復(fù)請(qǐng)求防止重復(fù)點(diǎn)擊的操作

    這篇文章主要介紹了springboot 防止重復(fù)請(qǐng)求防止重復(fù)點(diǎn)擊的操作,URL 攔截器可以使用 spring 攔截器,但使用 spring,每個(gè)需要過濾的新 URL 都需要添加配置,因此這里使用 AOP 注解 的形式來實(shí)現(xiàn),結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • 詳解關(guān)于IntelliJ IDEA中Schedule for Addition 的問題

    詳解關(guān)于IntelliJ IDEA中Schedule for Addition 的問題

    本篇文章主要介紹了詳解關(guān)于 IntelliJ IDEA 中 Schedule for Addition 的問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • java面向?qū)ο蟮娜筇匦灾焕^承用法實(shí)例分析

    java面向?qū)ο蟮娜筇匦灾焕^承用法實(shí)例分析

    這篇文章主要介紹了java面向?qū)ο蟮娜筇匦灾焕^承用法,結(jié)合實(shí)例形式分析了java面向?qū)ο蟪绦蛟O(shè)計(jì)中繼承的基本原理與具體使用方法,需要的朋友可以參考下
    2019-11-11

最新評(píng)論

陆丰市| 乐平市| 永登县| 忻州市| 兴仁县| 高密市| 慈利县| 三明市| 抚州市| 肥西县| 屯昌县| 呼和浩特市| 赣州市| 上虞市| 和政县| 延川县| 闽清县| 博爱县| 承德市| 临桂县| 南木林县| 开江县| 晋州市| 赤峰市| 当阳市| 遵义县| 迁西县| 吕梁市| 家居| 依兰县| 恩施市| 屯昌县| 内乡县| 思茅市| 仁化县| 凤山县| 西昌市| 江永县| 商河县| 赞皇县| 全南县|