Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an JSTL EL (Expression Language) Equivalent to <c:url/>

Tags:

jsp

jstl

el

We use the tomcat urlrewrite plugin to rewrite outbound URLs as well as inbound ones. To do this, you need to use the JSTL tag.

This works great for clean urls and i18n, however it yields ugly code, including tags-within-tags, like this:

<link href='<c:url value="/content/bootstrap/css/bootstrap.css" />' rel="stylesheet" />

or:

<a href='<c:url value="/nextPage.jsp"/>' />Next Page</a>

One alternative is to use a variable, like this:

<c:url value="/nextPage.jsp" var="nextPageUrl"/>
<a href='${nextPageUrl}' />Next Page</a>

This is really clean, but verbose.

Is there an expression-language friendly way to do this?

I was sort of hoping for something like:

<a href='${url "/nextPage.jsp}' />Next Page</a>

Thanks.

like image 587
JBCP Avatar asked May 31 '12 19:05

JBCP


2 Answers

There is nothing out of the box, but nothing prevents you to write your own EL functions, and thus use something like that:

<a href='${myFn:url("/nextPage.jsp")}' />Next Page</a>

I don't feel that it's more readable than the standard c:url tag, and it would be even worse if it has to accept parameter names and values, though.

See http://docs.oracle.com/javaee/1.4/tutorial/doc/JSPIntro7.html for how to define and use EL functions.

like image 128
JB Nizet Avatar answered Jan 02 '23 10:01

JB Nizet


Where are several approaches.

1) Bind base to variable in common fragment:

common.jspf:

<%@tag language="java" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:url value="/" var="base"/>

or like:

<c:set var="base" value="${pageContext.request.contextPath}"/>

and include fragment in each page:

<%@include file="base.jspf"%>
<script src="${base}/js/jquery.js"></script>
<link href="${base}/css/bootstrap.css" rel="stylesheet" type="text/css">
<a href="${base}/index.html">Home</a>

2) Use ${pageContext.request.contextPath} everywhere:

<script src="${pageContext.request.contextPath}/js/jquery.js"></script>
<link href="${pageContext.request.contextPath}/css/bootstrap.css" rel="stylesheet" type="text/css">
<a href="${pageContext.request.contextPath}/index.html">Home</a>

3) is my favorite: add filter that include base for attribute:

/src/java/company/project/web/filter/BaseFilter.java

import java.io.IOException;
import javax.servlet.*;

/**
 * Make sane JSP, instead of:
 *   <pre>&lt;a href="&lt;c:url value='/my/path/${id}.html'/&gt;"&gt;Title&lt;/a&gt;</pre>
 * allow to use:
 *   <pre>&lt;a href="${ctx}/my/path/${id}.html"&gt;Title&lt;/a&gt;</pre>
 */
public class BaseFilter implements Filter {

    @Override
    public void init(FilterConfig fc) {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setAttribute("base", request.getServletContext().getContextPath());
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() { }

}

and register that filter in web.xml:

<filter>
    <filter-name>BaseFilter</filter-name>
    <filter-class>company.project.web.filter.BaseFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>BaseFilter</filter-name>
    <url-pattern>*.htm</url-pattern>
    <url-pattern>*.json</url-pattern>
</filter-mapping>

and use clean syntax (like above but without need to include boilerplate fragments):

<script src="${base}/js/jquery.js"></script>
<link href="${base}/css/bootstrap.css" rel="stylesheet" type="text/css">
<a href="${base}/index.html">Home</a>

NOTE I set additional attributes in that filter, for example to switch between development and minified version of CSS/JS:

private String min;

@Override
public void init(FilterConfig fc) {
    min = fc.getServletContext().getInitParameter("min");
    if (min == null)
        min = fc.getInitParameter("min");
    if (min == null)
        min = "min";
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    request.setAttribute("ctx", request.getServletContext().getContextPath());
    request.setAttribute("min", min);
    chain.doFilter(request, response);
}

and corresponding JSP code:

<script src="${base}/js/jquery.${min}.js"></script>
<link href="${base}/css/bootstrap.${min}.css" rel="stylesheet" type="text/css">

Initial parameter min may set to dev or min in externally to WAR file in contex deployment descriptor with fall-back to minified version when not set.

4) Use a scriplets:

<a href="<%=request.getContextPath()%>/index.html">Home</a>
like image 35
gavenkoa Avatar answered Jan 02 '23 11:01

gavenkoa