簡體   English   中英

Spring MVC如何解析和驗證處理程序方法參數?

[英]How does Spring MVC resolve and validate handler method parameters?

我是Spring MVC的新手,我已經導入了一個與服務器端驗證相關的教程項目,我對它究竟是如何工作有一些疑問。

所以我有一個名為login.jsp的登錄頁面,其中包含以下登錄表單:

<form:form action="${pageContext.request.contextPath}/login" commandName="user" method="post">

    <table>

        <tr>
            <td><label>Enter Username : </label></td>
            <td><form:input type="text" path="username" name="username" />
                <br> <form:errors path="username" style="color:red;"></form:errors>
            </td>
        </tr>

        <tr>
            <td><label>Enter Password : </label></td>
            <td><form:input type="password" path="password" name="password" />
                <br> <form:errors path="password" style="color:red;"></form:errors>
            </td>
        </tr>

        <tr>
            <td>&nbsp</td>
            <td align="center"><input type="submit" value="Login" /></td>
        </tr>

    </table>

</form:form>

我認為使用從模型中檢索到的commandName =“user”屬性指定的對象(如果我做了錯誤的斷言,請核對我)來存儲用戶插入的用戶名和密碼。

commandName =“user”是此User類的實例:

import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotBlank;

public class User {

    @NotBlank(message="Username can not be blank")
    private String username;

    @Size(min=6,message="Password must be atleast 6 characters long")
    private String password;

    private String gender;
    private String vehicle;
    private String country;
    private String image;

    ...............................................
    ...............................................
    GETTER AND SETTER METHODS
    ...............................................
    ...............................................
}

因此,您可以看到在用戶名密碼字段中聲明了@NotBlank@Size驗證注釋。

這里是第一個疑問:與2使用的庫javax.validationorg.hibernate.validator的區別究竟是什么?

教程中為什么同時使用? 我可以只使用hibernate驗證器庫做同樣的事情嗎? (我認為我可以使用Hibernate驗證器指定字符串的有效長度,或者不是)?

因此,當提交登錄表單時,它會生成和HttpRequest,這個/ login資源由聲明為控制器類的此方法處理:

@RequestMapping(value="/login" , method=RequestMethod.POST)
public String do_login(HttpServletRequest req , Model md , HttpSession session , @Valid User user, BindingResult br)
{
    try
    {
        //System.out.println(br.getAllErrors().size());

        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println("Username and pasword are : "+username +"  "+ password);
        if(br.getAllErrors().size() > 0){
            System.out.println("Server side validation takes place....");
        }
        else{
        Login_Model lm = new Login_Model();
        String message = lm.do_login_process(username, password);

        if(message.equals("login success"))
        {
            session.setAttribute("username", username);
            return "redirect:/myprofile";
        }
        else
        {
            md.addAttribute("error_msg", message);
        }
        }
        return "login";
    }
    catch(Exception e)
    {
        return "login";
    }
}

好的,現在我對這個方法有以下疑問:

1)將此對象作為輸入參數: @Valid User user 誰傳遞給它? 我認為它可能取決於我指定commandName =“user”的形式,所以Spring自動執行它。 這是正確的嗎?

2)根據我的理解,@ Valid注釋會自動調用驗證過程。 怎么會發生? 與Spring提供的AOP功能有關嗎? 要不然是啥? 為什么這個@Valid注釋只與javax.validation庫相關,而不是與Hibernate驗證器相關(所以@Valid注釋也驗證了用Hibernate驗證器注釋注釋的字段?為什么?)

3)根據我的理解,如果用戶在登錄表單中插入了錯誤的值,我可以通過BindingResult br輸入參數獲取此錯誤。 使用調試器,我可以看到該對象包含由定義到User模型對象中的注釋定義的錯誤消息。 究竟如何運作?

TNX

這里是第一個疑問:2個使用過的庫javax.validationorg.hibernate.validator之間究竟有什么區別?

javax.validation來自JSR-303 API。 您可以在此Maven依賴項中查看API類。

Hibernate驗證器是JSR 303(實際參考實現)的實現之一,因此它實現了所有API,但添加了自己的擴展,例如您提到的@NotBlank注釋。 JSR 303的其他實現是例如Apache BVal


它將此對象作為輸入參數: @Valid User user 誰將它傳遞給處理程序方法?

Spring MVC中處理程序方法的值由HandlerMethodArgumentResolver接口的實現提供。 在您的情況下,將調用以解析User參數的實現可能是ServletModelAttributeMethodProcessor 您可以查看這些類的源代碼和JavaDoc,以了解它們在內部的工作方式。


