Sitemesh #2 Sitemesh 소개

web 2007. 8. 24. 05:22

이글은 webwork,sitemesh를 기반으로 한 프레임워크에 적합한 내용입니다. 그리고, 이 글은 모든 내용이 다 맞지 않습니다.

한글 자료가 거의 전무하여 적어 놓게 되었습니다. 회사이름은 밝히기 않기 위해. 대충 가명썼습니다..

 

소개

SiteMesh는 web-page layout이고, decoration(장식) 프레임웍이고, 일관된 look/fee, navagation, layout scheme를 필요로 하는 많은 페이지로 구성된 큰 사이트를 만드는것을 도와주는 web-application 통합 프레임웍이다. 일관성있는 요소들때문에 조직화하고, 변화와 수정에 탁월해야 한다. Sitemesh,는 웹 서버에 요구된 정적/동적 요청을 가로채어 요청된 페이지 자원을 파싱하여 설정된 속성과 렌더링할 데이터를 컨텐츠로부터 읽어들여 원래의 페이지에 decoration과 수정을 가해 최종 페이지를 생성한다.

대부분의 HTML 문서는 다음과 같은 decorator 패턴 양식을 가지고 있다.

  • meta tags (keywords, description, author)
  • stylesheet (CSS)
  • header
  • navigation
  • footer
  • copyright notice

naviation과 layout 스킴만 정하면 나머지는 공통부분으로 따로 정리할 수 있도록 도와주는 프레임웍이 Sitemesh 이다.


Figure 1. Normal Page Rendering


Figure 2. SiteMesh Page Rendering

 

간단히 맛보기

기본적인 jsp 코드는 다음과 같다.

simple.jsp
<html>
    <head>
        <title>Simple Document</title>
    </head>
    <body>
        Hello World! <br />
        <%= 1+1 %>
        </body>
</html>

위의 코드의 템플릿으로 만들어지는 페이지를 데코레이션을 사용하여 jsp 페이지를 동적으로 승화시킬 수 있다.

decorator.jsp
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<html>
    <head>
        <title> My Site - <decorator:title default="Welcome!" /> </title>
        <decorator:head />
    </head>
    <body>
        <h1><decorator:title default="Welcome!" /></h1>
        <p><decorator:body /></p>
    </body>
</html>

첫번째 라인에 sitemesh 태그라이브러리가 소개되고, <decorator:title> 엘리먼트는 장식될 페이지의 <title> 엘리먼트의 텍스트를 가져와 삽입한다. <decorator:body> 엘리멘트는 페이지의 본문을 장식한다.

Sitemesh에 모든 패턴에 사용할 decorator를 WEB-INF/decorators.xml파일에 설정한다.

