怎么在springMVC中引入Validation
怎么在springMVC中引入Validation?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
基本配置
pom引入maven依赖
<!--validationbegin--> <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> <!--validationend-->
增加validation配置
在spring-mvc-servlet.xml中增加如下配置:
<mvc:annotation-drivenvalidator="validator"> <beanid="validator"class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <propertyname="providerClass"value="org.hibernate.validator.HibernateValidator"/> <propertyname="validationMessageSource"ref="messageSource"/> </bean> //messageSource为i18n资源管理bean,见applicationContext.xml配置
自定义exceptionHandler
个性化处理validation错误信息,返回给调用方的信息更加友好, 在applicationContext.xml中增加如下配置:
<!--加载i18n消息资源文件--> <beanid="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"> <propertyname="basenames"> <list> <value>errormsg</value> <value>validation_error</value> </list> </property> </bean> <beanid="validationExceptionResolver"class="com.*.exception.ValidationExceptionResovler"/>
在项目类路径上增加:validation_error_zh_CN.properties资源文件:
#theerrormsgforinputvalidation #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 publicclassValidationExceptionResovlerextendsAbstractHandlerExceptionResolver{ publicValidationExceptionResovler(){ //设置order,在DefaultHandlerExceptionResolver之前执行 this.setOrder(0); } /** *Handlethecasewhereanargumentannotatedwith{@code@Valid}suchas *an{@link}or{@link}argumentfailsvalidation. *<p> *自定义ValidationException异常处理器 *获取到具体的validation错误信息,并组装CommonResponse,返回给调用方。 * *@paramrequestcurrentHTTPrequest *@paramresponsecurrentHTTPresponse *@paramhandlertheexecutedhandler *@returnanemptyModelAndViewindicatingtheexceptionwashandled *@throwsIOExceptionpotentiallythrownfromresponse.sendError() */ @ResponseBody protectedModelAndViewhandleMethodArgumentNotValidException(BindingResultbindingResult, HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler) throwsIOException{ List<ObjectError>errors=bindingResult.getAllErrors(); StringBuffererrmsgBF=newStringBuffer(); for(ObjectErrorerror:errors){ Stringmassage=error.getDefaultMessage(); errmsgBF.append(massage); errmsgBF.append("||"); } StringerrmsgString=errmsgBF.toString(); errmsgString=errmsgString.length()>2?errmsgString.substring(0,errmsgString.length()-2):errmsgString; log.error("Validationfailed!{}",errmsgString); Map<String,Object>map=newTreeMap<String,Object>(); map.put("success",false); map.put("errorCode","9999"); map.put("errorMsg",errmsgString); ModelAndViewmav=newModelAndView(); MappingJackson2JsonViewview=newMappingJackson2JsonView(); view.setAttributesMap(map); mav.setView(view); returnmav; } @Override protectedModelAndViewdoResolveException(HttpServletRequestrequest, HttpServletResponseresponse,Objecthandler, Exceptionex){ BindingResultbindingResult=null; if(exinstanceofMethodArgumentNotValidException){ bindingResult=((MethodArgumentNotValidException)ex).getBindingResult(); }elseif(exinstanceofBindException){ bindingResult=((BindException)ex).getBindingResult(); }else{ //otherexception,ignore } if(bindingResult!=null){ try{ returnhandleMethodArgumentNotValidException(bindingResult,request,response,handler); }catch(IOExceptione){ log.error("doResolveException:",e); } } returnnull; } }
在controller中增加@Valid
@RequestMapping("/buy") @ResponseBody publicBaseResponsebuy(@RequestBody@ValidBuyFlowerRequestrequest)throwsException{ //...... }
在request bean上为需要validation的属性增加validation注解
@Setter @Getter publicclassBuyFlowerRequest{ @NotEmpty(message="{name.can.not.be.null}") privateStringname; }
二级对象的validation
上面的写法,只能对BuyFlowerRequest在基本类型属性上做校验,但是没有办法对对象属性的属性进行validation,如果需要对二级对象的属性进行validation,则需要在二级对象及二级对象属性上同时添加@Valid 和 具体的validation注解.
如下写法:
@Setter @Getter publicclassBuyFlowerRequest{ @NotEmpty(field="花名") privateStringname; @Min(field="价格",value=1) privateintprice; @NotNull privateList<PayType>payTypeList; } @Setter @Getter publicclassPayType{ @Valid @Min(value=1) privateintpayType; @Valid @Min(value=1) privateintpayAmount; }
进一步减少编码量
为了减少编码工作量,通过自定义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@interfaceNotNull{ Stringfield()default""; Stringmessage()default"{field.can.not.be.null}"; Class<?>[]groups()default{}; Class<?extendsPayload>[]payload()default{}; }
2、定义Validator,所有的Validator均实现ConstraintValidator接口:
NotNullValidator.java
publicclassNotNullValidatorimplementsConstraintValidator<NotNull,Object>{ @Override publicvoidinitialize(NotNullannotation){ } @Override publicbooleanisValid(Objectstr,ConstraintValidatorContextconstraintValidatorContext){ returnstr!=null; } }
3、在filed上加入Validation注解,注意指定filed值,message如果没有个性化需求,可以不用指明,validation组件会自行填充default message。
BuyFlowerRequest.java
@Setter @Getter publicclassBuyFlowerRequest{ @NotEmpty(field="花名") privateStringname; @Min(field="价格",value=1) privateintprice; }
注:@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 publicBaseResponsedetail(@Valid@ModelAttributeDetailFlowerRequestrequest)throwsException{ DetailFlowerResponseresponse=newDetailFlowerResponse(); response.setName(request.getName()); returnResultFactory.success(response,BaseResponse.class); }
TODO
1、根据业务场景扩展validation,如:日期格式、金额等
2、支持多个field关系校验的validation
附:spring validation实现关键代码
@RequestBody
实现类:RequestResponseBodyMethodProcessor.java
publicObjectresolveArgument(MethodParameterparameter,ModelAndViewContainermavContainer,NativeWebRequestwebRequest,WebDataBinderFactorybinderFactory)throwsException{ Objectarg=this.readWithMessageConverters(webRequest,parameter,parameter.getGenericParameterType()); Stringname=Conventions.getVariableNameForParameter(parameter); WebDataBinderbinder=binderFactory.createBinder(webRequest,arg,name); if(arg!=null){ this.validateIfApplicable(binder,parameter); if(binder.getBindingResult().hasErrors()&&this.isBindExceptionRequired(binder,parameter)){ thrownewMethodArgumentNotValidException(parameter,binder.getBindingResult()); } } mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX+name,binder.getBindingResult()); returnarg; }
@ModelAttibute
实现类:ModelAttributeMethodProcessor.java
publicfinalObjectresolveArgument(MethodParameterparameter,ModelAndViewContainermavContainer,NativeWebRequestwebRequest,WebDataBinderFactorybinderFactory)throwsException{ Stringname=ModelFactory.getNameForParameter(parameter); Objectattribute=mavContainer.containsAttribute(name)?mavContainer.getModel().get(name):this.createAttribute(name,parameter,binderFactory,webRequest); if(!mavContainer.isBindingDisabled(name)){ ModelAttributeann=(ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class); if(ann!=null&&!ann.binding()){ mavContainer.setBindingDisabled(name); } } WebDataBinderbinder=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)){ thrownewBindException(binder.getBindingResult()); } } Map<String,Object>bindingResultModel=binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); returnbinder.convertIfNecessary(binder.getTarget(),parameter.getParameterType(),parameter); }
关于怎么在springMVC中引入Validation问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注恰卡编程网行业资讯频道了解更多相关知识。
推荐阅读
-
Spring中Spring Boot与Spring MVC的核心概念是什么
-
SpringMVC对Restful风格的支持是怎样的
SpringMVC对Restful风格的支持是怎样的这篇文章给大家...
-
springmvc处理器映射器和适配器怎么配置
springmvc处理器映射器和适配器怎么配置这篇文章主要介绍“s...
-
SpringMVC执行过程是怎样的
-
springmvc中怎么利用@ModelAttribute获取表单提交的数据
这篇文章将为大家详细讲解有关springmvc中怎么利用@ModelAttribute获取表单提交的数据,文章内容质量较高,因此小...
-
SpringMVC中Controller类数据响应的方式
-
SpringMVC中怎么发送GET、POST请求
SpringMVC中怎么发送GET、POST请求,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这...
-
springmvc中怎么进行异常处理
springmvc中怎么进行异常处理,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你...
-
SpringMVC记录我遇到的坑_AOP注解无效,切面不执行的解决
SpringMVC记录我遇到的坑_AOP注解无效,切面不执行的解决,恰卡网带你了解更多相关信息。AOP注解无效,切面不执行...
-
使用springMVC通过Filter实现防止xss注入
使用springMVC通过Filter实现防止xss注入,恰卡网带你了解更多相关信息。springMVCFilter防止...