SpringMVC 使用驗證架構 Bean Validation(下)__Java開發

來源:互聯網
上載者:User

本文接上一篇《SpringMVC 使用驗證架構 Bean Validation(上)》: 四、Controller 普通參數驗證與視圖錯誤資訊的展示

對於 form 表單提交綁定到對象的驗證方式,上面已經介紹了。但是在很多時候,我們是通過普通傳參來調用介面的。
比如:http://localhost:8080/myproject/hello?name=Shanhy&age=27&password=pwd
那麼對於這種情況,我們該如何校正 name、age、password 的值呢。

看下面的 Controller 代碼:

五、JSON 請求響應錯誤資訊
package org.springboot.sample.interceptor;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.validation.ConstraintViolation;import javax.validation.ConstraintViolationException;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;/** * JSON請求響應錯誤訊息處理 * * @author 單紅宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2016年4月17日 */public class JsonErrorMsgInterceptor implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)            throws Exception {        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,            ModelAndView modelAndView) throws Exception {        if(modelAndView == null)            return;        // 因為MappingJackson2JsonView預設會把BindingResult全部過濾掉。        // 所以我們要想將錯誤訊息輸出,要在這裡自己處理好。        // 判斷請求是否是.json、方法上是否有@ResponseBody註解,或者類上面是否有@RestController註解        // 表示為json請求        if (!request.getRequestURI().endsWith(".json")) {            HandlerMethod handlerMethod = (HandlerMethod)handler;            if(handlerMethod.getMethodAnnotation(ResponseBody.class) == null){                if(handlerMethod.getBeanType().getAnnotation(RestController.class) == null){                    return;                }            }        }        Map<String, Object> modelMap = modelAndView.getModel();        if (modelMap != null) {            Map<String, String> errorMsg = null;            if(modelMap.containsKey("errorMsg")){                errorMsg = (Map<String, String>)modelMap.get("errorMsg");            }            if(errorMsg == null){                errorMsg = new HashMap<>();                modelMap.put("errorMsg", errorMsg);            }            for (Entry<String, Object> entry : modelMap.entrySet()) {                if (entry.getValue() instanceof BindingResult) {                    BindingResult bindingResult = (BindingResult) entry.getValue();                    if (bindingResult.hasErrors()) {                        for (FieldError fieldError : bindingResult.getFieldErrors()) {                            errorMsg.put(fieldError.getObjectName() + "." + fieldError.getField(),                                    fieldError.getDefaultMessage());                        }                    }                }            }        }    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)            throws Exception {    }}

注意配置該攔截器配置,使其生效。

效果:
六、錯誤資訊的設定檔

預設在 ValidationMessages.properties 設定檔中(參考 《SpringMVC 使用驗證架構 Bean Validation(上)》中的第二點有範例)。

如果想統一使用 messaeg.properties 設定檔中的配置,下面的配置提供參考:

    <!-- 指定自己定義的validator -->    <mvc:annotation-driven validator="validator"/>    <!-- 以下 validator  ConversionService 在使用 mvc:annotation-driven 會 自動註冊-->    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>        <!-- 如果不加預設到 使用classpath下的 ValidationMessages.properties -->        <property name="validationMessageSource" ref="messageSource"/>    </bean>    <!-- 國際化的訊息資源檔(本系統中主要用於顯示/錯誤訊息定製) -->    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">        <property name="basenames">            <list>                <!-- 在web環境中一定要定位到classpath 否則預設到當前web應用下找  -->                <value>classpath:messages</value>                <value>classpath:org/hibernate/validator/ValidationMessages</value>            </list>        </property>        <property name="useCodeAsDefaultMessage" value="false"/>        <property name="defaultEncoding" value="UTF-8"/>        <property name="cacheSeconds" value="60"/>    </bean>
七、錯誤資訊中使用EL運算式

請參考 《SpringMVC 使用驗證架構 Bean Validation(上)》中的第二點。 八、方法層級的驗證

首先註冊 MethodValidationPostProcessor

<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">      <!-- 可以引用自己的 validator 配置,在本文中(下面)可以找到 validator 的參考配置,如果不指定則系統使用預設的 -->    <property name="validator" ref="validator"/>  </bean>

某個 Service 的方法:

@Validated // 告訴MethodValidationPostProcessor此Bean需要開啟方法層級驗證支援  @Servicepublic class ValidatorTestService {    public @Length(min = 12, max = 16, message = "傳回值長度應該為12-16")         String getContent(            @NotBlank(message = "name不可為空")            String name,            @Size(min = 5, max = 10, message="{password.length.illegal}")             String password) {        return name + ":" + password;    }}

在 Controller 調用該方法測試:

    /**     * 測試方法層級的驗證(如果驗證失敗,則會拋出異常 ConstraintViolationException)     *     * @param name     * @param model     * @return     * @author SHANHY     * @create  2016年4月17日     */    @RequestMapping("/test5")    @ResponseBody    public Model test5(String name, String password, Model model){        try {            String content = validatorTestService.getContent(name, password);            model.addAttribute("name", content);        } catch (ConstraintViolationException e) {            addErrorMessage(model, e);        }        return model;    }    /**     * 添加錯誤訊息,建議將該方法提取為一個公用的方法使用。     *     * @param model     * @param e     * @author SHANHY     * @create  2016年5月4日     */    protected void addErrorMessage(Model model, ConstraintViolationException e){        Map<String, String> errorMsg = new HashMap<>();        model.addAttribute("errorMsg", errorMsg);        for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {            // 獲得驗證失敗的類 constraintViolation.getLeafBean()            // 獲得驗證失敗的值 constraintViolation.getInvalidValue()            // 擷取參數值 constraintViolation.getExecutableParameters()            // 獲得傳回值 constraintViolation.getExecutableReturnValue()            errorMsg.put(constraintViolation.getLeafBean().getClass().getName() + "-" + constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage());        }    }
工具類

最後提供一個校正工具類,注意看第一個方法就行了:

/** * Copyright (c) 2005-2012 springside.org.cn */package org.springboot.sample.util;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Set;import javax.validation.ConstraintViolation;import javax.validation.ConstraintViolationException;import javax.validation.Validator;/** * JSR303 Validator(Hibernate Validator)工具類. *  * ConstraintViolation中包含propertyPath, message 和invalidValue等資訊. * 提供了各種convert方法,適合不同的i18n需求: * 1. List<String>, String內容為message * 2. List<String>, String內容為propertyPath + separator + message * 3. Map<propertyPath, message> *  * 詳情見wiki: https://github.com/springside/springside4/wiki/HibernateValidator */public class BeanValidatorUtils {    /**     * 調用JSR303的validate方法, 驗證失敗時拋出ConstraintViolationException.     *      * 參數 Validator 可以直接注入,如:     *      * @Autowired     * protected Validator validator;     *      */    public static void validateWithException(Validator validator, Object object, Class<?>... groups)            throws ConstraintViolationException {        Set<? extends ConstraintViolation<?>> constraintViolations = validator.validate(object, groups);        if (!constraintViolations.isEmpty()) {            throw new ConstraintViolationException(constraintViolations);            // 調用處捕獲異常後,擷取錯誤資訊的方法            // List<String> list = BeanValidatorUtils.extractPropertyAndMessageAsList(ex, ": ");        }    }    /**     * 輔助方法, 轉換ConstraintViolationException中的Set<ConstraintViolations>中為List<message>.     */    public static List<String> extractMessage(ConstraintViolationException e) {        return extractMessage(e.getConstraintViolations());    }    /**     * 輔助方法, 轉換Set<ConstraintViolation>為List<message>     */    @SuppressWarnings("rawtypes")    public static List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {        List<String> errorMessages = new ArrayList<String>();        for (ConstraintViolation violation : constraintViolations) {            errorMessages.add(violation.getMessage());        }        return errorMessages;    }    /**     * 輔助方法, 轉換ConstraintViolationException中的Set<ConstraintViolations>為Map<property, message>.     */    public static Map<String, String> extractPropertyAndMessage(ConstraintViolationException e) {        return extractPropertyAndMessage(e.getConstraintViolations());    }    /**     * 輔助方法, 轉換Set<ConstraintViolation>為Map<property, message>.     */    @SuppressWarnings("rawtypes")    public static Map<String, String> extractPropertyAndMessage(Set<? extends ConstraintViolation> constraintViolations) {        Map<String, String> errorMessages = new HashMap<String, String>();        for (ConstraintViolation violation : constraintViolations) {            errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage());        }        return errorMessages;    }    /**     * 輔助方法, 轉換ConstraintViolationException中的Set<ConstraintViolations>為List<propertyPath message>.     */    public static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e) {        return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");    }    /**     * 輔助方法, 轉換Set<ConstraintViolations>為List<propertyPath message>.     */    @SuppressWarnings("rawtypes")    public static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations) {        return extractPropertyAndMessageAsList(constraintViolations, " ");    }    /**     * 輔助方法, 轉換ConstraintViolationException中的Set<ConstraintViolations>為List<propertyPath +separator+ message>.     */    public static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) {        return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator);    }    /**     * 輔助方法, 轉換Set<ConstraintViolation>為List<propertyPath +separator+ message>.     */    @SuppressWarnings("rawtypes")    public static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations,            String separator) {        List<String> errorMessages = new ArrayList<String>();        for (ConstraintViolation violation : constraintViolations) {            errorMessages.add(violation.getPropertyPath() + separator + violation.getMessage());        }        return errorMessages;    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.