JSP技巧使模板更容易?

在工作中,我的任务是将一堆HTML文件转换成一个简单的JSP项目。它完全是静态的,没有服务器端逻辑来编程。我应该提一下,我对Java完全不熟悉。JSP文件似乎可以很容易地使用公共包含和变量,就像PHP一样,但我想知道一个简单的方法来获得像模板继承(Django风格)这样的东西,或者至少能够有一个包含页眉和页脚的base.jsp文件,以便稍后插入内容。

本凌似乎在他的回答中提供了一些希望: JSP模板继承 有人能解释一下如何做到这一点吗?< / p >

鉴于我没有太多的时间,我认为动态路由有点多,所以我很高兴只是有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实现,但然后我需要为每个包装器提供一个顶部和底部包含,这有点混乱。

130099 次浏览

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

但如果你不能,有包括标签,使它类似于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>

就像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 < / p >
<%@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 < / p >
<%@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 Files几乎篡夺了Tiles等,至少对我来说是这样。我发现它们更容易使用,因为唯一的结构是你给它的,没有先入为主。此外,您还可以将JSP标记文件用于其他事情(如上面的用户详细信息片段)。

这是一个类似于我所做的DisplayTag的例子,但这都是用标签文件完成的(和Stripes框架,这是s: tags..)。这将产生一个行表,交替的颜色,页面导航等:

<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的东西,我只需要把逻辑放到一个标记中,然后把标记放进去。一件容易的事。

标签文件可以是你想要的任何东西。在最基本的层次上,它是简单的剪切和粘贴重构。获取一个布局块,将其删除,执行一些简单的参数化,然后用标记调用替换它。

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

我做了一个很简单的,Django风格的JSP模板继承标签库。 https://github.com/kwon37xi/jsp-template-inheritance < / p >

我认为它可以很容易地管理布局,没有学习曲线。

示例代码:

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>

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>

基于与@Will哈的答案相同的基本思想,下面是我的神奇的单标签可扩展模板引擎。它甚至包括文档和一个例子:-)

web - inf /标签/ 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);
}
%>

我知道这个答案在几年之后才会出现,而且Will Hartung已经给出了一个很棒的JSP答案,但是还有Facelets,它们甚至在原始问题的链接问题的答案中被提到。

Facelets SO标签描述

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

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

由于Java-EE 6已经弃用了JSP,我建议使用Facelets,尽管它看起来可能需要更多的功能,但与JSP相比几乎没有任何好处。

为使用<%@tag description="User Page template" 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>
这也可以用jsp:include实现。查德·达比在这个视频中解释得很好 https://www.youtube.com/watch?v=EWbYj0qoNHo < / p >