Advanced SiteMesh

http://www.onjava.com/pub/a/onjava/2004/09/22/sitemesh.html?page=1

Suppose you're creating an enterprise-level web site and you have to use more than one technology for building it. For example, you want to add some new content to your web site using J2EE, but parts of your system have already been created using CGI or Microsoft IIS server.

In this case, how do you make sure that you have a consistent look and feel across your site? One option would be to rewrite everything in J2EE and then use a framework such as Struts-Tiles, but this option is not feasible because of the development costs associated with this approach. A second option could be to implement the same look and feel in every web application that is part of your system. This approach becomes a nightmare for anyone maintaining the web site, since any time there is look and feel change in one application, you'll have to make similar changes to the other web applications in the system.

The problem with most of the available frameworks for solving this type of business requirement is that they are either platform- or framework-specific. When you're using Tiles for decoration in Struts, you have to create tiles definition in tiels-defs.xml. Inside of yourstruts-config.xml while declaring forwards, you will have to use these tiles' definition instead of actual JSP.

The easiest possible solution is to let each of your web applications create plain HTML content without knowing about how it is being decorated, and only then have something else choose and apply appropriate decorators. This is precisely what SiteMesh does.

SiteMesh is an open source framework based on Java, J2EE, and XML. SiteMesh depends on filters, a cool feature introduced in the Servlet specification 2.3.

Installation and Setup

In my experience, the best way to learn any technology or framework is to create a simple sample application using it. So we will start by creating a simple Struts application using SiteMesh. Our application will have three pages:

  • A login page
  • A help page, which will have a header and footer
  • A home page, which will have a header, a footer, and a side menu

Here are the steps to building the simple web application:

  1. SiteMesh is based on filters, so we have to inform our web application about the SiteMesh filter. Adding the following lines toweb.xml can do this:

    <filter>
      <filter-name>sitemesh</filter-name>
      <filter-class>
          com.opensymphony.module.sitemesh.filter.PageFilter
      </filter-class>
      <init-param>
        <param-name>debug.pagewriter</param-name>
        <param-value>true</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>sitemesh</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

    Here we are telling the container that all requests to this web application should go through PageFilter. The PageFilter class is part of sitemesh-2.1.jar, which you can download from the SiteMesh downloads page. Once downloaded, you should copysitemesh-2.1.jar to the /WEB-INF/lib folder.

  2. Create a decorators.xml file in the WEB-INF folder like this:

    <decorators defaultdir="/decorators">
      <!-- Decorator for pages which need Sidemenu -->
      <decorator name="sidemenu" page="sidemenu.jsp">
        <pattern>/home.jsp</pattern>
      </decorator>
      <!-- Decorator for pages which need header and footer -->
      <decorator name="headerfooter" page="headerfooter.jsp">
        <pattern>/help.jsp</pattern>
      </decorator>
    </decorators>

    The decorators.xml file is used to define decorators for your application. In this file, each <decorator> element defines one decorator. The name attribute is used to define a name for that decorator, while the page attribute defines the JSP page that should be used for decorating. The <pattern> child element defines when a particular decorator should be applied.

    In our example web application, we want two decorators: headerfooter.jsp, to add a header and footer, and sidemenu.jsp, to add a header, a footer, and a side menu. We want to decorate the help page by adding a header and footer, so we add the /help.jsppath sub-element to headerfooter.jsp.

  3. Create headerfooter.jsp in the WebContent/decorators folder:

    <%@ taglib
        uri="http://www.opensymphony.com/sitemesh/decorator"
        prefix="decorator" %>
    <html>
      <head>
        <title>
          My Site - 
          <decorator:title default="Welcome!" />
        </title>
        <decorator:head />
      </head>
      <body>
        <table>
          <tr>
            <td>
              <H1>
                SiteMesh Corporation
              <H1>
            </td>
          </tr>
          <tr>
            <td><decorator:body /></td>
          </tr>
          <tr>
            <td> SiteMesh copyright</td>
          </tr>
        </table>
      </body>
    </html>

    A SiteMesh decorator is a JSP page using SiteMesh custom tags. In our web application, when the user requests the help page, SiteMesh will intercept the request and send it to the web application. Once it gets a response from the application, it will parse it and insert the header part of it in headerfooter.jsp in place of <decorator:head/>, and the body part in place of<decorator:body>. Finally, it will return headerfooter.jsp to the client.

  4. Create help.jsp in the WebContent folder:

    <HTML>
    <HEAD>
    <%@ page 
    language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"
    %>
    <TITLE>Help Page</TITLE>
    </HEAD>
    <BODY>
      Help Page 
    </BODY>
    </HTML>

    This is a very simple help page for our sample web application.

  5. Test the SiteMesh installation by requesting the help.jsp page. It should display the help page with header and footer.

