Есть ли JSTL EL (язык выражений), эквивалентный <c: url/">

Мы используем плагин tomcat urlrewrite для перезаписи исходящих URL-адресов, а также входящих. Для этого вам нужно использовать тег JSTL.

Это отлично работает для чистых URL-адресов и i18n, однако это дает уродливый код, включая теги-внутри-теги, например:

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

или

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

Один из вариантов заключается в использовании переменной, например:

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

Это действительно чистый, но подробный.

Есть ли способ выражения на языке для этого?

Я как бы надеялся на что-то вроде:

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

Спасибо.

Ответы

Ответ 1

В конечном итоге я решил использовать пользовательские теги для решения проблемы для CSS и JS. Разумеется, подобное решение может быть применено и к тегам, хотя у меня еще не было необходимости.

<my:csslink url="/css/custom.css" />
<my:script url="/script/myscript.js" />

Тэг CSS выглядит так: Javascript, очевидно, очень похож:

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

<%@attribute name="url" required="true" type="java.lang.String" description="the absolute (to the webapp) path of the css file"%>
<c:url var="encUrl" value='${url}' />
<link href='${encUrl}' rel='stylesheet' />

Не забудьте импортировать теги в jsp:

<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>

Пользовательское решение EL было бы чище - это некоторые обстоятельства, но если вы хотите добавить поддержку дополнительных параметров или атрибутов, то, вероятно, будет тег.

Ответ 2

Нет ничего из коробки, но ничто не мешает вам писать свои собственные функции EL и, таким образом, использовать что-то вроде этого:

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

Я не чувствую, что он более читабельен, чем стандартный тег c: url, и было бы еще хуже, если он должен принимать имена и значения параметров, однако.

См. http://docs.oracle.com/javaee/1.4/tutorial/doc/JSPIntro7.html для определения и использования функций EL.

Ответ 3

Где несколько подходов.

1) Свяжите базу с переменной в общем фрагменте:

common.jspf:

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

или как:

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

и включают фрагмент на каждой странице:

<%@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) Используйте ${pageContext.request.contextPath} везде:

<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) - мой любимый: добавить фильтр, содержащий базу для атрибута:

/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() { }

}

и зарегистрировать этот фильтр в 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>

и используйте чистый синтаксис (например, выше, но без необходимости включать фрагменты шаблона):

<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>

ПРИМЕЧАНИЕ Я установил дополнительные атрибуты в этом фильтре, например, чтобы переключиться между разработкой и уменьшенной версией 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);
}

и соответствующий код JSP:

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

Начальный параметр min может быть установлен в dev или min извне в файл WAR в дескрипторе развертывания contex с отбрасыванием на уменьшенную версию, если не установлен.

4) Используйте скрипты:

<a href="<%=request.getContextPath()%>/index.html">Home</a>