Top 5 enhancements of Spring MVC 3.1
from http://blog.goyello.com/2011/12/16/enhancements-spring-mvc31/
After many months of development, Spring 3.1 has been finally released. The release is shipped with some exciting features like caching abstraction, bean profiles and container configuration simplifications. However, in this blog post I will describe my top 5 enhancements of Spring MVC 3.1.
1. Flash attributes support
Flash attributes are used to store attributes between requests and are used mostly in Post/Redirect/Get pattern. Prior to Spring 3.1 some additional (repeatable) steps were required to utilize flash attributes in Spring MVC based applications:
Create or copy FlashMap object to hold flash attributes
public class FlashMap implements Serializable {
// implementation omitted
}
Create or copy FlashMapFilter to your project
public class FlashMapFilter extends OncePerRequestFilter {
// implementation omitted
}
Include FlashMapFilter in web.xml
Put flash attributes in the controller when needed
@PreAuthorize("hasRole('ROLE_USER')")
@RequestMapping(value = Routing.SOME_ROUTING, method = RequestMethod.POST)
public String processForm(@Valid Form form, BindingResult result) {
// process the form
// ...
// add flash attribute
FlashMap.addAttribute("message", "Form processed");
// redirect
return RoutingHelper.redirect(Routing.SOME_OTHER_ROUTING);
}
With Spring 3.1 flash attributes support is enabled by default. No additional configuration is required. @Controller method accepts the argument of a type RedirectAttributes. RedirectAttributes is an interface that extends from standard Spring MVC Model interface and it may be used to store flash attributes that will be available after the redirection.
@PreAuthorize("hasRole('ROLE_USER')")
@RequestMapping(value = Routing.SOME_ROUTING, method = RequestMethod.POST)
public String processForm(@Valid Form form, BindingResult result, RedirectAttributes redirectAttributes) {
// process the form
// ...
// add flash attribute
redirectAttributes.addFlashAttribute("message", "Form processed");
// redirect
return RoutingHelper.redirect(Routing.SOME_OTHER_ROUTING);
}
2. @Validated annotation with support for JSR-303 validation groups
Spring MVC Bean Validation support has been extended with a new @Validated annotation that provides support of JSR 303 validation groups. A group defines a subset of constraints that is validated for a given object graph. Each constraint declaration may define the group or the list of groups it belongs to.
public class User {
@NotNull
private String name;
@NotNull(groups = { Simple.class })
private String address;
@NotNull(groups = { Simple.class, Extended.class })
private String licenceType;
@NotNull(groups = { Extended.class })
private String creditCard;
}
public interface Simple {
}
public interface Extended {
}
The example usage of the new @Validated annotation is shown in the following example:
@Controller
public class MyController {
@RequestMapping(value = "/user/default", method = RequestMethod.GET)
public String createDefaultUser(@Validated({ Default.class }) User user, BindingResult result) {
if(result.hasErrors()) {
// Validation on 'name'
}
return null;
}
@RequestMapping(value = "/user/simple", method = RequestMethod.GET)
public String createSimpleUser(@Validated({ Simple.class }) User user, BindingResult result) {
if(result.hasErrors()) {
// Validation on 'licenceType' and 'address'
}
return null;
}
@RequestMapping(value = "/user/extended", method = RequestMethod.GET)
public String createExtendedUser(@Validated({ Simple.class, Extended.class }) User user, BindingResult result) {
if(result.hasErrors()) {
// Validation on 'creditCard' and 'licenceType' and 'address'
}
return null;
}
}
The support for validation groups as added to Spring 3.1 is really handy. To read more about validation groups download and read the JSR 303 specification.
3. Support @Valid on @RequestBody method arguments
The @RequestMapping handler methods support @RequestBody annotated parameter for accessing the HTTP request body. The conversion is done through the available message converters, including FormHttpMessageConverter (application/x-www-form-urlencoded), MarshallingHttpMessageConverter (application/xml), MappingJacksonHttpMessageConverter (application/json) and others. But the @RequestBody annotated method argument could not be automatically validated. Manual validation was required:
@Controller
public class MyController {
@Autowired
private Validator validator;
@RequestMapping(value = "", method = RequestMethod.PUT)
@ResponseStatus(value = HttpStatus.CREATED)
@Secured("ROLE_ADMIN")
@Transactional
public void save(@RequestBody User user) {
validate(user);
dao.save(user);
}
private void validate(User user) {
// perfom validation using injected validator
}
}
In Spring 3.1 the @RequestBody method argument can be annotated with @Valid to invoke automatic validation. This makes the code can be simplified:
@Controller
public class MyController {
@RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.CREATED)
@Transactional
public void save(@Valid @RequestBody User user) {
dao.save(user);
}
@ExceptionHandler
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleMethodArgumentNotValidException(
MethodArgumentNotValidException error) {
return "Bad request: " + error.getMessage();
}
}
In the above example, Spring automatically performs the validation and in case of error MethodArgumentNotValidException is thrown. Optional @ExceptionHandler method may be easily created to add custom behavior for handling this type of exception.
4. Supporting PUT request with form encoded data
The limitation of Servlet implementation is that it does not handle the encoded data of the HTTP PUT request properly. Introduction of the new HttpPutFormContentFilter solves that problem. With Spring 3.1 developing a RESTfull or RESTlike API became much simpler. See my previous post to read more about the usage of HttpPutFormContentFilter in a web application.
5. Java based configuration
The xml configuration of a Spring MVC application may be completely replaced by the Java based configuration. The simplest way to configure a web application is to use the @EnableWebMvc annotation:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.example" }, excludeFilters = @Filter(type = FilterType.ANNOTATION, value = Configuration.class))
@Import(PersistanceContextConfiguration.class)
public class ServletContextConfiguration extends WebMvcConfigurerAdapter {
@Bean
public TilesViewResolver configureTilesViewResolver() {
return new TilesViewResolver();
}
@Bean
public TilesConfigurer configureTilesConfigurer() {
TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions(new String[] { "/WEB-INF/tiles/tiles.xml",
"/WEB-INF/views/**/views.xml" });
return configurer;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("login");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/").addResourceLocations(
"/recourses/**");
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Extending from WebMvcConfigurerAdapter is not required, but it allows for the customization of the default Spring MVC configuration. The adapter enables us to register additional components like formatters, converters, custom validators, interceptors etc. This way the custom configuration can be done by Java code only. See my previous post about configuring a Spring MVC application with no xml in a Servlet 3.0 based environment.
Spring MVC 3.1 has a lot to offer
Spring MVC 3.1 brings many enhancements. The features mentioned in this blog post should have a positive impact on the application development with Spring MVC. They are not revolutionary, though. However, when I look at all the Spring features and enhancements shipped within the 3.1 release, I feel that the framework is going in the right direction. The caching abstraction, bean profiles, configuration simplifications and many other core features should allow to develop applications more efficiently.
References:
http://blog.springsource.org/2011/12/13/spring-framework-3-1-goes-ga/
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/new-in-3.1.html
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/