[英]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> </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.validation和org.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.validation
和org.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的故事!
如果類路徑上有任何JSR 303驗證器框架,Spring 3+通過@Valid
注釋支持JSR303
Bean驗證。 Hibernate Validator是JSR 303參考實現之一
任何約束違規都將作為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.