使用JSP技巧可以使模板制作更容易?


305

在工作中,我的任务是将一堆HTML文件变成一个简单的JSP项目。实际上,这完全是静态的,不需要编写服务器端逻辑。我应该提到我是Java的新手。JSP文件似乎使使用通用包含和变量变得很容易,就像PHP,但是我想知道一种简单的方法来获得诸如模板继承(Django样式)之类的东西,或者至少能够使base.jsp文件包含页眉和页脚,以便稍后插入内容。

Ben Lings在这里的回答似乎提供了一些希望: JSP模板继承 有人可以解释如何实现这一点吗?

考虑到我没有太多时间,我认为动态路由会花很多时间,所以我很高兴能将URL直接映射到.jsp文件上,但是我愿意提出建议。

谢谢。

编辑:我不想使用任何外部库,因为这会增加我自己和从事该项目的其他人的学习曲线,而我所工作的公司已与该公司签约。

另一个编辑:我不确定是否JSP tags有用,因为我的内容实际上没有任何模板变量。我需要的是一种能够做到这一点的方法:

base.html:

<html><body>
{ content.body }
</body></html>

somepage.html

<wrapper:base.html>
<h1>Welcome</h1>
</wrapper>

输出为:

<html><body>
<h1>Welcome</h1>
</body></html>

我认为这将使我有足够的多功能性来完成我需要的一切。它可以通过实现,includes但是然后我需要为每个包装程序添加一个顶部和一个底部,这有点混乱。

Answers:


682

正如skaffman所建议的那样JSP 2.0标记文件是蜜蜂的膝盖。

让我们举一个简单的例子。

将以下内容放入 WEB-INF/tags/wrapper.tag

<%@tag description="Simple Wrapper Tag" pageEncoding="UTF-8"%>
<html><body>
  <jsp:doBody/>
</body></html>

现在在您的example.jsp页面中:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:wrapper>
    <h1>Welcome</h1>
</t:wrapper>

这确实符合您的想法。


因此,让我们将其扩展到更一般的内容。 WEB-INF/tags/genericpage.tag

<%@tag description="Overall Page template" pageEncoding="UTF-8"%>
<%@attribute name="header" fragment="true" %>
<%@attribute name="footer" fragment="true" %>
<html>
  <body>
    <div id="pageheader">
      <jsp:invoke fragment="header"/>
    </div>
    <div id="body">
      <jsp:doBody/>
    </div>
    <div id="pagefooter">
      <jsp:invoke fragment="footer"/>
    </div>
  </body>
</html>

要使用此功能:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:genericpage>
    <jsp:attribute name="header">
      <h1>Welcome</h1>
    </jsp:attribute>
    <jsp:attribute name="footer">
      <p id="copyright">Copyright 1927, Future Bits When There Be Bits Inc.</p>
    </jsp:attribute>
    <jsp:body>
        <p>Hi I'm the heart of the message</p>
    </jsp:body>
</t:genericpage>

那买了什么?确实很多,但它变得更好...


WEB-INF/tags/userpage.tag

<%@tag description="User Page template" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<%@attribute name="userName" required="true"%>

<t:genericpage>
    <jsp:attribute name="header">
      <h1>Welcome ${userName}</h1>
    </jsp:attribute>
    <jsp:attribute name="footer">
      <p id="copyright">Copyright 1927, Future Bits When There Be Bits Inc.</p>
    </jsp:attribute>
    <jsp:body>
        <jsp:doBody/>
    </jsp:body>
</t:genericpage>

要使用此功能:(假设请求中有一个用户变量)

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:userpage userName="${user.fullName}">
  <p>
    First Name: ${user.firstName} <br/>
    Last Name: ${user.lastName} <br/>
    Phone: ${user.phone}<br/>
  </p>
</t:userpage>

但这使您喜欢在其他地方使用该用户详细信息块。因此,我们将对其进行重构。 WEB-INF/tags/userdetail.tag

<%@tag description="User Page template" pageEncoding="UTF-8"%>
<%@tag import="com.example.User" %>
<%@attribute name="user" required="true" type="com.example.User"%>

First Name: ${user.firstName} <br/>
Last Name: ${user.lastName} <br/>
Phone: ${user.phone}<br/>

现在,前面的示例变为:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:userpage userName="${user.fullName}">
  <p>
    <t:userdetail user="${user}"/>
  </p>
</t:userpage>

JSP标记文件的优点在于,它可以使您基本上标记通用标记,然后将其重构为您的内心需求。

JSP Tag FilesTiles至少对我来说,有很多篡改之类的东西。我发现它们更易于使用,因为唯一的结构就是您提供的结构,没有任何先入为主的构想。另外,您可以将JSP标记文件用于其他用途(例如上面的用户详细信息片段)。

这是一个与我已经完成的DisplayTag相似的示例,但是所有这些都由Tag Files(和Stripes框架,即s:标签..)完成。这将产生一个行表,交替的颜色,页面导航等:

<t:table items="${actionBean.customerList}" var="obj" css_class="display">
  <t:col css_class="checkboxcol">
    <s:checkbox name="customerIds" value="${obj.customerId}"
                onclick="handleCheckboxRangeSelection(this, event);"/>
  </t:col>
  <t:col name="customerId" title="ID"/>
  <t:col name="firstName" title="First Name"/>
  <t:col name="lastName" title="Last Name"/>
  <t:col>
    <s:link href="/Customer.action" event="preEdit">
      Edit
      <s:param name="customer.customerId" value="${obj.customerId}"/>
      <s:param name="page" value="${actionBean.page}"/>
    </s:link>
  </t:col>
</t:table>

当然,标记可与一起使用JSTL tags(如c:if,等等)。在标记文件标记的主体内,您唯一不能做的就是添加Java scriptlet代码,但这并没有您想象的那么多限制。如果我需要scriptlet的东西,我只是将逻辑放入标签中,然后将标签放入其中。

因此,标记文件几乎可以是任何您想要的文件。在最基本的级别上,它是简单的剪切和粘贴重构。抓取一部分布局,将其切出,进行一些简单的参数化,然后将其替换为标记调用。

在更高的级别上,您可以做一些复杂的事情,例如我在这里使用的这个表格标签。


34
谢谢你 这是我在JSP标记文件上可以找到的最佳教程,这对我来自JSF来说非常有用。希望我能投多票。
digitaljoel 2010年

66
+4000万。感谢您对它的解释比我发现的任何糟糕的教程要好50,000倍。来自Rails世界并且缺少ERB,这正是我所需要的。您应该写一个博客。
cbmeeks 2011年

2
真的很好的教程。您能否与我们分享您制作的表格标签的代码?我前一阵子创建了一个,但是您的方法更好。
Thiago Duarte'4

4
如果创建标记文件标记,则JSP文件中该标记的内容不能包含脚本代码:<t:mytag>此处没有脚本代码</ t:mytag>。但是在实现标签本身的标签文件中,可以像所有JSP一样拥有所需的所有scriptlet代码。
Will Hartung 2012年

4
注意-标签的顺序似乎很重要;jsp:attribute必须在jsp:body之前,否则您将得到一个错误。另外,我还必须设置一个相应的@attribute标记以匹配jsp:invoke以避免另一个错误。使用GlassFish 3.2.2
Ryan

21

Django风格的JSP Template继承标记库使我非常容易。 https://github.com/kwon37xi/jsp-template-inheritance

我认为无需学习曲线即可轻松管理布局。

示例代码:

base.jsp:布局

<%@page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://kwonnam.pe.kr/jsp/template-inheritance" prefix="layout"%>
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>JSP Template Inheritance</title>
    </head>

<h1>Head</h1>
<div>
    <layout:block name="header">
        header
    </layout:block>
