<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 閱讀(1579) 評論(0)  編輯  收藏 所屬分類: Spring
    主站蜘蛛池模板: 亚洲精品无码你懂的网站| 成人毛片视频免费网站观看| 亚洲女同成人AⅤ人片在线观看| 亚洲va中文字幕| 麻豆国产VA免费精品高清在线| 亚洲国产电影在线观看| 最近最新高清免费中文字幕| 久久精品国产亚洲AV网站| 免费观看91视频| 亚洲综合久久综合激情久久 | 亚洲日本国产乱码va在线观看| 久久久久久久99精品免费| 亚洲AV无码久久| 免费A级毛片无码A∨免费| 亚洲精品国产精品国自产网站 | 亚洲中文字幕一区精品自拍| 最近2019中文字幕免费看最新| 亚洲精华国产精华精华液好用| 国产精品四虎在线观看免费 | 在线观看人成视频免费无遮挡| 久久亚洲高清观看| 五月婷婷在线免费观看| 456亚洲人成影院在线观| 国产精品色午夜视频免费看| 国产免费伦精品一区二区三区| 久久久亚洲AV波多野结衣| 久久久久久久久免费看无码| 国产精品亚洲精品日韩动图| 亚洲综合色视频在线观看| 男人进去女人爽免费视频国产| 亚洲另类图片另类电影| 免费乱理伦在线播放| 最新久久免费视频| 亚洲伊人色一综合网| mm1313亚洲精品无码又大又粗| 久久精品视频免费| 亚洲精品无码你懂的| 亚洲中文字幕在线乱码| 国产情侣激情在线视频免费看| 国产亚洲精品成人久久网站| 亚洲AV美女一区二区三区|