怎么在springMVC中引入Validation

怎么在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问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注恰卡编程网行业资讯频道了解更多相关知识。

发布于 2021-05-10 20:39:08
收藏
分享
海报
0 条评论
166
上一篇:怎么在Vue中引入jquery实现平滑滚动到指定位置 下一篇:如何在Java 8中引入lambda表达式
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码