SiteMesh Architecture

The SiteMesh architecture is based on Filters, namely the PageFilter class. When a container receives a request for a page, it will pass it to PageFilter, which will create a custom response object for collecting the application's response, and pass it to the web application along with the request. The web application will write the requested resource in the custom response object and will return it back to PageFilter.



  1. The Parsing Phase

    Once control comes back to the PageFilter class, it will examine the content type of the response generated by the web application. Depending on the content type, it will determine which parser class to use for parsing the response. It will create an object of that parser class and will pass the response to it. For example, if an application returns content of the type text/html, SiteMesh will create an object of the FastPageParser class and pass the page generated by the web application to it.FastPageParser will parse that page to read the header, footer, title, etc. from it.

  2. The Decoration Phase

    Once the parsing phase is complete, SiteMesh will start the decoration phrase. This can be divided into two phases.

    a. Determining how to decorate this page

    SiteMesh has a concept of decorator mapper, which is a Java class implementing the DecoratorMapper interface (meaning it has init() and getDecorator() methods). A mapper is declared by adding an entry for it in sitemesh.xml. In sitemesh.xml, every mapper is parent of the mapper declared just above it. When SiteMesh has to find the decorator for a particular page, it will create an instance of the first mapper in sitemesh.xml and call its getDecorator() method. In the getDecorator() method, the mapper class will try to determine a decorator for that page. If mapper is able to get a decorator, it will return it; otherwise, it will call the getDecorator() method of its parent, following this process until it finds the correct decorator for that page.

    b. Applying decorators

    Once the decorator (a JSP page) is found, SiteMesh will dispatch the request to it. The decorator JSP page has access to the parsed page from the previous phase. It will use various SiteMesh custom tags to read various parts (such as header, footer, and title) and insert them at appropriate places in the final output page.

You can define which page parser classes to use for particular content types and what decorator mappers to use by editing WEB-INF/sitemesh.xml like this:

<?xml version="1.0" encoding="UTF-8"?>
<sitemesh>
  <property name="decorators-file" value="/WEB-INF/decorators.xml"/>
  <excludes file="${decorators-file}"/>
  <page-parsers>
    <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 for localization -->
    <mapper 
        class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper">
      <param name="match.en" value="en" />
      <param name="match.zh" value="zh" />
    </mapper>
    <!-- Mapper for browser compatibility -->
    <mapper 
        class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
      <param name="match.MSIE" value="ie" />
      <param name="match.Mozilla/" value="ns" />
    </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.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.ConfigDecoratorMapper">
      <param name="config" value="${decorators-file}" />
    </mapper>
  </decorator-mappers>
</sitemesh>

In this listing, <property name="decorators-file"> defines which file contains decorator definitions. <page-parsers> defines what content types SiteMesh can handle. Each <parser> child element maps which class should be used for parsing the response of a particular content type. In our sample sitemesh.xml, we are telling SiteMesh that FastPageParser should be used for handling thetext/html type of content. By default, SiteMesh can only handle HTML, but you can create your own parsers for handling other content types.

