<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
    主站蜘蛛池模板: 亚洲国产综合AV在线观看| 精品亚洲麻豆1区2区3区| 久久精品国产亚洲AV天海翼| 免费人成在线视频| 亚洲精品国产日韩| 国产色爽女小说免费看| 337P日本欧洲亚洲大胆精品| 国产一级一片免费播放| 五月天婷婷免费视频| 中文字幕精品亚洲无线码二区 | 亚洲精品影院久久久久久| 亚洲免费在线视频| 亚洲国产成人久久99精品| 亚洲AV日韩精品久久久久久| 一级毛片在线观看免费| 亚洲AV色吊丝无码| 少妇亚洲免费精品| 鲁丝片一区二区三区免费| 亚洲国产综合自在线另类| 韩国日本好看电影免费看| 一边摸一边桶一边脱免费视频| 亚洲国产精品无码成人片久久| 69视频在线观看高清免费| 亚洲人成色99999在线观看| 亚洲国产成人久久综合碰| 国产自国产自愉自愉免费24区| 久久精品国产亚洲AV高清热| 免费观看男人免费桶女人视频 | 日韩亚洲人成在线| 亚洲毛片不卡av在线播放一区| 在线播放免费人成毛片乱码| 亚洲a级片在线观看| 亚洲日韩在线观看| 97碰公开在线观看免费视频| 日韩在线观看免费| 亚洲精品在线网站| 久久久精品国产亚洲成人满18免费网站 | 成年女人毛片免费播放人| 精品多毛少妇人妻AV免费久久| 亚洲国产成人精品电影| 亚洲日韩VA无码中文字幕|