Using Spring MVC in the Sample Application

We tried to use all technologies described in this chapter in the SpringBlog application, and in this section, we show the most interesting implementation details.

We start the implementation discussion with the URL mappings. To map the request URLs to the controllers in our application, we use a single SimpleUrlHandlerMapping bean. This bean maps all *.html and *.tile requests to the appropriate controller. The bean definition is shown in Listing 17-37, and as you can see, it is not too much different from the code presented in the "Using Handler Mappings" section earlier in this chapter.

Listing 17-37: urlMapping Bean Definition

image from book
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"      "http://www.springframework.org/dtd/spring-beans.dtd"> <beans>     <bean bold">urlMapping"           >         <property name="mappings">             <props>                 <!-- Index -->                 <prop key="/index.html">indexController</prop>                 <!-- Entry -->                 <prop key="/entry/view.html">entryController</prop>                 <prop key="/entry/delete.html">entryController</prop>                 <prop key="/entry/edit.html">editEntryFormController</prop>                 <!-- Comment -->                 <prop key="/comment/index.html">commentController</prop>                 <prop key="/comment/delete.html">commentController</prop>                 <prop key="/comment/view.html">commentController</prop>                 <prop key="/comment/edit.html">editCommentFormController</prop>                 <!-- Audit -->                 <prop key="/admin/audit/*">auditController</prop>                 <!-- Tiles -->                 <prop key="/tiles/menu.html">menuTileController</prop>                 <!-- Users -->                 <prop key="/admin/users/index.html">usersController</prop>                 <!-- Login -->                 <prop key="/security/login.html">loginController</prop>                 <!-- Attachments -->                 <prop key="/attachment/*">attachmentController</prop>             </props>         </property>     </bean> </beans>
image from book

To support localized validation messages and messages in general, we configure a ResourceBundleMessageSource bean. We chose this implementation over ReloadableResourceBundleMessageSource because we did not need to reload the messages in the lifecycle of the application. The definition of the messageSource bean is shown in Listing 17-38.

Listing 17-38: messageSource Bean Definition

image from book
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"      "http://www.springframework.org/dtd/spring-beans.dtd"> <beans>     <bean           >         <property name="basename">             <value>messages</value>         </property>     </bean> </beans>
image from book

Here, we created two messages properties files: one for the Czech language stored in the messages_cs.properties and one in messages.properties, which contains the text in English and also represents the fallback properties file.

To use messageSource and to make sure the blog entries are valid before we pass them to the Business Tier, we implement CommentValidator and EntryValidator. These validators are a standard implementation; the only interesting point to consider is the implementation of the supports() method, which we show in Listing 17-39.

Listing 17-39: CommentValidator Implementation

image from book
package com.apress.prospring.business.validators;      import org.springframework.validation.Errors; import org.springframework.validation.Validator;      import com.apress.prospring.domain.Comment;      public class CommentValidator implements Validator {          public boolean supports(Class clazz) {         return Comment.class.isAssignableFrom(clazz);         // return clazz.isAssignableFrom(Comment.class);     }          public void validate(Object obj, Errors errors) {         Comment comment = (Comment)obj;         if (comment.getSubject() == null || comment.getSubject().length() == 0) {             errors.rejectValue("subject", "required", null, "required");         }         if (comment.getBody() == null || comment.getBody().length() == 0) {             errors.rejectValue("body", "required", null, "required");         }     }      }  
image from book

We implemented the supports() method using Comment.class.isAssignableFrom(clazz) because we had to create a subclass of the Comment domain class to support the uploading of the attachments. We defined the validators as regular Spring beans, and the controllers that require validation simply reference the validator beans, as shown in Listing 17-40.

Listing 17-40: Validator Beans and Their Usage

image from book
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"      "http://www.springframework.org/dtd/spring-beans.dtd"> <beans>     <bean bold">commentValidator"          />     <bean           >         <property name="blogManager"><ref bean="blogManager"/></property>         <property name="validator"><ref local="commentValidator"/></property>     </bean>          <bean bold">entryValidator"          />     <bean           >         <property name="blogManager"><ref bean="blogManager"/></property>         <property name="validator"><ref local="entryValidator"/></property>     </bean> </beans>
image from book

The implementation of the controllers in the application is not different from the sample code offered in the "Working with Controllers" section earlier in this chapter. However, here we create a set of convenience classes that give their subclasses access to the blogManager property. The convenience classes we implement are the AbstractBlogManagerController, AbstractBlogManagerFormController, and AbstractBlogManagerMultiactionController. All these abstract classes implement the InitializingBean interface to make sure that the blogManager property is set to an instance of the BlogManager implementation; moreover, the AbstractBlogManagerController is not a subclass of AbstractController, it just implements the Controller interface, making the class much more lightweight.

Typical usage of the AbstractBlogManagerMultiactionController is shown in Listing 17-41.

Listing 17-41: Typical Usage of AbstractBlogManagerMultiactionController

image from book
package com.apress.prospring.web.entry;      import java.util.HashMap; import java.util.Map;      import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;      import org.springframework.web.bind.RequestUtils; import org.springframework.web.servlet.ModelAndView;      import com.apress.prospring.domain.Entry; import com.apress.prospring.web.AbstractBlogManagerMultiactionController; import com.apress.prospring.web.security.SessionSecurityManager;      public class EntryController extends AbstractBlogManagerMultiactionController {          public ModelAndView handleView(HttpServletRequest request,          HttpServletResponse response) throws Exception {         int entryId = RequestUtils.getRequiredIntParameter(request, "entryId");         Entry e = getBlogManager().getEntry(entryId);         Map model = new HashMap();         model.put("entry", e);         return new ModelAndView("entry-view", model);     }          public ModelAndView handleDelete(HttpServletRequest request,          HttpServletResponse response) throws Exception {         boolean confirm = RequestUtils.getIntParameter(request, "confirm", 0) == 1;         int entryId = RequestUtils.getRequiredIntParameter(request, "entryId");         if (confirm) {             getBlogManager().deleteEntry(entryId,                  SessionSecurityManager.getUser(request));             return new ModelAndView("entry-deleted");         } else {             Map model = new HashMap();             model.put("entry", getBlogManager().getEntry(entryId));             return new ModelAndView("entry-delete", model);         }     } } 
image from book

Notice that you do not need to implement the InitializingBean interface to make sure that the required properties are set. In fact, the afterPropertiesSet() is implemented as final, which actually prevents the subclasses from providing their own implementation.

We do not implement any security the way you would expect in standard web applications. Instead, we create the SessionSecurityManager class that contains static methods that perform just a very basic support for retrieving user identities. To extend the security code a bit further to make sure it actually restricts the actions that require a user to be logged in, you can implement a HandlerInterceptor, that makes sure the User domain object is set in the session and redirect it to a login page if this is not the case. To allow some of the URLs to be accessible without the user being logged in, you split the urlMapping bean into two beans. One contains the mappings with no restrictions, and the other contains the HandlerInterceptor implementation and the mappings that require a user to be logged in.

For view technologies, we use JSP pages to render the output returned to the client and we use Tiles to aggregate the output of the JSP pages into the final page layout. A more detailed discussion of the Tiles framework and other view technologies follows in Chapter 18.



Pro Spring
Pro Spring
ISBN: 1590594614
EAN: 2147483647
Year: 2006
Pages: 189

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net