The <decorator-mappers> element defines what mappers SiteMesh is going to apply while finding decorators for a particular page. You can pass configuration information to the mapper with the <param> sub-element. SiteMesh will wrap these configuration parameters in a java.util.Properties object and pass it to the init() method of mapper class.

Locale-Specific Decorators

In our example sitemesh.xml, we have the following tag:

<mapper class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper">
  <param name="match.en" value="en" />
  <param name="match.zh" value="zh" />
</mapper>

While finding a decorator for a page, SiteMesh will read the Accept-Language header of the request. If it matches the en locale, it will take the name of the decorator JSP and append -en to it. In our sample, if you request help.jsp, for which headerfooter.jsp is the decorator, then for the English locale, SiteMesh will search for headerfooter-en.jsp. If headerfooter-en.jsp is found, it will use that; otherwise it will use headerfooter.jsp.

Browser-Specific Decorator

We are using AgentDecoratorMapper for browser compatibility:

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

This means that while finding the decorator for a page, SiteMesh will try to figure out what the user's browser is from the value of theUser-Agent header. If it is Microsoft Internet Explorer, then it will append -ie to the name of the decorator file, and if found, use it as the decorator. Otherwise, it will use headerfooter.jsp

Advanced SiteMesh

SiteMesh provides mappers, which let every page participate in process of finding a decorator for that page.

PrintableDecoratorMapper

Most web sites provide a facility for getting a printable version of a page. The printable version normally removes headers, footers, and side menus, and may provide a different stylesheet. In SiteMesh, we can achieve this by using PrintableDecoratorMapper. To use this mapper you have to add an entry for it in sitemesh.xml, like this:

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

This passes three parameters to PrintableDecoratorMapper. These parameters are passed to the PrintableDecoratorMapper's initmethod as a java.util.Properties object:

  • decorator
    The name of the decorator, which should be used for creating the printable version of a page.

  • parameter.name
    The name of the request parameter to be used for informing SiteMesh that we want a printable page. In our example, all we have to do is pass printable=true in the query string.

  • parameter.value
    The value of the printable parameter that indicates we want a printable version of the page.

PageDecoratorMapper

A page can override which decorator should be used by specifying the decorator name through the META attribute.



In order to use this mapper, you have to change sitemesh.xml:

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

PageDecoratorMapper takes a list of parameters. In our example, we are instructing it that the value of decorator's META property should be used as the decorator name. So if I want to use a decorator named test for the page, all I have to do is add the following line in the header:

<META name="decorator" content="test">

PageDecoratorMapper provides a static approach for a page to choose which decorator should be used. A page can decide which decorator to use at runtime by using ParameterDecoratorMapper.

ParameterDecoratorMapper

To use a ParameterDecoratorMapper, add an entry for it in sitemesh.xml:

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

This takes three parameters:

  • decorator.parameter
    The name of the request parameter used for specifying the name of the decorator.

  • parameter.name
    The name of the request parameter used for confirming the decorator parameter.

  • parameter.value
    The value of the request parameter used for confirming the decorator parameter.

If you want help.jsp to use the test decorator, then you can invoke it like this:

help.jsp?decorator=test&confirm=true

SiteMesh provides a few more mappers that are very helpful. Some of these are:

  • FrameSetDecoratorMapper
    Should be used when page is a frame.

  • CookieDecoratorMapper
    Lets you use a cookie value for specifying the name of the decorator to be used.

  • RobotDecoratorMapper
    Will use the specified decorator when the requester is identified as a robot. You may want to add a keywords header if the page is accessed by a robot, and a decorator is a good way to do that.

Velocity and Freemarker Decorators

SiteMesh does not restrict you to use JSP while creating decorators. You are free to use either Velocity or Freemarker. Velocity and Freemarker are templating languages that can be used for creating web pages. These languages are much easier to use than normal JSP, but are not as programmable as JSP.

