A Grails Plugin for Spring MVC Controllers

I wrote earlier about using Spring MVC controllers in a Grails app. I was looking at that again since I thought it might be useful as a plugin. Unfortunately although it did work at the time, I ended up having to do a lot more work to get it going. I guess some things changed in intermediate Grails releases, and I didn’t save the code. But anyway, it’s working now :)

Installation

To use it in your app, install like any plugin:

grails install-plugin springmvc

The install script will create a web-app/WEB-INF/jsp folder if it doesn’t exist, and copy the sample error.jsp there if it doesn’t exist. It also creates an empty web-app/WEB-INF/SpringMVC-servlet.xml – the file has to exist but all beans are defined by the plugin or in the app’s resources.groovy and/or resources.xml.

Configuration

There are a few configuration options available – all are optional. They’re defined in a springmvc block in Config.groovy:

Name Default Value Description
urlSuffix ‘action’, i.e. *.action the URL pattern for Spring MVC controller URLs
exceptionMappings none Map with exception class names as keys and JSP names as values
defaultErrorView ‘error’, i.e. web-app/WEB-INF/jsp/error.jsp the default error page if there’s no corresponding mapping for the exception class
interceptors none bean names of HandlerInterceptors to apply to Spring MVC URLs

So a configuration block that defines a single interceptor, uses *.action for URLs, and defines a default error JSP and two exeption-specific exception mappings (note that the values for urlSuffix and defaultErrorView are redundant since they’re the default values) would be:

springmvc {
   interceptors = ['loggingInterceptor']
   exceptionMappings = ['java.io.IOException': 'ioexception']
   exceptionMappings = ['com.myapp.MyException': 'myex']
   defaultErrorView = 'error'
   urlSuffix = 'action'
}

Application Beans

Unlike in Grails, there’s no automatic URL mapping. To connect a controller to a URL you define a Spring bean (in resources.groovy or resources.xml) whose name is the url and the bean class is the controller, e.g.:

   '/test.action'(com.burtbeckwith.mvctest.controller.TestController) {
      cacheSeconds = 0
      bookService = ref('bookService')
   }

This will map http://localhost:8080/yourapp/test.action to TestController. Setting cacheSeconds to 0 instructs Spring to send headers to disable caching. And ‘bookService’ is a dependency injection for BookService to access Book domain instances. The controller returns ‘books’ as it’s view name – this is prefixed by ‘/WEB-INF/jsp/’ and suffixed by ‘.jsp’ to define the JSP that will render the response (i.e. ‘/WEB-INF/jsp/books.jsp’).

You can also define HandlerInterceptors in resources.groovy. They should extend HandlerInterceptorAdapter or implement HandlerInterceptor directly. Add their bean names to the ‘interceptors’ list and Spring MVC requests will be intercepted. Note that these interceptors are in addition to the standard Hibernate OSIV interceptor and a locale change interceptor.

For example:

   loggingInterceptor(com.burtbeckwith.mvctest.interceptor.LoggingInterceptor)

Sample App

You can download a sample app here. It’s pretty simple – it has a single domain class, and a single Grails controller and a Spring MVC controller (to test that both work in the same app). There’s a Grails service to access domain instances that implements a Java interface so it’s callable by the MVC controller. There’s also a sample interceptor (it just logs requests) and a sample JSP 2.0 tag file, date.tag.

The app creates six books in Bootstrap – you can see the data by going to http://localhost:8080/mvctest/test.action. Go to http://localhost:8080/mvctest/regular to access a regular Grails controller.

2 Responses to “A Grails Plugin for Spring MVC Controllers”

  1. Graeme Rocher says:

    Hi burt,

    Congrats once again for another useful contribution. It would be awesome if you could document your contributes at http://grails.org/Plugins. Even if it is just copying and pasting the contents you have here in the blog, at least people know where to look for the docs.

    Keep it up!

  2. [...] feature is described by VaanNila and for it’s use in Grails I found this older post by Burt Beckwith [...]

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.