关于java:JSP技巧使模板更容易?

JSP tricks to make templating easier?

在工作中,我的任务是把一堆HTML文件变成一个简单的JSP项目。它实际上都是静态的,没有服务器端逻辑来编程。我应该说我对Java完全陌生。JSP文件似乎可以很容易地使用通用的include和变量,很像PHP,但是我想知道一个简单的方法来获得类似模板继承(Django样式)的东西,或者至少能够有一个包含头和尾的base.jsp文件,这样我以后可以插入内容。

本·林斯似乎在他的回答中提供了一些希望:JSP模板继承有人能解释如何做到这一点吗?

考虑到我没有太多时间,我认为动态路由有点长,所以我很乐意将URL直接映射到.jsp文件,但我愿意接受建议。

谢谢。

编辑:我不想使用任何外部的库,因为它会增加我自己和其他在项目上工作的人的学习曲线,而且我为之工作的公司已经签订了这样的合同。

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

base.html:

1
2
3
<html><body>
{ content.body }
</body></html>

somepage.html

1
2
3
<wrapper:base.html>
Welcome
</wrapper>

输出为:

1
2
3
<html><body>
Welcome
</body></html>

我认为这将给我足够的多功能性来做我需要的一切。它可以用includes实现,但是我需要一个顶部和底部,包括每个包装,这有点混乱。


正如斯卡夫曼所建议的,JSP 2.0标签文件是蜜蜂的膝盖。

让我们举个简单的例子。

WEB-INF/tags/wrapper.tag中输入以下内容

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

现在在您的example.jsp页:

1
2
3
4
5
6
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

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

这正是你所认为的。

所以,让我们把它扩展到更一般的东西上。WEB-INF/tags/genericpage.tag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@tag description="Overall Page template" pageEncoding="UTF-8"%>
<%@attribute name="header" fragment="true" %>
<%@attribute name="footer" fragment="true" %>
<html>
  <body>
   
      <jsp:invoke fragment="header"/>
   
   
      <jsp:doBody/>
   
   
      <jsp:invoke fragment="footer"/>
   
  </body>
</html>

使用此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:genericpage>
    <jsp:attribute name="header">
      Welcome
    </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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@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">
      Welcome ${userName}
    </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>

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

1
2
3
4
5
6
7
8
9
10
11
12
<%@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

1
2
3
4
5
6
7
<%@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/>

现在前面的例子变成:

1
2
3
4
5
6
7
8
9
10
<%@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 Files有相当多的篡夺行为,比如Tiles等。我发现它们更容易使用,因为唯一的结构就是你给它的东西,没有什么先入为主的。另外,您还可以将JSP标记文件用于其他用途(如上面的用户详细信息片段)。

这里有一个与我所做的displaytag类似的例子,但这都是通过标记文件(以及Stripes框架,即s:tags..)完成的。这将生成一个由行、交替颜色、页面导航等组成的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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的东西,我只需要把逻辑放到一个标签上,然后把标签放进去。容易的。

所以,标记文件可以是任何你想要的文件。在最基本的层次上,它是简单的剪切粘贴重构。抓取一块布局,将其切掉,进行一些简单的参数化,并用标记调用替换它。

在更高的层次上,你可以做一些复杂的事情,比如我这里的这个表标签。


我制作了非常简单的django风格的JSP模板继承标记库。https://github.com/kwon37xi/jsp-template-inheritance

我认为不需要学习曲线就可以很容易地管理布局。

示例代码:

base.jsp:布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://kwonnam.pe.kr/jsp/template-inheritance" prefix="layout"%>
<!DOCTYPE html>
<html lang="en">
    <head>
        JSP Template Inheritance
    </head>

Head

    <layout:block name="header">
        header
    </layout:block>


Contents

    <p>

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



    <hr />
    jsp template inheritance example

</html>

view.jsp:目录

1
2
3
4
5
6
7
8
9
10
11
<%@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">
        This is an example about layout management with JSP Template Inheritance
    </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>


基于与@will-hartung答案相同的基本思想,这里是我的神奇的一个标签可扩展模板引擎。它甚至包括文档和一个示例:—)

WEB-INF/tags/block.tag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<%--
    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">
           
                Powered by the block tag
           
        </jsp:attribute>
        <jsp:body>
            <html>
                <head>
                    ${title}
                    <style>
                        ${style}
                    </style>
                </head>
                <body>
                    ${title}
                   
                        ${content}
                   
                    ${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);
    }
%>

使用瓦片。它救了我的命。

但是如果不能,就有include标签,使其类似于php。

body标签实际上可能不会做你需要它做的事情,除非你有超简单的内容。body标记用于定义指定元素的主体。看看这个例子:

1
2
3
4
5
<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

那么输出将是

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

我知道这个答案是在这个事实之后的几年,威尔·哈顿已经有了一个很好的JSP答案,但是还有facelets,它们甚至在原始问题的链接问题的答案中被提到。

Facelets so标签描述

Facelets is an XML-based view technology for the JavaServer Faces framework. Designed specifically for JSF, Facelets is intended to be a simpler and more powerful alternative to JSP-based views. Initially a separate project, the technology was standardized as part of JSF 2.0 and Java-EE 6 and has deprecated JSP. Almost all JSF 2.0 targeted component libraries do not support JSP anymore, but only Facelets.

遗憾的是,我找到的最简单的教程描述是在维基百科上,而不是在教程网站上。事实上,描述模板的部分甚至按照原始问题的要求来做。

由于JavaEE 6已经禁止JSP,所以我建议使用FACELET,尽管事实上它看起来比JSP有更多的需求。