SiteMesh adds supports for these two templating languages through two servlets, which are part of SiteMesh.jar. We have to declare these two servlets in web.xml, as follows:

<servlet>
  <servlet-name>sitemesh-velocity</servlet-name>
  <servlet-class> 
    com.opensymphony.module.sitemesh.velocity.VelocityDecoratorServlet
  </servlet-class>
</servlet>
<!--Declare servlet for handling freemarker requests -->
<servlet>
  <servlet-name>sitemesh-freemarker</servlet-name>
  <servlet-class>
    com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet
  </servlet-class>
  <init-param>
    <param-name>TemplatePath</param-name>
    <param-value>/</param-value>
  </init-param>
  <init-param>
    <param-name>default_encoding</param-name>
    <param-value>ISO-8859-1</param-value>
  </init-param>
</servlet>
<!-- Velocity servlet should serve all requests with .vm extension-->
<servlet-mapping>
  <servlet-name>sitemesh-velocity</servlet-name>
  <url-pattern>*.vm</url-pattern>
</servlet-mapping>
<!-- FreeMarker servlet should serve all requests with .dec extension-->
<servlet-mapping>
  <servlet-name>sitemesh-freemarker</servlet-name>
  <url-pattern>*.dec</url-pattern>
</servlet-mapping>

We also have to copy freemarker.jarvelocity-dep.jar, and velocity-tools-view.jar into the lib folder. These .jars are shipped with the SiteMesh distribution. We will change our first sample for using Velocity and Freemarker decorators instead of JSP. In our first sample we have two decorators: headerfooter and sidemenu. We will create headerfooter.dec like this:

<html>
  <head>
    <title>My Site - $Advanced SiteMesh</title>
      ${head}
  </head>
  <body>
    <table border="1">
      <tr>
        <td>SiteMesh Corporation</td>
      </tr>
      <tr>
        <td>${body}</td>
      </tr>
      <tr>
        <td>SiteMesh copyright</td>
      </tr>
    </table>
  </body>
</html>

In this page, we are using Freemarker templates for header, footer, and title instead of custom tags, but the page layout is the same. When the container receives a request for a page with a .dec extension, it will pass it to FreemarkerDecoratorServlet, which invokesFreemarkerDecorator for generating the final HTML page. We are using the $Advanced SiteMesh template for accessing the title of the web page generated by the application, ${head} for accessing the head, and ${body} for accessing the body. Freemarker provides more such templates. You can find out more about it in the Resources section below.

We also need to create sidemenu.vm in the decorators folder. This is the Velocity decoration file.

<html>
  <head>
    <title>My Site - $title</title>
      $head
  </head>
  <body>
    <table border="1">
      <tr>
        <td> SiteMesh Header </td>
      </tr>
      <tr>
        <td> Sidemenu </td>
        <td> $body </td>
      </tr>
      <tr>
        <td> SiteMesh Footer </td>
      </tr>
    </table>
  </body>
</html>

For a Velocity decorator, we need to replace decorator:title with a $title template. Similarly, we will use head and body Velocity templates instead of custom tags.

Conclusion

SiteMesh is a very flexible and easy-to-use decoration framework based on filters. But it has a couple of problems. First, filters were introduced in the Servlet 2.3 specification, so older application servers may not support them. Please check that your application is going to be deployed on a container that supports filters.

Also, a filter gets control only if a user requests that page. If you call home.jsp through a browser, it will be decorated, but if one of your servlets gives control to home.jsp through either RequestDispatcher.include() or forward(), it won't get decorated. But don't worry--in the Servlet 2.4 specification and up, you can just configure filters to be invoked in forwarding and include cases, as well as for regular requests.

Resources

Sunil Patil has worked on J2EE technologies for more than five years. His areas of interest include object relational mapping tools, UI frameworks, and portals.


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值