Skip to content

Allow links to @Controller methods from views without hardcoding URLs [SPR-5779] #10449

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue May 22, 2009 · 20 comments
Assignees
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented May 22, 2009

Chris Herron opened SPR-5779 and commented

The various Spring Web tags and template-URI implementation encourage hard-coding of URLs in the view layer.
If I alter a Controller's URL mapping, I need to remember to go and make the corresponding change(s) in my JSPs so that links and forms aren't broken.
If the spring:url and form:form tags were able to accept the FQCN of a controller bean instead of an actual URL, the tag implementation could determine the most appropriate URL mapping, and (if applicable) incorporate any template-URI params / path variables to generate a reliable URL.
By using the the FQCN, we can rely on any modern IDE to locate references during refactoring, instead of requiring additional help from Spring-aware IDE plugins. IMHO this would fit particularly well with Spring 3.0's annotation-based controller configuration.

Stripes supports this approach:
http://stripes.sourceforge.net/docs/current/taglib/stripes/link.html
http://stripes.sourceforge.net/docs/current/taglib/stripes/form.html


Affects: 3.0 M3

Reference URL: http://forum.springsource.org/showthread.php?t=72284

Issue Links:

Referenced from: commits 6b129c5, 9d479fe

32 votes, 29 watchers

@spring-projects-issues
Copy link
Collaborator Author

Chris Herron commented

Oops - meant to say "If the spring:url and form:form tags" in the original description.

@spring-projects-issues
Copy link
Collaborator Author

Dave Syer commented

Fixed the description.

The problem I see is that "determine the most appropriate URL mapping" isn't particularly well posed. How would a JSP tag know which of potentially many URLs were intended? Only really makes sense if there is a way to specify the particular @RequestMapping (except in the special case where a single controller has a single mapping - old style interface driven MVC). I suppose that's what you had in mind?

@spring-projects-issues
Copy link
Collaborator Author

Chris Herron commented

Yes - ideally we could specify both the classname and the targeted method. Then the corresponding @RequestMapping could be identified. You might do this with one or two tag parameters:

<spring:url class="com.foo.UserProfileController" method="view">
   <spring:param name="user.username" value="${user.username}" />
</spring:url>

or

<spring:url target="com.foo.UserProfileController#view" >
   <spring:param name="user.username" value="${user.username}" />
</spring:url>

The equivalent in Stripes:

@UrlBinding("/profile/{$event}/{user.username}/")
public class UserProfileController {
    private User user;
    public Resolution view() { ... );
    public User getUser() { ... };
    public void setUser(User user) { ... };
}
<stripes:link beanclass="com.foo.UserProfileController" event="view">
   <stripes:param name="user.username" value="${user.username}"/>
</stripes:link>

This generates a URL like: http://foo.com/profile/view/johnsmith.

@spring-projects-issues
Copy link
Collaborator Author

Numan Salati commented

+1

grails does this with g:link tag. very useful functionality to have. i am surprised this feature is missing since its a common feature on many web frameworks.

please implement this.

@spring-projects-issues
Copy link
Collaborator Author

Elnur Abdurrakhimov commented

I'd really like to have this functionality. Any progress on this? Or maybe any pointers to existing solutions solving this problem?

@spring-projects-issues
Copy link
Collaborator Author

Elnur Abdurrakhimov commented

I'm trying to switch from the PHP Spring's clone Symfony2 to Spring, because I like Java much more than PHP. Since Symfony2 is a Spring's clone, I thought I'd share a couple of links to its implementation of routes in hope it will help to solve this problem in Spring too. So, here we go:

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Thanks for the links. We're considering some sort of a centralized route mapping configuration for 3.2. This certainly provides a good example including the ability to refer to a specific mapping through an alias.

@spring-projects-issues
Copy link
Collaborator Author

Jari Pennanen commented

Has anyone a idea how to implement this as an JAR?

It sounds like a simple thing to do, I need a way to create Map of all controllers and their Request mappings. (Assuming each controller has at maximum one RequestMapping it is easy, otherwise RequestMappings must be named too).

I've been using Django in the past also a lot. But been yearning for "strongly typed Django", so I seeked for Spring. This would be a killer feature as it would allow to create:

  1. Project specific RequestMappings.
  2. (optionally) Site widely overriding the RequestMapping of certain controllers.

