首页 文章

JSP技巧使模板更容易?

提问于
浏览
291

在工作中,我的任务是将一堆 HTML 文件转换成一个简单的 JSP 项目 . 它是's really all static, no serverside logic to program. I should mention I'对Java来说是全新的 . JSP文件似乎可以很容易地使用常见的包含和变量,就像 PHP ,但我想知道一种简单的方法来获得类似模板继承( Django 样式)或者至少能够拥有base.jsp包含页眉和页脚的文件,所以我可以稍后插入内容 .

Ben Lings似乎在这里给出了一些希望:JSP template inheritance有人可以解释如何实现这个目标吗?

鉴于我很高兴只是让URL直接映射到 .jsp 文件,但我愿意接受建议 .

谢谢 .

edit: 我不想使用任何外部库,因为它会增加我自己和其他从事该项目工作的人的学习曲线,而我所工作的公司也签约了这样做 .

Another edit: 我不确定 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 来实现,但是我需要为每个包装器提供顶部和底部包含,这有点混乱 .

5 回答

  • 651

    由于skaffman suggestedJSP 2.0 Tag Files 是蜜蜂的膝盖 .

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

    将以下内容放入 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} 
    Last Name: ${user.lastName}
    Phone: ${user.phone}
    </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} 
    Last Name: ${user.lastName}
    Phone: ${user.phone}

    现在前一个例子变为:

    <%@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 几乎篡夺了像_686445等等的东西,至少对我而言 . 我发现它们更容易使用,因为唯一的结构是你给它的,没有任何先入为主 . 另外,您可以将JSP标记文件用于其他内容(例如上面的用户详细信息片段) .

    这里完成了's an example that is similar to DisplayTag that I',但这都是使用标记文件(和 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 等) . 你唯一能做到的就像你想象的那么多 . 如果我需要scriptlet的东西,我只需将逻辑放入标签并将标签放入 . 容易 .

    因此,标记文件可以是您想要的任何内容 . 在最基本的层面上,它是简单的剪切和粘贴重构 . 抓取一大块布局,将其剪切掉,进行一些简单的参数化,然后用标签调用替换它 .

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

  • 8

    我做了相当简单的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>
    
  • 21

    基于与@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);
        }
    %>
    
  • 4

    使用tiles . 它救了我的命 .

    但是,如果你能't, there'的include tag,使它类似于PHP .

    除非你有超级简单的内容,否则body标签可能实际上并不能满足你的需要 . body标签用于定义指定元素的主体 . 看看this example

    <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

    我知道这个答案是在事实发生后的几年,并且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 .

    可悲的是,我发现最好的简单教程描述是在Wikipedia而不是教程网站 . 事实上,描述templates的部分确实如此与原始问题所要求的一致 .

    由于Java-EE 6已经弃用了JSP,我建议使用Facelets,尽管事实上看起来可能需要更多,而不是通过JSP获得 .

相关问题