@Valid注釋將自動調用驗證過程。 這是怎么回事? 它使用AOP嗎? 為什么這個@Valid注釋只與javax.validation庫相關,而不是與Hibernate驗證器相關(所以@Valid注釋也驗證了用Hibernate驗證器注釋注釋的字段?)

驗證過程由ModelAttributeMethodProcessor調用,這是前面提到的ServletModelAttributeMethodProcessor繼承的類。 它包含以下方法:

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
    Annotation[] annotations = parameter.getParameterAnnotations();
    for (Annotation ann : annotations) {
        if (ann.annotationType().getSimpleName().startsWith("Valid")) {
            Object hints = AnnotationUtils.getValue(ann);
            binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
            break;
        }
    }
}

如果仔細觀察,您將看到以下表達式的條件:

ann.annotationType().getSimpleName().startsWith("Valid")

這意味着如果參數具有以Valid開頭的任何注釋 ,Spring將調用驗證。 它可能是JSR 303的@Valid或Spring的@Validated ,它支持驗證組。 它甚至可以是您的自定義注釋,只要它的名稱以Valid開頭即可。


根據我的理解,如果用戶在登錄表單中插入了錯誤的值,我可以從BindingResult處理程序參數中獲取此錯誤。 使用調試器,我可以看到該對象包含由定義到User模型對象中的注釋定義的錯誤消息。 究竟如何運作?

讓我們回到ModelAttributeMethodProcessor類。 resolveArgument方法中有以下代碼:

WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);

這將創建WebDataBinder實例,在前面提到的validateIfApplicable方法中調用validateIfApplicable 驗證本身填充BindingResult ,然后通過ErrorsMethodArgumentResolver類將其提供給控制器處理程序方法,該類再次實現HandlerMethodArgumentResolver


TLDR :你在這個問題中提出的許多問題都可以追溯到HandlerMethodArgumentResolver各種實現。 我建議通過這些課程並使用調試器逐步完成它們以更好地理解它們。

與2使用的庫javax.validation和org.hibernate.validator有什么區別?

Bean Validation是一個Java 規范 ,它允許您通過注釋表達對象模型的約束,允許您以可擴展的方式編寫自定義約束。 它只是一個完全沒有實現的規范 Hibernate Validator是此規范的實現。 Hibernate Validator完全實現了Bean Validation,它還具有hibernate獨有的一些功能。 簡而言之, javax.validation是規范部分, org.hibernate.validator是hibernate的獨特功能。

我可以只使用hibernate驗證器庫做同樣的事情嗎? (我認為我可以使用Hibernate驗證器指定字符串的有效長度,或者不是)?

是的,你可以但最好堅持使用javax.validation命名空間,並且只使用供應商特定命名空間的獨特功能,例如org.hibernate.validator 這種方法的好處是你可以將Hibernate Validator的Bean Validation實現切換到其他更改的東西。

教程中為什么同時使用?

因為@NotBlank約束在Bean Validation規范中不可用,並且僅由Hibernate Validator提供。

它將此對象作為輸入參數:@Valid User user。 誰傳遞給它? 我認為它可能取決於我指定commandName =“user”的形式,所以Spring自動執行它。 這是正確的嗎?

可能你有login url的GET控制器,它返回一個空的User對象,后者又與spring標簽綁定,例如<form:input type="text" path="username" name="username" /> 當用戶填寫表單並提交表單時,spring會收集這些標記值並創建User實例並將其傳遞給控制器​​。

為什么這個@Valid注釋只與javax.validation庫相關,而不是與Hibernate驗證器相關(所以@Valid注釋也驗證了用Hibernate驗證器注釋注釋的字段?為什么?)

已經解釋過,Spec / Impl的故事!

  1. 正確,稱為屬性綁定
  2. 如果類路徑上有任何JSR 303驗證器框架,Spring 3+通過@Valid注釋支持JSR303 Bean驗證。 Hibernate Validator是JSR 303參考實現之一

  3. 任何約束違規都將作為BindingResult對象中的錯誤公開,因此您可以檢查控制器方法中的違規行為,就像您擁有的那樣

    if(br.getAllErrors()。size()> 0){System.out.println(“服務器端驗證發生......”); }

總結,Spring MVC將在使用Spring的表單標簽的JSP表單的輸入binding its properties之后驗證由@Valid注釋注釋的模型對象。 任何約束違規都將暴露,因為BindingResult對象中的錯誤是一個很好的帖子

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM