I ultimately decided to create a controller-chain structure for these sorts of issues. Basically, we create a parent controller that has a mapping for URI's that trail off the parent controller, then have logic in that mapping to forward to another controller to handle the delegated functionality (passing along the resolved parent domain object in the model that is forwarded to the "subcontext" controller). In this way, the logic of the parent domain (for instance, mapping User objects in the below sample) lives in just one place, but that place isn't muddied up by logic for all of the related types of data.
For example, here's a skeleton of structures that would be able to handle the URL "/user/my-id" in a parent User controller, and also intercept the URL's "/user/my-id/blogs" and "/user/my-id/blogs/a-blog-id" at the parent User controller but then forward along the request to a subcontext "Blogs" controller to handle blog-related issues:
Sample Controller
Code:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/{id}")
public ModelAndView getUser(@PathVariable("id") String id) {
...
}
@RequestMapping("/{id}/{subcontext}/**")
public String redirectToSubcontext(@PathVariable("id") String id, @PathVariable("subcontext") String subcontext, Model model, HttpServletRequest request) {
User user = userServiceDelegate.getUserByIdOrProfileUri(id);
model.addAttribute("user", user);
String forwardUrl = forwardFactory.forSlugInUri(subcontext, request.getRequestURI());
return forwardUrl;
}
}
Forward Factory
Code:
public class ForwardFactory {
public String forSlugInUri(String slug, String uri) {
int slugIndex = uri.indexOf(slug);
String forwardMapping = slugIndex != -1 ? uri.substring(slugIndex) : "";
return "forward:/" + forwardMapping;
}
}
Sample Subcontext Controller
Code:
@Controller
@RequestMapping("/blogs")
public class UserBlogsController {
@RequestMapping
public ModelAndView getAllBlogs(@ModelAttribute("user") User user) {
...
}
@RequestMapping("/{id}") {
public ModelAndView getBlog(@ModelAttribute("user") User user, @PathVariable("id") String id) {
...
}
}