JSP技巧使模板更容易?

在工作中,我负责将一堆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但是然后我需要一个顶部和底部包括每个包装,这是一种凌乱。

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

我们来举个简单的例子。

把下面的WEB-INF/tags/wrapper.tag放入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 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的东西,我只是把逻辑放在一个标签,并放入标签。

所以,标签文件可以几乎任何你想要的。 在最基本的层面上,它是简单的剪切和粘贴重构。 抓住一个布局的块,把它切出来,做一些简单的参数化,并用标记调用替换它。

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

我做了相当简单的,Django风格的JSP模板继承标签库。 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> 

基于和@Will Hartung的回答一样的基本思想,这里是我的魔术单标签可扩展模板引擎。 它甚至包括文档和一个例子:-)

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); } %> 

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

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

您应该意识到,使用大量<%…%>的JSP,通常会创建难以维护的应用程序(非平凡的大小)。

因此,你现在应该已经准备好自己学习一个额外的层,无论是为这个或下一个项目。 就我个人而言,我选择JSF作为一个项目,允许纯XML XML页面调用taglibs,这是相当不错的,但有一个陡峭的学习曲线,所以我不会推荐它,除非你先仔细考虑它:)

无论您选择哪种技术,都需要一个能让您将演示文稿与实际代码分开的演示文稿。 有一天你会明白这一点。