Announcement Announcement Module
No announcement yet.
Method level RequestMapping annotations for more REST style actions Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Method level RequestMapping annotations for more REST style actions

    I'm toying with annotation driven controller configuration and I really, really like it.

    Now I just have one issue: I'd like to be able to have more (g)rails like URLs with the pattern /controller/action[/id] but that doesn't seem to be possible as I don't seem to be able to specify a pattern like "action/*" in the method level RequestMapping annotation. If I do, that method never gets mapped. Is there a simple solution to that short of writing my own variant of org.springframework.web.servlet.mvc.annotation.Ann otationMethodHandlerAdapter (which somehow seems like a bad idea) and isn't that something that would be more generally useful?

    Any suggestions would be greatly appreciated.


  • #2
    I'm able to do this and it works fine mapping all html requests (below). Have you tried putting two asterisks instead of just one? I also jus tried "/delete/*" and "/delete/**" and they both intercepted a "/delete/person.html?id=1" request.

    Have you tried "/**/action/*"?



    • #3
      I actually just tried "/**/action/*" in a webapp I have setup already and seemed like it was working ok. It intercepted '/action/person.html', '/foo/bar/action/person.html', '/foo/bar/action/12', etc.


      • #4
        Thanks David! That's good news - but I actually think now that the controller mapping is the problem. I've always tried with relative paths at the method level RequestMapping and mapping the controller at the type level and it seems that then it doesn't work. Will need to further test that.



        • #5

          OK, it was my fault. The mappings didn't work becuase I didn't explicity add org.springframework.web.servlet.mvc.annotation.Def aultAnnotationHandlerMapping as a bean in my context but inadvertently added a org.springframework.web.servlet.mvc.annotation.Ann otationMethodHandlerAdapter bean instead which kind of made it work half.

          Now if only I wouldn't need to specify '/**/action/*' at th emethod level but 'action/*' I would be in heaven ...


          • #6
            sample code to extract id from url

            Just if anybody else cares: I've created a little interceptor to extract ids from the URL in REST style URLs following the pattern /controller/action/id. It's not tested production quality code but maybe somebody else can draw some inspiration from it.

            I have a dispatcher servlet context that looks something like this

            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="" xmlns:xsi="" xmlns:context=""
            	<bean id="handlerMappingTemplate" abstract="true">
            		<property name="interceptors">
            				<bean class="some.package.IdFromUrlInterceptor" />
            	<bean class="" parent="handlerMappingTemplate" />
            	<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" parent="handlerMappingTemplate" />
            			<context:component-scan base-package="some.package.controllers" />

            and the interceptor looks like this

            package some.package;
            import java.lang.reflect.Method;
            import java.util.Map;
            import java.util.regex.Matcher;
            import java.util.regex.Pattern;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import org.springframework.core.CollectionFactory;
            import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
             * Interceptor that tries to read an id value from URLs of the pattern /controller/action/id and tries to then set
             * the read value on the passed in handler (generally a Controller class) by calling a method with the signature setId(String id) if existent.
             * @author joerg
            public class IdFromUrlInterceptor extends HandlerInterceptorAdapter
                private final Map<String, Method> handlerMethodCache = CollectionFactory.createConcurrentMapIfPossible(16);
                private final static Pattern idPattern = Pattern.compile("^/(\\S*)/(\\S*)/(\\S*)");
                public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
                    Matcher matcher = idPattern.matcher(request.getPathInfo());
                    if (matcher.matches())
                            Method idSetter;
                            if (handlerMethodCache.containsKey(handler.getClass().getName()))
                                idSetter = handlerMethodCache.get(handler.getClass().getName());
                                idSetter = handler.getClass().getMethod("setId", new Class[]{String.class});
                                handlerMethodCache.put(handler.getClass().getName(), idSetter);
                            if (idSetter != null)
                                idSetter.invoke(handler, new Object[]{});
                        catch (Exception e)
                    return true;
            You can then write a controller like this

            public class TestController
                private String id;
                public String getId()
                    return id;
                public void setId(String id)
           = id;
                public ModelAndView hello(HttpServletRequest request, HttpServletResponse response) throws Exception
                    System.out.println("id: " + getId());
                    return new ModelAndView("hello");
            So as long as your controller has a method with the signature void setId(String id) you then should be able to get the extracted id by the time the action is called. Hope this all makes sense.

            If somebody knows of a better way to achieve this please let me know.
            Last edited by joeslow; Jun 10th, 2008, 10:09 AM.