How do I map Spring MVC controller to a uri with and without trailing slash?

Viewed 38869

I have a Spring Controller with several RequestMappings for different URIs. My servlet is "ui". The servlet's base URI only works with a trailing slash. I would like my users to not have to enter the trailing slash.

This URI works:

http://localhost/myapp/ui/

This one does not:

http://localhost/myapp/ui

It gives me a HTTP Status 404 message.

The servlet and mapping from my web.xml are:

<servlet>
    <servlet-name>ui</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>ui</servlet-name>
    <url-pattern>/ui/*</url-pattern>
</servlet-mapping>    

My Controller:

@Controller
public class UiRootController {

    @RequestMapping(value={"","/"})
    public ModelAndView mainPage() { 
        DataModel model = initModel();
        model.setView("intro");     
        return new ModelAndView("main", "model", model);
    }

    @RequestMapping(value={"/other"})
    public ModelAndView otherPage() { 
        DataModel model = initModel();
        model.setView("otherPage");     
        return new ModelAndView("other", "model", model);
    }

}
7 Answers

Not sure if this is the ideal approach, but what worked for me was to treat them as if they were two different paths and make them both accepted by each of my endpoints, such as.

@RestController
@RequestMapping("/api/mb/actor")
public class ActorController {

@GetMapping({"", "/"})
public ResponseEntity<Object> getAllActors() {

    ...
}

@GetMapping({"/{actorId}", "/{actorId}/"})
public ResponseEntity<Object> getActor(@PathVariable UUID actorId) {

    ...
}

There may be best ways to do this and to avoid this duplication, and I'd love to know that. However, what I found when I tried using configurer.setUseTrailingSlashMatch(true); is that broken paths also start becoming accepted, such as /api/mb////actor (with many slashs), and that's why I ended up going the multiple paths instead.

Related