Java 使模板更容易的 JSP 技巧?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1296235/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 07:56:41  来源:igfitidea点击:

JSP tricks to make templating easier?

javajspinheritancetemplatestags

提问by Scott

At work I've been tasked with turning a bunch of HTMLfiles into a simple JSPproject. It's really all static, no serverside logic to program. I should mention I'm completely new to Java. JSP files seem to make it easy to work with common includes and variables, much like PHP, but I'd like to know a simple way to get something like template inheritance (Djangostyle) or at least be able to have a base.jsp file containing the header and the footer, so I can insert content later.

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

Ben Lingsseems to offer some hope in his answer here: JSP template inheritanceCan someone explain how to achieve this?

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

Given that I don't have much time I think dynamic routing is a little much, so I'm happy to just to have URLs map directly onto .jspfiles, but I'm open to suggestion.

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

Thanks.

谢谢。

edit:I don't want to use any external libraries, because it would increase the learning curve for myself and others who work on the project, and the company I work for has been contracted to do this.

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

Another edit:I'm not sure if JSP tagswill be useful because my content doesn't really have any template variables. What I need is a way to be able to do this:

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

base.html:

base.html:

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

somepage.html

somepage.html

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

with the output being:

输出为:

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

I think this would give me enough versatility to do everything I need. It could be achieved with includesbut then I would need a top and a bottom include for each wrapper, which is kind of messy.

我认为这会给我足够的多功能性来做我需要的一切。它可以实现,includes但随后我需要为每个包装器添加一个顶部和一个底部,这有点凌乱。

采纳答案by Will Hartung

As skaffman suggested, JSP 2.0 Tag Filesare the bee's knees.

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

Let's take your simple example.

让我们以您的简单示例为例。

Put the following in WEB-INF/tags/wrapper.tag

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

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

Now in your example.jsppage:

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

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

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

That does exactly what you think it does.

这正是您认为的那样。



So, lets expand upon that to something a bit more general. WEB-INF/tags/genericpage.tag

所以,让我们把它扩展到更一般的东西。 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>

To use this:

要使用这个:

<%@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>

What does that buy you? A lot really, but it gets even better...

那给你买什么?真的很多,但它变得更好......



WEB-INF/tags/userpage.tag

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>

To use this: (assume we have a user variable in the request)

要使用它:(假设我们在请求中有一个用户变量)

<%@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>


But it turns you like to use that user detail block in other places. So, we'll refactor it. WEB-INF/tags/userdetail.tag

但它变成了您喜欢在其他地方使用该用户详细信息块。所以,我们将重构它。 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/>

Now the previous example becomes:

现在前面的例子变成了:

<%@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>


The beauty of JSP Tag files is that it lets you basically tag generic markup and then refactor it to your heart's content.

JSP 标记文件的美妙之处在于它让您基本上可以标记通用标记,然后将其重构为您的核心内容。

JSP Tag Fileshave pretty much usurped things like Tilesetc., at least for me. I find them much easier to use as the only structure is what you give it, nothing preconceived. Plus you can use JSP tag files for other things (like the user detail fragment above).

JSP Tag Files几乎篡夺了诸如此类的东西Tiles,至少对我而言。我发现它们更容易使用,因为唯一的结构就是你给它的,没有任何先入为主。此外,您还可以将 JSP 标记文件用于其他用途(如上面的用户详细信息片段)。

Here's an example that is similar to DisplayTag that I've done, but this is all done with Tag Files (and the Stripesframework, that's the s: tags..). This results in a table of rows, alternating colors, page navigation, etc:

这是一个类似于我做过的 DisplayTag 的例子,但这都是用标签文件完成的(和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>

Of course the tags work with the JSTL tags(like c:if, etc.). The only thing you can't do within the body of a tag file tag is add Java scriptlet code, but this isn't as much of a limitation as you might think. If I need scriptlet stuff, I just put the logic in to a tag and drop the tag in. Easy.

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

So, tag files can be pretty much whatever you want them to be. At the most basic level, it's simple cut and paste refactoring. Grab a chunk of layout, cut it out, do some simple parameterization, and replace it with a tag invocation.

所以,标签文件几乎可以是你想要的任何东西。在最基本的层面上,它是简单的剪切和粘贴重构。抓取一大块布局,剪下来,做一些简单的参数化,然后用标签调用替换它。

At a higher level, you can do sophisticated things like this table tag I have here.

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

回答by geowa4

Use tiles. It saved my life.

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

But if you can't, there's the include tag, making it similar to php.

但是如果你不能,有include 标签,使它类似于 php.ini 。

The body tag might not actually do what you need it to, unless you have super simple content. The body tag is used to define the body of a specified element. Take a look at this example:

除非你有超级简单的内容,否则 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>

You specify the element name, any attributes that element might have ("lang" in this case), and then the text that goes in it--the body. So if

您指定元素名称、元素可能具有的任何属性(在本例中为“lang”),然后是其中的文本——正文。因此,如果

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

Then the output would be

然后输出将是

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

回答by KwonNam

I made quite easy, Django style JSP Template inheritance tag library. https://github.com/kwon37xi/jsp-template-inheritance

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

I think it make easy to manage layouts without learning curve.

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

example code :

示例代码:

base.jsp : layout

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 : contents

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>

回答by amichair

Based on the same basic idea as in @Will Hartung's answer, here is my magic one-tag extensible template engine. It even includes documentation and an example :-)

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

WEB-INF/tags/block.tag:

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

回答by Fering

I know this answer is coming years after the fact and there is already a great JSP answer by Will Hartung, but there is Facelets, they are even mentioned in the answers from the linked question in the original question.

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

Facelets SO tag description

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.

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

Sadly the best plain tutorial description I found was on Wikipediaand not a tutorial site. In fact the section describing templateseven does along the lines of what the original question was asking for.

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

Due to the fact that Java-EE 6 has deprecated JSP I would recommend going with Facelets despite the fact that it looks like there might be more required for little to no gain over JSP.

由于 Java-EE 6 已弃用 JSP,我建议使用 Facelets,尽管它看起来可能比 JSP 需要更多的好处。

回答by Juan Silupú Maza

add dependecys for use <%@tag description="User Page template" pageEncoding="UTF-8"%>

添加使用依赖 <%@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>

回答by Sandeep Amarnath

This can also be achieved with jsp:include. Chad Darby explains well here in this video https://www.youtube.com/watch?v=EWbYj0qoNHo

这也可以通过 jsp:include 来实现。Chad Darby 在此视频中解释得很好 https://www.youtube.com/watch?v=EWbYj0qoNHo