国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > Java > 正文

springMVC引入Validation的具體步驟詳解

2024-07-14 08:40:54
字體:
供稿:網(wǎng)友

本文簡單介紹如何引入validation的步驟,如何通過自定義validation減少代碼量,提高生產(chǎn)力。特別提及:非基本類型屬性的valid,GET方法的處理,validation錯(cuò)誤信息的統(tǒng)一resolve。

本文中validation的實(shí)際實(shí)現(xiàn)委托給Hibernate validation處理

基本配置

pom引入maven依賴

<!-- validation begin --><dependency>  <groupId>javax.validation</groupId>  <artifactId>validation-api</artifactId>  <version>1.1.0.Final</version></dependency><dependency>  <groupId>org.hibernate</groupId>  <artifactId>hibernate-validator</artifactId>  <version>5.4.0.Final</version></dependency><!-- validation end -->

增加validation配置

在spring-mvc-servlet.xml中增加如下配置:

<mvc:annotation-driven validator="validator"><bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">  <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />  <property name="validationMessageSource" ref="messageSource"/></bean>//messageSource 為i18n資源管理bean,見applicationContext.xml配置

自定義exceptionHandler

個(gè)性化處理validation錯(cuò)誤信息,返回給調(diào)用方的信息更加友好, 在applicationContext.xml中增加如下配置:

<!-- 加載i18n消息資源文件 --><bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">  <property name="basenames">    <list>      <value>errormsg</value>      <value>validation_error</value>    </list>  </property></bean><bean id="validationExceptionResolver" class="com.*.exception.ValidationExceptionResovler"/>

在項(xiàng)目類路徑上增加:validation_error_zh_CN.properties資源文件:

#the error msg for input validation#commonfield.can.not.be.null={field}不能為空field.can.not.be.empty={field}不能為空或者空字符串field.must.be.greater.than.min={field}不能小于{value}field.must.be.letter.than.max={field}不能大于{value}

ValidationExceptionResovler實(shí)現(xiàn):

ValidationExceptionResovler.java

