템플릿을 쉽게 만드는 JSP 트릭?


305

직장에서 나는 많은 HTML파일을 간단한 JSP프로젝트 로 바꾸는 일을 해왔다 . 프로그래밍 할 서버 측 논리가없는 것은 모두 정적입니다. Java를 완전히 처음 사용한다고 언급해야합니다. JSP 파일은 일반적인 include 및 변수를 쉽게 사용할 수있는 것처럼 보이지만 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있었지만 각 포장지에 대해 상단 및 하단 포함이 필요합니다.

답변:


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 FilesTiles적어도 나를 위해 등을 많이 빼앗 았 습니다. 유일한 구조는 당신이주는 것이므로 선입견이 없으므로 사용하기가 훨씬 쉽다는 것을 알았습니다. 또한 JSP 태그 파일을 다른 용도로 사용할 수 있습니다 (위의 사용자 세부 사항 조각과 같은).

다음은 내가 수행 한 DisplayTag와 유사한 예이지만, 모두 Tag Files (및 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 스크립틀릿 코드 추가 뿐이지 만 생각만큼 제한이 없습니다. 스크립틀릿이 필요한 경우 로직을 태그에 넣고 태그를 넣습니다.

따라서 태그 파일은 원하는대로 만들 수 있습니다. 가장 기본적인 수준에서는 간단한 잘라 내기 및 붙여 넣기 리팩토링입니다. 레이아웃 청크를 잡고 잘라내어 간단한 매개 변수화를 수행 한 후 태그 호출로 대체하십시오.

더 높은 수준에서는 여기에있는이 테이블 태그와 같은 정교한 작업을 수행 할 수 있습니다.


34
고마워 JSP 태그 파일에서 찾을 수있는 가장 좋은 자습서입니다 .JSF에서 온 것이 좋습니다. 하나 이상의 투표를 할 수 있으면 좋겠습니다.
digitaljoel

66
+40 백만. 내가 찾은 엉뚱한 튜토리얼보다 50,000 배 더 잘 설명해 주셔서 감사합니다. Rails 세계에서 나오고 누락 된 ERB가 바로 이것이 필요한 것입니다. 블로그를 작성해야합니다.
cbmeeks

2
정말 좋은 튜토리얼. 작성한 표 태그의 코드를 공유해 주시겠습니까? 나는 얼마 전에 나 자신을 만들었지 만 당신의 접근 방식이 더 좋습니다.
Thiago Duarte

4
태그 파일 태그를 작성하면 JSP 파일에서 해당 태그의 컨텐츠에 스크립틀릿 코드를 사용할 수 없습니다 : <t : mytag> 여기에 스크립틀릿 코드 없음 </ t : mytag>. 그러나 태그 자체를 구현하는 태그 파일 내에서 JSP처럼 원하는 모든 스크립틀릿 코드를 가질 수 있습니다.
Will Hartung

4
참고-태그 순서가 중요한 것 같습니다. jsp : attribute가 jsp : body 앞에 와야합니다. 그렇지 않으면 오류가 발생합니다. 또한 다른 오류를 피하기 위해 해당 @attribute 태그를 jsp : invoke와 일치하도록 설정해야했습니다. GlassFish 3.2.2 사용
Ryan

21

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>

10

@Will Hartung 의 답변 과 동일한 기본 아이디어를 바탕으로 내 마술 1 태그 확장 가능한 템플릿 엔진이 있습니다. 그것은 심지어 문서와 예제를 포함합니다 :-)

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

4

타일을 사용하십시오 . 내 생명을 구했습니다.

그러나 당신이 할 수 없다면 include 태그 가있어 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>


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

나는이 대답이 사실 이후 몇 년이 지난 것을 알고 있으며 Will Hartung의 JSP 답변이 이미 훌륭하지만 Facelets가 있으며 원래 질문의 링크 된 질문에 대한 답변에도 언급되어 있습니다.

Facelets SO 태그 설명

Facelets는 JavaServer Faces 프레임 워크를위한 XML 기반보기 기술입니다. JSF를 위해 특별히 설계된 Facelets는 JSP 기반보기에 대한보다 단순하고 강력한 대안이되도록 고안되었습니다. 처음에는 별도의 프로젝트였던이 기술은 JSF 2.0 및 Java-EE 6의 일부로 표준화되었으며 JSP는 더 이상 사용되지 않습니다. 거의 모든 JSF 2.0 대상 구성 요소 라이브러리는 더 이상 JSP를 지원하지 않고 Facelets 만 지원합니다.

안타깝게도 내가 찾은 최고의 일반 자습서 설명 은 자습서 사이트가 아니라 Wikipedia에 있었습니다 . 실제로 템플릿을 설명하는 섹션 은 원래 질문이 요청한 내용을 따라 수행됩니다.

Java-EE 6이 JSP를 더 이상 사용하지 않는다는 사실 때문에 JSP보다 이득이 적거나 전혀 필요하지 않은 것처럼 보이지만 Facelets를 사용하는 것이 좋습니다.


Java EE 6은 JSP를 더 이상 사용하지 않고 JSF의 뷰 기술로 JSP를 사용하여 사용되지 않습니다.
Ryan

@Ryan이 경우 둘 다 뷰 기술에 대해 이야기 한 이래 더 이상 사용되지 않는다고 말한 것은 무엇입니까?
Fering

이 질문은 JSF와 관련이 없습니다. 순수한 JSP에 관한 것입니다. 당신의 대답은 JSF를위한 Facelets를 사용하는 것입니다.
Ryan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.