</div>

<h1>Contents</h1>
<div>
    <p>
    <layout:block name="contents">
        <h2>Contents will be placed under this h2</h2>
    </layout:block>
    </p>
</div>

<div class="footer">
    <hr />
    <a href="https://github.com/kwon37xi/jsp-template-inheritance">jsp template inheritance example</a>
</div>
</html>

view.jsp:内容

<%@page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://kwonnam.pe.kr/jsp/template-inheritance" prefix="layout"%>
<layout:extends name="base.jsp">
    <layout:put name="header" type="REPLACE">
        <h2>This is an example about layout management with JSP Template Inheritance</h2>
    </layout:put>
    <layout:put name="contents">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin porta,
        augue ut ornare sagittis, diam libero facilisis augue, quis accumsan enim velit a mauris.
    </layout:put>
</layout:extends>

10

基于与@Will Hartung的回答相同的基本思想,这是我神奇的单标签可扩展模板引擎。它甚至包括文档和示例:-)

WEB-INF / tags / block.tag:

<%--
    The block tag implements a basic but useful extensible template system.

    A base template consists of a block tag without a 'template' attribute.
    The template body is specified in a standard jsp:body tag, which can
    contain EL, JSTL tags, nested block tags and other custom tags, but
    cannot contain scriptlets (scriptlets are allowed in the template file,
    but only outside of the body and attribute tags). Templates can be
    full-page templates, or smaller blocks of markup included within a page.

    The template is customizable by referencing named attributes within
    the body (via EL). Attribute values can then be set either as attributes
    of the block tag element itself (convenient for short values), or by
    using nested jsp:attribute elements (better for entire blocks of markup).

    Rendering a template block or extending it in a child template is then
    just a matter of invoking the block tag with the 'template' attribute set
    to the desired template name, and overriding template-specific attributes
    as necessary to customize it.

    Attribute values set when rendering a tag override those set in the template
    definition, which override those set in its parent template definition, etc.
    The attributes that are set in the base template are thus effectively used
    as defaults. Attributes that are not set anywhere are treated as empty.

    Internally, attributes are passed from child to parent via request-scope
    attributes, which are removed when rendering is complete.

    Here's a contrived example:

    ====== WEB-INF/tags/block.tag (the template engine tag)

    <the file you're looking at right now>

    ====== WEB-INF/templates/base.jsp (base template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block>
        <jsp:attribute name="title">Template Page</jsp:attribute>
        <jsp:attribute name="style">
            .footer { font-size: smaller; color: #aaa; }
            .content { margin: 2em; color: #009; }
            ${moreStyle}
        </jsp:attribute>
        <jsp:attribute name="footer">
            <div class="footer">
                Powered by the block tag
            </div>
        </jsp:attribute>
        <jsp:body>
            <html>
                <head>
                    <title>${title}</title>
                    <style>
                        ${style}
                    </style>
                </head>
                <body>
                    <h1>${title}</h1>
                    <div class="content">
                        ${content}
                    </div>
                    ${footer}
                </body>
            </html>
        </jsp:body>
    </t:block>

    ====== WEB-INF/templates/history.jsp (child template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block template="base" title="History Lesson">
        <jsp:attribute name="content" trim="false">
            <p>${shooter} shot first!</p>
        </jsp:attribute>
    </t:block>

    ====== history-1977.jsp (a page using child template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block template="history" shooter="Han" />

    ====== history-1997.jsp (a page using child template)

    <%@ page trimDirectiveWhitespaces="true" %>
    <%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>
    <t:block template="history" title="Revised History Lesson">
        <jsp:attribute name="moreStyle">.revised { font-style: italic; }</jsp:attribute>
        <jsp:attribute name="shooter"><span class="revised">Greedo</span></jsp:attribute>
    </t:block>

--%>

<%@ tag trimDirectiveWhitespaces="true" %>
<%@ tag import="java.util.HashSet, java.util.Map, java.util.Map.Entry" %>
<%@ tag dynamic-attributes="dynattributes" %>
<%@ attribute name="template" %>
<%
    // get template name (adding default .jsp extension if it does not contain
    // any '.', and /WEB-INF/templates/ prefix if it does not start with a '/')
    String template = (String)jspContext.getAttribute("template");
    if (template != null) {
        if (!template.contains("."))
            template += ".jsp";
        if (!template.startsWith("/"))
            template = "/WEB-INF/templates/" + template;
    }
    // copy dynamic attributes into request scope so they can be accessed from included template page
    // (child is processed before parent template, so only set previously undefined attributes)
    Map<String, String> dynattributes = (Map<String, String>)jspContext.getAttribute("dynattributes");
    HashSet<String> addedAttributes = new HashSet<String>();
    for (Map.Entry<String, String> e : dynattributes.entrySet()) {
        if (jspContext.getAttribute(e.getKey(), PageContext.REQUEST_SCOPE) == null) {
            jspContext.setAttribute(e.getKey(), e.getValue(), PageContext.REQUEST_SCOPE);
            addedAttributes.add(e.getKey());
        }
    }
%>

<% if (template == null) { // this is the base template itself, so render it %>
    <jsp:doBody/>
<% } else { // this is a page using the template, so include the template instead %>
    <jsp:include page="<%= template %>" />
<% } %>

<%
    // clean up the added attributes to prevent side effect outside the current tag
    for (String key : addedAttributes) {
        jspContext.removeAttribute(key, PageContext.REQUEST_SCOPE);
    }
%>

4

使用瓷砖。它救了我的命。

但是,如果不能这样做,则有include标记,使其类似于php。

除非您具有超简单的内容,否则body标记可能实际上并没有执行您需要的操作。body标签用于定义指定元素的主体。看一下这个例子

<jsp:element name="${content.headerName}"   
   xmlns:jsp="http://java.sun.com/JSP/Page">    
   <jsp:attribute name="lang">${content.lang}</jsp:attribute>   
   <jsp:body>${content.body}</jsp:body> 
</jsp:element>

您可以指定元素名称,元素可能具有的所有属性(在这种情况下为“ lang”),然后输入其中的文本-正文。因此,如果

  • content.headerName = h1
  • content.lang = fr
  • content.body = Heading in French

然后输出将是

<h1 lang="fr">Heading in French</h1>


0

添加要使用的依赖<%@ tag description =“用户页面模板” pageEncoding =“ UTF-8”%>

<dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>

-1

我知道这个答案是在事实发生之后的几年,并且Will Hartung已经有了一个很棒的JSP答案,但是有Facelets,甚至在原始问题的链接问题的答案中都提到了Facelets。

Facelets SO标签说明

Facelets是JavaServer Faces框架的基于XML的视图技术。Facelets专为JSF设计,旨在成为基于JSP的视图的一种更简单,更强大的替代方法。最初是一个单独的项目,该技术被标准化为JSF 2.0和Java-EE 6的一部分,并且已弃用JSP。几乎所有针对JSF 2.0的组件库都不再支持JSP,而仅支持Facelets。

遗憾的是,我发现的最好的普通教程描述是在Wikipedia上,而不是在教程网站上。实际上,描述模板的部分甚至遵循原始问题的要求。

由于Java-EE 6已弃用JSP,因此我建议还是使用Facelets,尽管事实似乎是,与JSP相比,可能需要更多的东西,而收效甚微。


Java EE 6并未弃用JSP,只是弃用了JSP作为JSF的视图技术。
瑞安

@Ryan既然在这种情况下,两个人都在谈论视图技术,那么说它已过时又有什么错呢?
Fering

这个问题与JSF无关。它是关于纯JSP的。您的答案是使用供JSF使用的Facelets。
瑞安
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.