@Slf4jpublic class ValidationExceptionResovler extends AbstractHandlerExceptionResolver {  public ValidationExceptionResovler() {    // 設(shè)置order,在DefaultHandlerExceptionResolver之前執(zhí)行    this.setOrder(0);  }  /**   * Handle the case where an argument annotated with {@code @Valid} such as   * an {@link } or {@link } argument fails validation.   * <p>   * 自定義ValidationException 異常處理器   * 獲取到具體的validation 錯(cuò)誤信息,并組裝CommonResponse,返回給調(diào)用方。   *   * @param request current HTTP request   * @param response current HTTP response   * @param handler the executed handler   * @return an empty ModelAndView indicating the exception was handled   * @throws IOException potentially thrown from response.sendError()   */  @ResponseBody  protected ModelAndView handleMethodArgumentNotValidException(BindingResult bindingResult,                                 HttpServletRequest request,                                 HttpServletResponse response,                                 Object handler)      throws IOException {    List<ObjectError> errors = bindingResult.getAllErrors();    StringBuffer errmsgBF = new StringBuffer();    for (ObjectError error : errors) {      String massage = error.getDefaultMessage();      errmsgBF.append(massage);      errmsgBF.append("||");    }    String errmsgString = errmsgBF.toString();    errmsgString = errmsgString.length() > 2 ? errmsgString.substring(0, errmsgString.length() - 2) : errmsgString;    log.error("Validation failed! {} ", errmsgString);    Map<String, Object> map = new TreeMap<String, Object>();    map.put("success", false);    map.put("errorCode", "9999");    map.put("errorMsg", errmsgString);    ModelAndView mav = new ModelAndView();    MappingJackson2JsonView view = new MappingJackson2JsonView();    view.setAttributesMap(map);    mav.setView(view);    return mav;  }  @Override  protected ModelAndView doResolveException(HttpServletRequest request,                       HttpServletResponse response, Object handler,                       Exception ex) {    BindingResult bindingResult = null;    if (ex instanceof MethodArgumentNotValidException) {      bindingResult = ((MethodArgumentNotValidException) ex).getBindingResult();    } else if(ex instanceof BindException) {      bindingResult = ((BindException) ex).getBindingResult();    } else {      //other exception , ignore    }    if(bindingResult != null) {      try {        return handleMethodArgumentNotValidException(bindingResult, request, response, handler);      } catch (IOException e) {        log.error("doResolveException: ", e);      }    }    return null;  }}

在controller中增加@Valid 

@RequestMapping("/buy")@ResponseBodypublic BaseResponse buy(@RequestBody @Valid BuyFlowerRequest request) throws Exception { //......} 

在request bean上為需要validation的屬性增加validation注解

@Setter@Getterpublic class BuyFlowerRequest {@NotEmpty(message = "{name.can.not.be.null}") private String name;} 

二級對象的validation

上面的寫法,只能對BuyFlowerRequest在基本類型屬性上做校驗(yàn),但是沒有辦法對對象屬性的屬性進(jìn)行validation,如果需要對二級對象的屬性進(jìn)行validation,則需要在二級對象及二級對象屬性上同時(shí)添加@Valid 和 具體的validation注解.

如下寫法:

@Setter@Getterpublic class BuyFlowerRequest {  @NotEmpty(field = "花名")  private String name;  @Min(field = "價(jià)格", value = 1)  private int price;  @NotNull  private List<PayType> payTypeList;} @Setter@Getterpublic class PayType {  @Valid  @Min(value = 1)  private int payType;  @Valid  @Min(value = 1)  private int payAmount;}

進(jìn)一步減少編碼量

為了減少編碼工作量,通過自定義Validation注解,嘗試將validation作用的filed名稱傳遞到 錯(cuò)誤信息的資源文件中,從而避免為每個(gè)域編寫不同的message模版.

下面以重寫的@NotNull為例講解:

1、定義Validation注解,注意相比原生注解增加了field(),用于傳遞被validated的filed名字

NotNull.java

@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER })@Constraint(validatedBy = { NotNullValidator.class })@Retention(RetentionPolicy.RUNTIME)public @interface NotNull {  String field() default "";  String message() default "{field.can.not.be.null}";  Class<?>[] groups() default {};  Class<? extends Payload>[] payload() default {};}

2、定義Validator,所有的Validator均實(shí)現(xiàn)ConstraintValidator接口:

NotNullValidator.java

public class NotNullValidator implements ConstraintValidator<NotNull, Object> {  @Override  public void initialize(NotNull annotation) {  }  @Override  public boolean isValid(Object str, ConstraintValidatorContext constraintValidatorContext) {    return str != null;  }}

3、在filed上加入Validation注解,注意指定filed值,message如果沒有個(gè)性化需求,可以不用指明,validation組件會(huì)自行填充default message。

BuyFlowerRequest.java

@Setter@Getterpublic class BuyFlowerRequest {  @NotEmpty(field = "花名")  private String name;  @Min(field = "價(jià)格", value = 1)  private int price;} 

注:@NotNull注解已經(jīng)支持對list的特殊校驗(yàn),對于List類型節(jié)點(diǎn),如果list==null || list.size() == 0都會(huì)返回false,validation失敗。目前已按照此思路自定義實(shí)現(xiàn)了@NotNull、@NotEmpty、@Min、@Max注解,在goods工程中可以找到.

支持GET請求

上面的示例都是POST請求,@RequestBody可以 resolve POST請求,但是不支持GET請求,閱讀spring的文檔和源碼,發(fā)現(xiàn)@ModelAttribute可以將GET請求resolve成Bean,且支持Validation。具體可以翻閱spring源碼:ModelAttributeMethodProcessor.resolveArgument()方法。

使用示例:

@RequestMapping(value = "/buy", method = RequestMethod.GET)@ResponseBodypublic BaseResponse detail(@Valid @ModelAttribute DetailFlowerRequest request) throws Exception {  DetailFlowerResponse response = new DetailFlowerResponse();  response.setName(request.getName());  return ResultFactory.success(response, BaseResponse.class);}

TODO

1、根據(jù)業(yè)務(wù)場景擴(kuò)展validation,如:日期格式、金額等

2、支持多個(gè)field關(guān)系校驗(yàn)的validation

 附:spring validation實(shí)現(xiàn)關(guān)鍵代碼

@RequestBody

實(shí)現(xiàn)類:RequestResponseBodyMethodProcessor.java

public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { this.validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {  throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); return arg;}

@ModelAttibute

實(shí)現(xiàn)類:ModelAttributeMethodProcessor.java

public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String name = ModelFactory.getNameForParameter(parameter); Object attribute = mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : this.createAttribute(name, parameter, binderFactory, webRequest); if (!mavContainer.isBindingDisabled(name)) { ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null && !ann.binding()) {  mavContainer.setBindingDisabled(name); } } WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { if (!mavContainer.isBindingDisabled(name)) {  this.bindRequestParameters(binder, webRequest); } this.validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {  throw new BindException(binder.getBindingResult()); } } Map<String, Object> bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);}

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


注:相關(guān)教程知識(shí)閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宿州市| 饶平县| 镇康县| 施甸县| 康定县| 威信县| 朔州市| 东辽县| 南开区| 涪陵区| 天柱县| 绥芬河市| 延吉市| 张北县| 会理县| 如东县| 遂宁市| 繁峙县| 乐昌市| 师宗县| 麻阳| 青冈县| 宁南县| 金门县| 鹤峰县| 丹巴县| 章丘市| 宜阳县| 南靖县| 聂拉木县| 个旧市| 法库县| 延边| 呼和浩特市| 台东县| 宁陵县| 新津县| 洮南市| 永和县| 青海省| 竹北市|