decorators.xml
<decorators>

    <decorator name="mydecorator" page="/decorator.jsp">
        <pattern>/*</pattern>
    </decorator>

<decorators>

이런 식으로 밑의 파일처럼 특정 디렉토리 또는 패턴에 따라 다양하게 decoration이 가능하다.

decorators.xml
<decorators defaultdir="/decorators">

    <decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>

    <decorator name="anotherdecorator" page="decorator2.jsp">
        <pattern>/subdir/*</pattern>
    </decorator>

    <decorator name="htmldecorator" page="html.jsp">
        <pattern>*.html</pattern>
        <pattern>*.htm</pattern>
    </decorator>

    <decorator name="none">
        <!-- These files will not get decorated. -->
        <pattern>/anotherdir/*</pattern>
    </decorator>
</decorators>

환경 설정

cvs서버로부터 test_project프로젝트를 update하고, 그 기반에서 동작하는 것을 기준으로 한다.

  • sitemesh.jar가 [web-app home directory]/WEB-INF/lib에 위치해 있는지 확인한다. (sitemesh 2.1.1 gl 버젼의 jar파일이 저장되어 있음을 확인할 수 있을 것이다.)
  • [web-app home directory]/WEB-INF/web.xml의 <web-app> 태그안에 다음의 내용이 추가되어야 한다. webwork-cleanup - sitemesh - webwork 의 순서대로 등록해야 한다.
    web.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    	version="2.4">
    
    .....fileter의 webwork-cleanup 정의 .....
             <filter>
    		<filter-name>sitemesh</filter-name>
    		<filter-class>
    			com.opensymphony.module.sitemesh.filter.PageFilter
    		</filter-class>
    		<init-param>
    			<param-name>pageEncoding</param-name>
    			<param-value>MS949</param-value>
    		</init-param>
    	</filter>
    
    .....fileter의 sitemesh 정의 .....
    
    
    .....filter-mapping의 webwork-cleanup 정의 .....
    	<filter-mapping>
    		<filter-name>sitemesh</filter-name>
    		<url-pattern>/*</url-pattern>
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    .....filter-mapping의 sitemesh 정의 .....
  • [web-app home directory]/WEB-INF/sitemesh.xml 파일이 생성해야 한다. 필수 파일은 아니지만, 있어야 원하는 패턴을 지정할 수 있다.
    sitemesh.xml
    <sitemesh>
      <page-parsers>
        <parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
        <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
      </page-parsers>
    
      <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
          <param name="property.1" value="meta.decorator" />
          <param name="property.2" value="decorator" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
          <param name="match.MSIE" value="ie" />
          <param name="match.Mozilla [" value="ns" />
          <param name="match.Opera" value="opera" />
          <param name="match.Lynx" value="lynx" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
          <param name="decorator" value="printable" />
          <param name="parameter.name" value="printable" />
          <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
          <param name="decorator" value="robot" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
          <param name="decorator.parameter" value="decorator" />
          <param name="parameter.name" value="confirm" />
          <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
          <param name="config" value="/WEB-INF/decorators.xml" />
        </mapper>
      </decorator-mappers>	
    </sitemesh>
  • [web-app home directory]/WEB-INF/decorators.xml 파일이 생성되어야 한다.
    decorators.xml
    <decorators>
        <decorator name="defaultHeader" page="defaultHeader.jsp"/>
        <decorator name="defaultFooter" page="defaultFooter.jsp"/>
    
        <decorator name="default" page="default.jsp">
            <pattern>/*</pattern>
        </decorator>
    </decorators>

    헤더와 풋터 jsp를 지정한다.그리고, 디폴트 페이지를 모든페이지에 지정한다.

  • [web-app home directory]/WEB-INF/decorators 디렉토리에 템플릿으로 쓰일 default.jsp, defaultHeader.jsp, defaultFooter.jsp 파일을 생성한다.
    default.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
    <%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
    
    <head>
    <meta http-equiv=Cache-Control content=No-Cache>
    <meta http-equiv=Pragma content=No-Cache>
    <meta http-equiv="expires" content="0">
    <META HTTP-EQUIV="imagetoolbar" CONTENT="no">
    <meta http-equiv="Content-type" content="text/html; charset=euc-kr">
    <title><decorator:title default="퍼블 테스트" /></title>
    </head>
    
    <body bgcolor=ffffff bottommargin=0 topmargin=0 marginheight=0>
    <!-- TOP Menu -->
    <page:applyDecorator name="defaultHeader"/>
    <!-- //TOP Menu 영역 -->
    xxxx   <decorator:body/>   xxxx
    
    <!-- footer -->
    <page:applyDecorator name="defaultFooter"/>
    <!-- //footer 영역 -->
    </html>
    defaultHeader.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <!--head start-->
    Header<br>
    <!--head end-->
    defaultFooter.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <!--Footer start-->
    <br> Footer <Br>
    <!--Footer end-->
  • 하나의 액션 HelloWorld.java를 생성한다.
    HelloWorld
    import com.google.common.actions.GoogleBaseAction;
    
    public class HelloWorld extends GoogleBaseAction {
    	
    	public String execute() throws Exception {
    		return SUCCESS;
    	}
    }
  • [web-app home directory]/hello.jsp 코드를 작성한다.
    hello.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
    <%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
    Hello World
  • 결과
    Web browser
    Header
    xxxx Hello World xxxx 
    Footer

Sitemesh의 설정 파일 설명

decorators.xml

decorators.xml 은 여러 decorator의 정의와 특정 decorator가 적용될 페이지의 리스트가 설정되어 있다. decorator의 순서에 따라 적용되어 진다.

decorators.xml
<?xml version="1.0" encoding="ISO-8859-1"?>

<decorators defaultdir="/decorators">
    <!-- Any urls that are excluded will never be decorated by Sitemesh -->
    <excludes>
        <pattern>/exclude.jsp</pattern>
        <pattern>/exclude/*</pattern>
    </excludes>

    <!-- decorator 태그안에 page의 경로는 web-app/decorators/main.jsp가 된다.-->
    <decorator name="main" page="main.jsp">
        <pattern>/*</pattern>
    </decorator>

    <decorator name="panel" page="panel.jsp"/>
    <decorator name="printable" page="printable.jsp"/>
    <decorator name="black" page="black.jsp"/>
    <decorator name="nopanelsource" page="nopanelsource.jsp"/>
    <decorator name="badpanelsource" page="badpanelsource.jsp"/>

    <decorator name="velocity" page="velocity.vm">
        <pattern>/velocity.html</pattern>
    </decorator>

    <decorator name="freemarker" page="freemarker.ftl">
        <pattern>/freemarker.html</pattern>
    </decorator>

    <decorator name="test" page="test.jsp">
        <pattern>/agent.jsp</pattern>
    </decorator>
</decorators>
  • decorators
    <decorators> 엘리먼트는 decorator들의 리스트를 정의하고 있다. <decorators defaultdir="/decorators">의 defaultdir="/decorators" attribute은 기본적으로 decorator page들이 위치하고 있는 경로를 나타낸다.
  • excludes
    <excludes> 엘리먼트는 decorator가 적용되지 않아야 할 패턴의 리스트이다.
    decorator name="main"의 main decorator는 모든 패턴의 리소스에 적용되며 main.jsp를 decorator page로 사용한다는 뜻이다.
    panel, printable, black, nonpanelsource, badpanelsource는 모두 패턴을 지정하지 않았고, freemaker, velocity는 특정페이지를 적용했다.
  • pattern
    <pattern> 엘리먼트는 decorator가 적용될 Request URI를 지정한다. 패턴이 적용되는 순서가 다르다. Request URI를 보고 다음의 순서대로 해당 decorator page를 찾게된다.
  1. 정확하게 단어가 맞는 패턴 (Exact word)
  2. 'abc*'나 'abc?'와 같은 컴플렉스 패턴 (Complext)
  3. '/', '*', '/*'와 같은 디폴트 패턴 (Default)

적절한 패턴이 설정되지 않은 decorator는 다른 decorator 내에서 <page:applyDecorator/>를 통해 포함할 때 사용되거나 decorator mapper(sitemesh.xml)에서 특정 decorator를 지정할 때 사용된다.

sitemesh.xml

sitemesh.xml은 decorator mapper 리스트가 설정되어 있다. 만일 Sitemesh가 해당 경로에서 설정 파일을 찾는데 실패하면sitemesh.jar 에 패키징 되어 있는 sitemesh-default.xml 파일로 대체된다.

sitemesh.xml
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />

    <page-parsers>
         <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
    </page-parsers>

    <excludes file="${decorators-file}" />

    <decorator-mappers>
	<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
	    <param name="property.1" value="meta.decorator" />
	    <param name="property.2" value="decorator" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
		<param name="match.MSIE" value="ie" />
		<param name="match.Mozilla [" value="ns" />
		<param name="match.Opera" value="opera" />
		<param name="match.Lynx" value="lynx" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
		<param name="decorator" value="printable" />
		<param name="parameter.name" value="printable" />
		<param name="parameter.value" value="true" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
		<param name="decorator" value="robot" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
		<param name="decorator.parameter" value="decorator" />
		<param name="parameter.name" value="confirm" />
		<param name="parameter.value" value="true" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
		<param name="config" value="${decorators-file}" />
	</mapper>

	</decorator-mappers>
</sitemesh>
  • page parsers
    <page-parsers> 엘리먼트는 content-type에 따라 적용할 파서를 정의한다. SiteMesh는 현재 text/html을 파싱할 때 사용되는 FastPage Parser만 구현되어 있다. 나머지에 대해서는 디폴트로 DefaultPageParser가 사용가능하다.
    <page-parsers>
    	<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
    	<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
    </page-parsers>
  • decorator mapper
    decorator mapper는 Sitemesh에게 장식에 사용될 적합한 decorator를 설정해주는 역할을 한다. <decorator-mapper> 엘리먼트는 decorator mapper들을 정의한다. decorator mapper 추상 클래스는 링크드 리스트로 정의되어 있고, 적혀진 순서에 따라 decorator 체인으로 만들어진다.
    <decorator-mappers>
    	<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
    		<param name="property.1" value="meta.decorator" />
    		<param name="property.2" value="decorator" />
    	</mapper>
    </decorator-mappers>
    ....
  • excludes
    특정 웹 페이지(jsp)들을 모아 decoration이 적용되지 않도록 하는 설정파일을 지정한다.
    <excludes file="/WEB-INF/decorators.xml"/>
  • property
    변수화하여 쉽게 사용할 수 있도록 한다.
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />
    ...
    <excludes file="${decorators-file}" />
    ...
    <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
    	<param name="config" value="${decorators-file}" />
    </mapper>

ConfigDecoratorMapper는 decorator 파일들을 config로 지정할 수 있음을 의미하며, 여러 개의 config 파일을 포함할 수 있다.

Decorator를 이용한 일관성있는 Look

jsp와 이미 기존에 쓰이고 있는 CGI script가 사용할 수 있도록 도와줌으로서, 일관성있는 look을 제공한다.

 

Flow Diagram

web.xml에서 정의된 필터, 즉 PageFiletr에 의해 Sitemesh가 사용되어진다.


페이지를 Page 객체에 파싱한 후 DecoratorMapper에 의해서 Decorator를 판단한다. 그래서 sitemesh.xml 파일에 DecoratorMapper 선언된 순서대로 decorator를 사용하고 mapper에서 결국 decorator를 얻지 못하면 본래 모습으로 보여준다. 주요 DecoratorMapper는 /WEB-INF/decorators.xml에서 decorator와 mapping을읽어들이는 ConfigDecoratorMapper 이다.

 

 

SiteMesh 구조와 흐름

  1. request 단계
    모든 request는 PageFilter에서 가로채어진다. PageFilter는 Context 초기화 시점에 decorator.xml에 정의된 <exclude> 태그에 따라 요청된 request의 url-pattern에 따라 장식을 수행할지 여부를 결정한다.
  2. paring 단계
    PageFilter는 요청된 자원에 대한 웹 어플리케이션의 수행결과를 do(request, respose) 메소드를 호출하여 받아낸다. 응답 파라미터에는 ServletResponse가 아닌 HttpServletResponseWrapper를 상속받아 확장한 PageResponseWrapper 객체를 사용한다.
    따라서 페이지 아웃풋은 writer로 보내지 않고 content-type에 따라 선택된 파서가 PageResponseWrapper에서 캡처된 page 아웃풋 데이터를 파싱한다. 현재는 반환 page의 content-type이 text/html일 경우만 FastPageParser가 작동한다.
  3. decorator 선정 단계
    적합한 decorator를 결정한다. 이 과정은 mapper 클래스의 getDecorator()에 의해서 이뤄진다. 처음 decorator 선정을 시도한 mapper 클래스가 적합한 decorator를 얻어낸다면 리턴하고, 아니면 decorator 체인상의 상위 링크의 getDecorator() 메소들르 호출하게 된다. 정확한 decorator가 결정될 때까지 반복된다.
  4. decorator 단계
    decorator를 얻오고, decorator로부터 decorator page를 구해 올 수 있다면, PageFilter는 applyDecorator()내에서 decorator 페이지에 대한 요청을 생성하고, decorator page는 FastPageParser에 의해 파싱된 결과 page의 적절한 부분들을 커스텀 태그를 통해 가져와 출력 페이지를 작성한다.

참조

http://today.java.net/pub/a/today/2004/03/11/sitemesh.html

마소의 sitemesh 기사

Posted by '김용환'
,