您好,登錄后才能下訂單哦!
怎么在springMVC中引入Validation?針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
基本配置
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錯誤信息,返回給調(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"/>
在項目類路徑上增加: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實現(xiàn):
ValidationExceptionResovler.java
@Slf4j public 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 錯誤信息,并組裝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") @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在基本類型屬性上做校驗,但是沒有辦法對對象屬性的屬性進(jìn)行validation,如果需要對二級對象的屬性進(jìn)行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; }
進(jìn)一步減少編碼量
為了減少編碼工作量,通過自定義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均實現(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如果沒有個性化需求,可以不用指明,validation組件會自行填充default message。
BuyFlowerRequest.java
@Setter @Getter public class BuyFlowerRequest { @NotEmpty(field = "花名") private String name; @Min(field = "價格", value = 1) private int price; }
注:@NotNull注解已經(jīng)支持對list的特殊校驗,對于List類型節(jié)點,如果list==null || list.size() == 0都會返回false,validation失敗。目前已按照此思路自定義實現(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) @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、根據(jù)業(yè)務(wù)場景擴(kuò)展validation,如:日期格式、金額等
2、支持多個field關(guān)系校驗的validation
附:spring validation實現(xiàn)關(guān)鍵代碼
@RequestBody
實現(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
實現(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); }
關(guān)于怎么在springMVC中引入Validation問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。