<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sealyu

    --- 博客已遷移至: http://www.sealyu.com/blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      618 隨筆 :: 87 文章 :: 225 評論 :: 0 Trackbacks

    Annotation-Based Validation with the Spring Bean Validation Framework

    by Willie Wheeler
    2008?7?17? ???
    Use Java annotations to validate your Spring WebMVC form beans.

    The Spring Bean Validation Framework, which is part of the Spring Modules project, allows you to perform validation declaratively using Java annotations. I've always liked the declarative approach, which we saw for instance in Commons Validator, but annotation-based validation is especially convenient.

    JSR 303 (Bean Validation) specifies some standards around bean validation, though the Spring Bean Validation Framework does not adopt those standards. The Hibernate Validator project, on the other hand, aims to provide an implementation of the emerging JSR 303 standard.

    While it very well could be subpar Googling skills on my part, there doesn't seem to be much detailed how-to information out there on actually using the Bean Validation Framework. Hence this article.

    I'm using Spring 2.5.x (specifically, Spring 2.5.5) and Spring Modules 0.9. I assume that you already know Spring and Spring WebMVC in particular.

    If you want to download the code, you can do so here:

    You'll have to download the dependencies separately though.

    Dependencies

    Here's what you'll need (again, I'm using Spring 2.5.x and Spring Modules 0.9):

    • commons-collections.jar
    • commons-lang.jar
    • commons-logging.jar
    • spring.jar
    • spring-modules-validation.jar
    • spring-webmvc.jar

    Java Sources

    I'm going to do things a little differently than I normally do, and start with the Java first. We're going to build a very simple "Contact Us" form of the sort that you might use to ask a question, complain about lousy service, or whatever. Since we're just showing how validation works, I've left out the service and persistence tiers. We're going to do everything with a form bean and a controller.

    Here's the form bean:

    Code listing: contact.UserMessage
    1. package contact;  
    2.   
    3. import org.springmodules.validation.bean.conf.loader.annotation.handler.Email;  
    4. import org.springmodules.validation.bean.conf.loader.annotation.handler.Length;  
    5. import org.springmodules.validation.bean.conf.loader.annotation.handler.NotBlank;  
    6.   
    7. public final class UserMessage {  
    8.       
    9.     @NotBlank  
    10.     @Length(max = 80)  
    11.     private String name;  
    12.       
    13.     @NotBlank  
    14.     @Email  
    15.     @Length(max = 80)  
    16.     private String email;  
    17.       
    18.     @NotBlank  
    19.     @Length(max = 4000)  
    20.     private String text;  
    21.       
    22.     public String getName() {  
    23.         return name;  
    24.     }  
    25.   
    26.     public void setName(String name) {  
    27.         this.name = name;  
    28.     }  
    29.       
    30.     public String getEmail() {  
    31.         return email;  
    32.     }  
    33.   
    34.     public void setEmail(String email) {  
    35.         this.email = email;  
    36.     }  
    37.   
    38.     public String getText() {  
    39.         return text;  
    40.     }  
    41.   
    42.     public void setText(String text) {  
    43.         this.text = text;  
    44.     }  
    45. }  

    The bean itself is pretty uninteresting—I have field for the user's name, e-mail address, and the message text. But the cool part is that I've included annotations that specify validation constraints. It's probably self-explanatory, but I've specified that none of the fields is allowed to be blank, and I've also specified the maximum lengths for each. (You can also specify minimum lengths, which one could use instead of @NotBlank, but I'm using @NotBlank instead for a reason I'll explain in just a bit.) Finally, I've specified that email needs to be a valid e-mail address. It's that simple!

    Here are the rest of the validation rules you can use.

    Now here's the Spring MVC controller, which I've implemented as a POJO controller:

    Code listing: contact.ContactController
    1. package contact;  
    2.   
    3. import org.springframework.beans.factory.annotation.Autowired;  
    4. import org.springframework.stereotype.Controller;  
    5. import org.springframework.ui.ModelMap;  
    6. import org.springframework.validation.BindingResult;  
    7. import org.springframework.validation.Validator;  
    8. import org.springframework.web.bind.annotation.ModelAttribute;  
    9. import org.springframework.web.bind.annotation.RequestMapping;  
    10. import org.springframework.web.bind.annotation.RequestMethod;  
    11.   
    12. @Controller  
    13. public final class ContactController {  
    14.       
    15.     @Autowired  
    16.     private Validator validator;  
    17.       
    18.     public void setValidator(Validator validator) {  
    19.         this.validator = validator;  
    20.     }  
    21.       
    22.     @RequestMapping(value = "/form", method = RequestMethod.GET)  
    23.     public ModelMap get() {  
    24.           
    25.         // Because we're not specifying a logical view name, the  
    26.         // DispatcherServlet's DefaultRequestToViewNameTranslator kicks in.  
    27.         return new ModelMap("userMessage", new UserMessage());  
    28.     }  
    29.       
    30.     @RequestMapping(value = "/form", method = RequestMethod.POST)  
    31.     public String post(@ModelAttribute("userMessage") UserMessage userMsg,  
    32.             BindingResult result) {  
    33.           
    34.         validator.validate(userMsg, result);  
    35.         if (result.hasErrors()) { return "form"; }  
    36.           
    37.         // Use the redirect-after-post pattern to reduce double-submits.  
    38.         return "redirect:thanks";  
    39.     }  
    40.       
    41.     @RequestMapping("/thanks")  
    42.     public void thanks() {  
    43.     }  
    44. }  

    The Bean Validation Framework includes its own Validator implementation, called BeanValidator, and I'm making that injectable here. Also, note that we're going to autowire it in.

    It may be that there's a standard, predefined interceptor to apply BeanValidator (as opposed to injecting the Validator into the controller), but if there is, I haven't seen it. I'd be interested to hear if you, gentle reader, know of one.

    The noteworthy method here is the second post() method, which contains the validation code. I just call the standard validate() method, passing in the form bean and the BindingResult, and return the current logical view name if there's an error. That way the form shows the validation error messages, which we'll see below. If everything passes validation, I just redirect to a "thank you" page.

    Now let's look at how we define the validation messages that the end user sees if his form submission fails validation.

    Validation Messages

    Code listing: /WEB-INF/classes/errors.properties
    1. UserMessage.name[not.blank]=Please enter your name.  
    2. UserMessage.name[length]=Please enter no more than {2} characters.  
    3. UserMessage.email[not.blank]=Please enter your e-mail address.  
    4. UserMessage.email[email]=Please enter a valid e-mail address.  
    5. UserMessage.email[length]=Please enter no more than {2} characters.  
    6. UserMessage.text[not.blank]=Please enter a message.  
    7. UserMessage.text[length]=Please enter no more than {2} characters.  

    The keys should be fairly self-explanatory given UserMessage above. Each key involves a class, a field and an annotation. The values are parametrizable messages, not unlike Commons Validator messages if you're familiar with those. In the three length messages, I'm using {2} to indicate argument #2—viz., max—for the length validation rule. Argument #1 happens to be min, and argument #0 in general appears to be the form bean itself. I can imagine that it would be nice to be able to use the form bean to get at the specific submitted value so you could say things like "You entered 4012 characters, but the limit is 4000 characters." And I think there's actually a way to do that though I don't myself know how to do it yet. (This is another one of those areas where I'd appreciate whatever information you may have.)

    I mentioned above that I chose @NotBlank instead of @Length(min = 1, max = 80). The reason is that I wanted to use a specific error message ("Please enter your name") if the message is blank. I could have just used "Please enter a name between 1-80 characters" but that sounds slightly silly compared to "Please enter your name", and since I'm a usability guy I care about such things.

    The JSPs

    We have two JSPs: the form itself, and a basic (really basic) "thank you" page.

    Code listing: /WEB-INF/form.jsp
    1. <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>  
    2.   
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
    4.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
    5.   
    6. <html xmlns="http://www.w3.org/1999/xhtml">  
    7.     <head>  
    8.         <title>Contact Us</title>  
    9.         <style>  
    10.             .form-item { margin: 20px 0; }  
    11.             .form-label { font-weight: bold; }  
    12.             .form-error-field { background-color: #FFC; }  
    13.             .form-error-message { font-weight: bold; color: #900; }  
    14.         </style>  
    15.     </head>  
    16.     <body>  
    17.       
    18. <h1>Contact Us</h1>  
    19.   
    20. <%-- Give command object a meaningful name instead of using default name, 'command' --%>  
    21. <form:form commandName="userMessage">  
    22.     <div class="form-item">  
    23.         <div class="form-label">Your name:</div>  
    24.         <form:input path="name" size="40" cssErrorClass="form-error-field"/>  
    25.         <div class="form-error-message"><form:errors path="name"/></div>  
    26.     </div>  
    27.     <div class="form-item">  
    28.         <div class="form-label">Your e-mail address:</div>  
    29.         <form:input path="email" size="40" cssErrorClass="form-error-field"/>  
    30.         <div class="form-error-message"><form:errors path="email"/></div>  
    31.     </div>  
    32.     <div class="form-item">  
    33.         <div class="form-label">Your message:</div>  
    34.         <form:textarea path="text" rows="12" cols="60" cssErrorClass="form-error-field"/>  
    35.         <div class="form-error-message"><form:errors path="text"/></div>  
    36.     </div>  
    37.     <div class="form-item">  
    38.         <input type="submit" value="Submit" />  
    39.     </div>  
    40. </form:form>  
    41.   
    42.     </body>  
    43. </html>  

    This is just a standard Spring WebMVC form, so I'll invoke my "I assume you know Spring WebMVC" assumption here. The cssErrorClass attribute is kind of fun if you don't already know about it. It indicates the CSS class to use in the event of a validation error. You can combine that with the cssClass attribute (which applies in the non-error case) though I haven't done that here.

    Now here's the basic "thank you" page:

    Code listing: /WEB-INF/thanks.jsp
    1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
    2.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
    3.   
    4. <html xmlns="http://www.w3.org/1999/xhtml">  
    5.     <head>  
    6.         <title>Thank You</title>  
    7.     </head>  
    8.     <body>  
    9.         <h1>Thank You</h1>  
    10.     </body>  
    11. </html>  

    (I told you it was basic...)

    OK, now we're ready to move onto application configuration. Almost done!

    Servlet and Spring Configuration

    Here's our completely standard web.xml:

    Code listing: /WEB-INF/web.xml
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
    5.         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
    6.     version="2.5">  
    7.       
    8.     <servlet>  
    9.         <servlet-name>contact</servlet-name>  
    10.         <servlet-class>  
    11.             org.springframework.web.servlet.DispatcherServlet  
    12.         </servlet-class>  
    13.     </servlet>  
    14.       
    15.     <servlet-mapping>  
    16.         <servlet-name>contact</servlet-name>  
    17.         <url-pattern>/contact/*</url-pattern>  
    18.     </servlet-mapping>          
    19. </web-app>  

    Though I said I'm assuming you already know Spring WebMVC, I'll just point out that since I didn't specify a custom location for the application context file, I have to put it at /WEB-INF/contact-servlet.xml. If you want the file to live elsewhere, or if you want it to be associated with the servlet context instead of the DispatcherServlet, you'll have to set that up in web.xml accordingly.

    Here's the Spring application context:

    Code listing: /WEB-INF/contact-servlet.xml
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:context="http://www.springframework.org/schema/context"  
    4.     xmlns:p="http://www.springframework.org/schema/p"  
    5.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    6.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    7.         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
    8.         http://www.springframework.org/schema/context  
    9.         http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
    10.       
    11.     <!-- Enable annotation-based validation using Bean Validation Framework -->  
    12.     <!-- Using these instead of vld namespace to prevent Eclipse from complaining -->  
    13.     <bean id="configurationLoader"  
    14.         class="org.springmodules.validation.bean.conf.loader.annotation  
    15. .AnnotationBeanValidationConfigurationLoader"/>  
    16.     <bean id="validator" class="org.springmodules.validation.bean.BeanValidator"  
    17.         p:configurationLoader-ref="configurationLoader"/>  
    18.       
    19.     <!-- Load messages -->  
    20.     <bean id="messageSource"  
    21.         class="org.springframework.context.support.ResourceBundleMessageSource"  
    22.         p:basenames="errors"/>  
    23.   
    24.     <!-- Discover POJO @Components -->  
    25.     <!-- These automatically register an AutowiredAnnotationBeanPostProcessor -->  
    26.     <context:component-scan base-package="contact"/>  
    27.       
    28.     <!-- Map logical view names to physical views -->  
    29.     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"  
    30.         p:prefix="/WEB-INF/"  
    31.         p:suffix=".jsp"/>  
    32. </beans>  

    (IMPORTANT: In the configurationLoader definition, make sure you put the class name on a single line. I had to break it up for formatting purposes.)

    If you're not familiar with it, I'm using the p namespace here for syntactic sugar—it allows me to specify properties using a nice shorthand.

    The first two beans basically create the BeanValidator instance we're going to use. It turns out that instead of defining these two beans explicitly, you can use a special element from a special namespace:

    • namespace is xmlns:vld="http://www.springmodules.org/validation/bean/validator";
    • purported schema location is http://www.springmodules.org/validation/bean/validator-2.0.xsd;
    • element is <vld:annotation-based-validator id="validator"/>

    But when I do it, Eclipse complains (even though the code works when you run it) since there isn't at the time of this writing actually an XSD at the specified location. (At least there's a JIRA ticket for it.) So I'll just use the two beans for now.

    The other stuff is mostly normal Spring WebMVC stuff. I put the message source on the app context, scan for the controller (which is why I'm autowiring the validator into the controller), and put a view resolver on the context too.

    Finis

    Build and deploy your WAR, and then point your browser to your web app; for example:

    http://localhost:8080/contact-example/contact/form

    Try submitting the form with empty fields, or an invalid e-mail address, or fields that are too long. If things are working correctly, you ought to see error messages and even field highlighting when validation fails.

    And that, my friends, is it! Feel free to post a comment if you run into problems getting it to work and I'll try to help if I can.

    Again, if you want to download the sample code (minus dependencies; see above), here it is:

    Have fun!

    posted on 2009-10-21 23:19 seal 閱讀(1577) 評論(0)  編輯  收藏 所屬分類: Spring
    主站蜘蛛池模板: 91亚洲精品自在在线观看| 国内一级一级毛片a免费| 亚洲男人天堂2022| 亚洲av一本岛在线播放| 国产人在线成免费视频| 亚洲人成色7777在线观看| 亚洲不卡1卡2卡三卡2021麻豆| 久久久久av无码免费网| 亚洲资源最新版在线观看| 91免费精品国自产拍在线不卡| 光棍天堂免费手机观看在线观看| 国产日韩在线视频免费播放| 欧洲精品99毛片免费高清观看 | 日韩午夜免费视频| 亚洲精品女同中文字幕| 亚洲?V无码乱码国产精品| 免费精品视频在线| 亚洲精品无码久久一线| 热re99久久6国产精品免费| 亚洲国产成a人v在线| 日本视频免费在线| a级毛片免费高清视频| 久久久久亚洲精品美女| 美女视频黄是免费的网址| 国产成人人综合亚洲欧美丁香花 | 久久久久国产免费| 国产成人精品日本亚洲直接| 国产hs免费高清在线观看| 99re8这里有精品热视频免费| 亚洲精品成人网站在线播放| 最近的免费中文字幕视频| 一级特黄色毛片免费看| 亚洲首页在线观看| 国产免费人人看大香伊| 成人爽a毛片免费| 亚洲高清视频在线| 亚洲情综合五月天| 最近高清国语中文在线观看免费| 在线播放国产不卡免费视频| 亚洲精品日韩专区silk| 国产一级一片免费播放|