เทคนิค JSP เพื่อให้การสร้างเทมเพลตง่ายขึ้น?


305

ที่ทำงานฉันได้รับมอบหมายให้เปลี่ยนHTMLไฟล์เป็นJSPโครงการง่าย ๆ ทุกอย่างมันคงที่ไม่มีตรรกะของเซิร์ฟเวอร์ในการเขียนโปรแกรม ฉันควรพูดถึงว่าฉันใหม่กับ Java อย่างสมบูรณ์ ไฟล์ JSP ดูเหมือนจะทำให้ง่ายต่อการทำงานกับการรวมทั่วไปและตัวแปรเหมือนPHPกัน แต่ฉันต้องการทราบวิธีง่ายๆในการรับสิ่งที่เป็นเทมเพลตการสืบทอด ( Djangoสไตล์) หรืออย่างน้อยสามารถมีไฟล์ base.jsp ที่มี ส่วนหัวและส่วนท้ายดังนั้นฉันสามารถแทรกเนื้อหาในภายหลัง

เบ็นลิงดูเหมือนว่าจะเสนอความหวังในคำตอบของเขาที่นี่: การ ถ่ายทอดเทมเพลต 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แต่แล้วฉันจะต้องรวมถึงด้านบนและด้านล่างสำหรับแต่ละเสื้อคลุมซึ่งเป็นชนิดของยุ่ง

คำตอบ:


682

ในฐานะที่เป็น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

<%@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: แท็ก .. ) ผลลัพธ์นี้เป็นตารางของแถวสีสลับการนำทางหน้า ฯลฯ :

<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ฯลฯ ) สิ่งเดียวที่คุณไม่สามารถทำได้ภายในเนื้อหาของแท็กไฟล์แท็กคือการเพิ่มโค้ดจาวาสคริปต์เล็ต แต่นี่ไม่ใช่ข้อ จำกัด อย่างที่คุณคิด หากฉันต้องการสิ่งสคริปต์เล็ตฉันก็ใส่ตรรกะลงในแท็กและวางแท็กในง่าย

ดังนั้นแท็กไฟล์อาจเป็นอะไรก็ได้ที่คุณต้องการ ในระดับพื้นฐานที่สุดมันง่ายในการตัดและวาง refactoring หยิบอันเลย์เอาต์มาตัดออกทำพารามิเตอร์ง่ายๆและแทนที่ด้วยการเรียกใช้แท็ก

ในระดับที่สูงขึ้นคุณสามารถทำสิ่งที่ซับซ้อนเช่นแท็กตารางที่ฉันมีที่นี่


34
ขอบคุณสำหรับสิ่งนี้. มันเป็นแบบฝึกหัดที่ดีที่สุดที่ฉันสามารถหาได้ในไฟล์แท็ก JSP ซึ่งยอดเยี่ยมสำหรับฉันที่มาจาก JSF หวังว่าฉันจะให้มากกว่าหนึ่งคะแนน
digitaljoel

66
+ 40million ขอบคุณสำหรับการอธิบาย 50,000 ครั้งดีกว่าการกวดวิชาเส็งเคร็งใด ๆ ที่ฉันได้พบ มาจากโลกของ Rails และขาด ERB นี่คือสิ่งที่ฉันต้องการ คุณควรเขียนบล็อก
cbmeeks

2
กวดวิชาที่ดีจริงๆ คุณสามารถแบ่งปันรหัสสำหรับแท็กตารางที่คุณสร้างให้เราได้ไหม ฉันสร้างขึ้นมาซักพักแล้ว แต่แนวทางของคุณดีกว่า
Thiago Duarte

4
หากคุณสร้างแท็กไฟล์แท็กเนื้อหาของแท็กนั้นในไฟล์ JSP ไม่สามารถมีรหัส scriptlet: <t: mytag> ไม่มีรหัสสคริปต์ที่นี่ </ t: mytag> แต่ภายในไฟล์แท็กที่ใช้แท็กนั้นสามารถมีโค้ดสคริปต์ทั้งหมดที่คุณต้องการเช่น JSP ใด ๆ
Will Hartung

