views:

233

answers:

4

I'm mapping the url /modules/tips/SOME_ID/small to access the tip with id SOME_ID and to render it using the view small.jsp. The following code works great for this, however I am forced to repeat the string modules/tips in two places. Spring MVC doesn't seem to have a convention for this that I can determine. Other than using a constant, is there a better way to reduce this repetition?

@Controller
public class TipsController{

  @RequestMapping(value="/modules/tips/{tipId}/{viewName}",method=RequestMethod.GET)
  public ModelAndView get(
    @PathVariable String tipId,
    @PathVariable String viewName) {
    Tip tip = findTip(tipId);
    return new ModelAndView("modules/tips/" + viewName,"tip",tip);
  }
}
A: 

You can put a @requestMappings annotation on your class. The @requestMapping annotations on methods are then relative to this:

@Controller
@RequestMapping(value="/modules/tips")
public class TipsController{

    @RequestMapping(value="{tipId}/{viewName}",method=RequestMethod.GET)
    public ModelAndView get(
        @PathVariable String tipId,
        @PathVariable String viewName) {
        Tip tip = findTip(tipId);
        return new ModelAndView("modules/tips/" + viewName,"tip",tip);
    }
}
darren
This solution doesn't reduce the need to repeat the string "modules/tips" twice. It would only reduce the need if I had more than one method, which I don't in this example
davetron5000
+1  A: 

You view name mapping logic looks too "custom", so Spring hardly can offer some build-in support for it. Hovewer, as a theoretical possibility, you can implement a custom ModelAndViewResolver and register it in the AnnotationMethodHandlerAdapter

axtavt
Initially, I omitted the {viewName} and had my method return void. Spring then uses the last path element unmapped as the view name, however it looked in the root of my JSP hierarchy, which makes no sense to me. I suppose that is my real problem; I want a parallel structure between paths and view locations if at-all possible
davetron5000
Spring does not provide the functionality, but I back the idea of axtavt
Teja Kantamneni
A: 

You can do what you're trying to do by simply omitting the view name, as long as your views match up with your URLs. If you don't provide a view name, Spring will use a RequestToViewNameTranslator to try to figure out a view name. You can look at the source for that class to see exactly how it work. Here's a good quote from the docs:

"... a request URL of 'http://localhost/registration.html' will result in a logical view name of 'registration' being generated by the DefaultRequestToViewNameTranslator. This logical view name will then be resolved into the '/WEB-INF/jsp/registration.jsp' view by the InternalResourceViewResolver bean."

So it could, for example, make it so that a controller method handling "/modules/tips" would by default try to use a view named "modules/tips", presumably you would have a JSP at "/WEB-INF/jsp/modules/tips.jsp".

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-coc-r2vnt

EDIT: I just noticed that you said you tried omitting the view name, and it didn't seem like that worked. You could always write your own implementation of the RequestToViewNameTranslator and replace the DefaultRequestToViewNameTranslator with your own custom implentation. Check the docs for how to inject your own translator.

sdouglass
A: 

If you change your <url-pattern> element in web.xml to include modules/tips, you can effectively omit it from all of your Spring binding configuration:

<servlet-mapping>
        <servlet-name>spring-mvc</servlet-name>
        <url-pattern>/myapp/modules/tips/*</url-pattern>
</servlet-mapping>


@RequestMapping(value="/{tipId}/{viewName}",method=RequestMethod.GET)
public ModelAndView get(
    @PathVariable String tipId,
    @PathVariable String viewName) {
    Tip tip = findTip(tipId);
    return new ModelAndView(viewName,"tip",tip);
}
James Earl Douglas