And the urls would just keep working.

@spring-projects-issues
Copy link
Collaborator Author

Brian Clozel commented

I've had the same problem and came up with another solution: https://github.com/bclozel/springmvc-router

@spring-projects-issues
Copy link
Collaborator Author

Jari Pennanen commented

Brian, that's fantastic! And it works today.

Is the package name part of the reversing?

I'm looking at the code:
${route.reverse('userController.listAll')}

Can I do like this instead:
${route.reverse('mypackage.userController.listAll')}

If have several apps, like "Auth" app in a different WAR. Can I reverse it from my other application using ${route.reverse(otherpackage.Auth.AuthController.login)} ? As I'd like to separate all apps, but still being able to access their urls and functions somehow.

@spring-projects-issues
Copy link
Collaborator Author

Brian Clozel commented

Currently the controller name "userController" is based on the bean name created by Spring. I don't know how Spring handles naming when several Controllers have the same classname.

But I guess you can go:

@Controller("auth.MyController") on one,
@Controller("business.MyController") on another one.

@spring-projects-issues
Copy link
Collaborator Author

Brian Clozel commented

Not sure about a "." in a controller bean name: I think it's used as a separator in "controllerName.action".

Maybe?
@Controller("auth-MyController")
@Controller("business-MyController")

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Chris Herron, since @RequestMapping annotations are both type and method level, a method name at least must be specified. That won't work in the general case since method names can be overloaded. Furthermore each annotation can have multiple URL patterns and patterns can contain Ant-style wild cards (e.g. "/foo/\*", "/foo\*Bar", /foo/\*\*/bar"). All of these are challenges for reverse engineering in the general case. However, to make this work some assumptions could be made -- e.g. the method must not be overloaded, the annotation must have only one URL pattern, and the URL pattern must not have any wild cards.

Overall I think the approach would work, if anyone wants to put something together in the form of a pull request. Specific questions, if any, can be posted to the spring-framework-contrib list. I do think this should be a different tag ("spring:requestMappingUrl", "spring:controllerUrl" maybe?) even if internally the UrlTag class is extended.

The springmvc-router project looks very nice also as an alternative to @RequestMapping annotations!

@spring-projects-issues
Copy link
Collaborator Author

Alexander Hawley commented

Asp.Net implementation might be workable.

Many MVC frameworks generate URIs from controller mappings. It closes the loop on referencing a controller action from anywhere: a redirect from controller to controller, link from a view to controller, submit form from view to controller. They can all reference the resource map in the same way.

@spring-projects-issues
Copy link
Collaborator Author

Andy Chang commented

We have been using a form of this internally @ mohchi.com, but it requires a separate annotation (@Action). It supports path variables but perhaps not in the way you'd like it to. It uses an action uri builder to build urls in the view layer. I hope that some elements from our example might help in integrating this functionality into spring:url and @RequestMapping.

The controller:
https://github.com/mohchi/spring-mvc-action-resolver/blob/master/src/main/java/com/mohchi/example/web/controllers/HomePageController.java

The jsp:
https://github.com/mohchi/spring-mvc-action-resolver/blob/master/src/main/webapp/WEB-INF/views/homePage.jsp

That the JSP doesn't have any examples of this, but it also supports fully qualified names, e.g. "com.mohchi.example.web.controller.HomePageController#homePage". However, one limitation is that it doesn't support overloaded controller methods annotated with @Action.

@spring-projects-issues
Copy link
Collaborator Author

Fabien benichou commented

It is à shame that such a popular MVC framework like Spring does not have this mechanism present in many other frameworks (like Grails) and forces you to hardcode your URLs in your code

Why this feature is not a top priority for future releases ?

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Let's put this into the 4.1 bucket to consider potential mechanisms in Spring MVC itself, or at least some enablers for custom policies to be implemented on top of it.

Juergen

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Now that we have MvcUriComponentsBuilder, this is a good one to consider. For example based on the fromMethodName method.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

I've created a proposal to address this. For anyone interested, you can try it with 4.1.0.BUILD-SNAPSHOT (repo.spring.io/snapshot).

For an overview and sample usage, see the javadoc of MvcUriComponentsBuilder.fromMappingName.

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Modified title (was "Add "controller class name" attribute to spring:url and form:form tags")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants