22
votes

I am writing a web application using Spring MVC. I am using annotations for the controllers, etc. Everything is working fine, except when it comes to actual links in the application (form actions, <a> tags, etc.) Current, I have this (obviously abbreviated):

//In the controller
@RequestMapping(value="/admin/listPeople", method=RequestMethod.GET)

//In the JSP
<a href="/admin/listPeople">Go to People List</a>

When I directly enter the URL like "http://localhost:8080/MyApp/admin/listPeople", the page loads correctly. However, the link above does not work. It looses the application name "MyApp".

Does anyone know if there is a way to configure Spring to throw on the application name on there?

Let me know if you need to see any of my Spring configuration. I am using the standard dispatcher servlet with a view resolver, etc.

7
This is possible in spring 3.0 with <a href="<spring:url value="/admin/listPeople"/>">People</a>tterrace

7 Answers

50
votes

You need to prepend context path to your links.

// somewhere on the top of your JSP
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>

...
<a href="${contextPath}/admin/listPeople">Go to People List</a>
14
votes

The c:url tag will append the context path to your URL. For example:

<c:url value="/admin/listPeople"/>

Alternately, I prefer to use relative URLs as much as possible in my Spring MVC apps as well. So if the page is at /MyApp/index, the link <a href="admin/listPeople"> will take me to the listPeople page.

This also works if you are deeper in the URL hierarchy. You can use the .. to traverse back up a level. So on the page at/MyApp/admin/people/aPerson, using <a href="../listPeople"> will like back to the list page

6
votes

I prefer to use BASE tag:

<base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" />

Then, all your links can be like:

<a href="admin/listPeople">Go to People List</a>
4
votes

As i have just been trying to find the answer to this question and this is the first google result.

This can be done now using the MvcUriComponentsBuilder

This is part of the 4.0 version of Spring MVC

http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.html

The method needed is fromMappingName

From the documentation :

Create a URL from the name of a Spring MVC controller method's request mapping. The configured HandlerMethodMappingNamingStrategy determines the names of controller method request mappings at startup. By default all mappings are assigned a name based on the capital letters of the class name, followed by "#" as separator, and then the method name. For example "PC#getPerson" for a class named PersonController with method getPerson. In case the naming convention does not produce unique results, an explicit name may be assigned through the name attribute of the @RequestMapping annotation.

This is aimed primarily for use in view rendering technologies and EL expressions. The Spring URL tag library registers this method as a function called "mvcUrl".

For example, given this controller:

@RequestMapping("/people")
 class PersonController {

   @RequestMapping("/{id}")
   public HttpEntity getPerson(@PathVariable String id) { ... }

 }

A JSP can prepare a URL to the controller method as follows:

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>

 <a href="${s:mvcUrl('PC#getPerson').arg(0,"123").build()}">Get Person</a>
0
votes

I usually configure tomcat to use context root of "/" or deploy the war as ROOT.war. Either way the war name does not become part of the URL.

0
votes

You could use a servletRelativeAction. I'm not sure what versions this is available in (I'm using 4.0.x currently) and I haven't seen much documentation on this, but if you look at the code backing the spring form you can probably guess. Just make sure the path you pass it starts with a "/".

Example:

<form:form class="form-horizontal" name="form" servletRelativeAction="/j_spring_security_check"  method="POST">

See org.springframework.web.servlet.tags.form.FormTag:

protected String resolveAction() throws JspException {
    String action = getAction();
    String servletRelativeAction = getServletRelativeAction();
    if (StringUtils.hasText(action)) {
        action = getDisplayString(evaluate(ACTION_ATTRIBUTE, action));
        return processAction(action);
    }
    else if (StringUtils.hasText(servletRelativeAction)) {
        String pathToServlet = getRequestContext().getPathToServlet();
        if (servletRelativeAction.startsWith("/") && !servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
            servletRelativeAction = pathToServlet + servletRelativeAction;
        }
        servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
        return processAction(servletRelativeAction);
    }
    else {
        String requestUri = getRequestContext().getRequestUri();
        ServletResponse response = this.pageContext.getResponse();
        if (response instanceof HttpServletResponse) {
            requestUri = ((HttpServletResponse) response).encodeURL(requestUri);
            String queryString = getRequestContext().getQueryString();
            if (StringUtils.hasText(queryString)) {
                requestUri += "?" + HtmlUtils.htmlEscape(queryString);
            }
        }
        if (StringUtils.hasText(requestUri)) {
            return processAction(requestUri);
        }
        else {
            throw new IllegalArgumentException("Attribute 'action' is required. " +
                    "Attempted to resolve against current request URI but request URI was null.");
        }
    }
}
-1
votes

Since it's been some years I thought I'd chip in for others looking for this. If you are using annotations and have a controller action like this for instance:

@RequestMapping("/new")   //<--- relative url
public ModelAndView newConsultant() {
    ModelAndView mv = new ModelAndView("new_consultant");
    try {
        List<Consultant> list = ConsultantDAO.getConsultants();
        mv.addObject("consultants", list);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return mv;
}

in your .jsp (view) you add this directive

<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>

and simply use

<spring:url value="/new" var="url" htmlEscape="true"/>
<a href="${url}">New consultant</a>

where

value's value should match @RequestMapping's argument in the controller action and

var's value is the name of the variable you use for href

HIH