4
หมายเหตุ - ดูเหมือนว่าลำดับของแท็กมีความสำคัญ แอตทริบิวต์ jsp: ต้องมาก่อน jsp: body หรือคุณจะได้รับข้อผิดพลาด นอกจากนี้ฉันยังต้องตั้งแท็ก @attribute ที่เกี่ยวข้องให้ตรงกับ jsp: เรียกใช้เพื่อหลีกเลี่ยงข้อผิดพลาดอื่น ใช้ GlassFish 3.2.2
Ryan

21

ฉันสร้างไลบรารีแท็กการสืบทอดเทมเพลต JSP เทมเพลตสไตล์ Django ได้ง่ายมาก 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>

10

ใช้แนวคิดพื้นฐานเดียวกับใน@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

ใช้กระเบื้องกระเบื้องมันช่วยชีวิตฉันไว้

แต่ถ้าคุณทำไม่ได้มีแท็กรวมอยู่ด้วยทำให้มันคล้ายกับ php

แท็กเนื้อหาอาจไม่ได้ทำในสิ่งที่คุณต้องการยกเว้นว่าคุณมีเนื้อหาที่เรียบง่าย แท็กร่างกายจะใช้ในการกำหนดร่างกายขององค์ประกอบที่ระบุ ดูตัวอย่างนี้ :

<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

เพิ่มการพึ่งพาสำหรับการใช้ <% @ 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>

-1

ฉันรู้คำตอบนี้มาหลายปีหลังจากความจริงและมีคำตอบ JSP ที่ยอดเยี่ยมจาก Will Hartung แต่มี Facelets พวกเขายังพูดถึงคำตอบจากคำถามที่เชื่อมโยงในคำถามเดิม

อำนวยความสะดวกในการอธิบายแท็ก SO

Facelets เป็นเทคโนโลยีมุมมองแบบ XML สำหรับกรอบงาน JavaServer Faces ออกแบบโดยเฉพาะสำหรับ JSF Facelets มีวัตถุประสงค์เพื่อเป็นทางเลือกที่ง่ายและมีประสิทธิภาพยิ่งขึ้นสำหรับมุมมองที่ใช้ JSP เริ่มแรกโครงการแยกเทคโนโลยีได้มาตรฐานเป็นส่วนหนึ่งของ JSF 2.0 และ Java-EE 6 และเลิกใช้ JSP ไลบรารีคอมโพเนนต์ที่กำหนดเป้าหมาย JSF 2.0 เกือบทั้งหมดไม่สนับสนุน JSP อีกต่อไป แต่เป็น Facelets เท่านั้น

น่าเศร้าที่คำอธิบายแบบฝึกหัดธรรมดาที่ดีที่สุดที่ฉันพบมีอยู่ในWikipediaและไม่ใช่เว็บไซต์กวดวิชา ในความเป็นจริงส่วนที่อธิบายเทมเพลตจะทำตามบรรทัดของคำถามเดิมที่ถาม

เนื่องจากข้อเท็จจริงที่ว่า Java-EE 6 เลิกใช้งานแล้ว JSP ฉันขอแนะนำให้ใช้ Facelets แม้ว่าความจริงที่ว่าดูเหมือนจะมีความต้องการมากกว่าเล็กน้อยจาก JSP


Java EE 6 ไม่ได้เลิกใช้ JSP เพียงเลิกใช้โดยใช้ JSP เป็นเทคโนโลยีมุมมองสำหรับ JSF
Ryan

@ ไรอันเนื่องจากในกรณีนี้ทั้งคู่กำลังพูดถึงเทคโนโลยีมุมมองสิ่งที่ผิดเกี่ยวกับการบอกว่ามันเลิกใช้แล้ว?
Fering

คำถามไม่มีส่วนเกี่ยวข้องกับ JSF มันเป็นเรื่องเกี่ยวกับ JSP บริสุทธิ์ คำตอบของคุณคือใช้ Facelets ซึ่งใช้สำหรับ JSF
Ryan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.