怎么在springMVC中引入Validation

怎么在springMVC中引入Validation?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

公司主营业务:成都网站设计、成都网站制作、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联推出洪江免费做网站回馈大家。

基本配置

pom引入maven依赖



  javax.validation
  validation-api
  1.1.0.Final


  org.hibernate
  hibernate-validator
  5.4.0.Final

增加validation配置

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




  
  

//messageSource 为i18n资源管理bean,见applicationContext.xml配置

自定义exceptionHandler

个性化处理validation错误信息,返回给调用方的信息更加友好, 在applicationContext.xml中增加如下配置:



  
    
      errormsg
      validation_error
    
  


在项目类路径上增加:validation_error_zh_CN.properties资源文件:

#the error msg for input validation
#common
field.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实现:

ValidationExceptionResovler.java

@Slf4j
public class ValidationExceptionResovler extends AbstractHandlerExceptionResolver {
  public ValidationExceptionResovler() {
    // 设置order,在DefaultHandlerExceptionResolver之前执行
    this.setOrder(0);
  }
  /**
   * Handle the case where an argument annotated with {@code @Valid} such as
   * an {@link } or {@link } argument fails validation.
   * 

   * 自定义ValidationException 异常处理器    * 获取到具体的validation 错误信息,并组装CommonResponse,返回给调用方。    *    * @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 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 map = new TreeMap();     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")
@ResponseBody
public BaseResponse buy(@RequestBody @Valid BuyFlowerRequest request) throws Exception {
 //......
}

在request bean上为需要validation的属性增加validation注解

@Setter
@Getter
public class BuyFlowerRequest {

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

二级对象的validation

上面的写法,只能对BuyFlowerRequest在基本类型属性上做校验,但是没有办法对对象属性的属性进行validation,如果需要对二级对象的属性进行validation,则需要在二级对象及二级对象属性上同时添加@Valid 和 具体的validation注解.

如下写法:

@Setter
@Getter
public class BuyFlowerRequest {
  @NotEmpty(field = "花名")
  private String name;

  @Min(field = "价格", value = 1)
  private int price;

  @NotNull
  private List payTypeList;

} 

@Setter
@Getter
public class PayType {

  @Valid
  @Min(value = 1)
  private int payType;

  @Valid
  @Min(value = 1)
  private int payAmount;
}

进一步减少编码量

为了减少编码工作量,通过自定义Validation注解,尝试将validation作用的filed名称传递到 错误信息的资源文件中,从而避免为每个域编写不同的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[] payload() default {};
}

2、定义Validator,所有的Validator均实现ConstraintValidator接口:

NotNullValidator.java

public class NotNullValidator implements ConstraintValidator {

  @Override
  public void initialize(NotNull annotation) {

  }

  @Override
  public boolean isValid(Object str, ConstraintValidatorContext constraintValidatorContext) {
    return str != null;
  }
}

3、在filed上加入Validation注解,注意指定filed值,message如果没有个性化需求,可以不用指明,validation组件会自行填充default message。

BuyFlowerRequest.java

@Setter
@Getter
public class BuyFlowerRequest {

  @NotEmpty(field = "花名")
  private String name;

  @Min(field = "价格", value = 1)
  private int price;
}

注:@NotNull注解已经支持对list的特殊校验,对于List类型节点,如果list==null || list.size() == 0都会返回false,validation失败。目前已按照此思路自定义实现了@NotNull、@NotEmpty、@Min、@Max注解,在goods工程中可以找到.

支持GET请求

上面的示例都是POST请求,@RequestBody可以 resolve POST请求,但是不支持GET请求,阅读spring的文档和源码,发现@ModelAttribute可以将GET请求resolve成Bean,且支持Validation。具体可以翻阅spring源码:ModelAttributeMethodProcessor.resolveArgument()方法。

使用示例:

@RequestMapping(value = "/buy", method = RequestMethod.GET)
@ResponseBody
public BaseResponse detail(@Valid @ModelAttribute DetailFlowerRequest request) throws Exception {

  DetailFlowerResponse response = new DetailFlowerResponse();
  response.setName(request.getName());

  return ResultFactory.success(response, BaseResponse.class);
}

TODO

1、根据业务场景扩展validation,如:日期格式、金额等

2、支持多个field关系校验的validation

 附:spring validation实现关键代码

@RequestBody

实现类: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

实现类: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 bindingResultModel = binder.getBindingResult().getModel();
 mavContainer.removeAttributes(bindingResultModel);
 mavContainer.addAllAttributes(bindingResultModel);
 return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}

关于怎么在springMVC中引入Validation问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。


网页标题:怎么在springMVC中引入Validation
文章分享:http://hbruida.cn/article/jihdhi.html