springMVC引入Validation的具体步骤详解
|
本文简单介绍如何引入validation的步骤,如何通过自定义validation减少代码量,提高生产力。特别提及:非基本类型属性的valid,GET方法的处理,validation错误信息的统一resolve。 本文中validation的实际实现委托给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 个性化处理validation错误信息,返回给调用方的信息更加友好, 在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"/>
在项目类路径上增加: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.
* <p>
* 自定义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<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,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<PayType> 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<? extends Payload>[] payload() default {};
}
2、定义Validator,所有的Validator均实现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如果没有个性化需求,可以不用指明,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()方法。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
