2011年9月30日 星期五

apache tiles 2 學習筆記

Apache tiles是一個版型模組化的工具.

通常網頁至少會將版型切割為4個區塊, 例如下圖:


tiles 的定義檔如下:
<tiles-definitions>
  <definition name="indexTemplate" template="/WEB-INF/views/tiles/indexTemplate.jsp">
    <put-attribute name="title" value="Welcome" />
    <put-attribute name="header" value="/WEB-INF/views/tiles/header.jsp" />
    <put-attribute name="category" value="/WEB-INF/views/tiles/category.jsp" />
    <put-attribute name="browse" value="/WEB-INF/views/tiles/browse.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/tiles/footer.jsp" />
  </definition>
</tiles-definitions>


而頁面變更的時候, 通常都只是更換整頁中的某一個區塊, 其它區塊不需要變化.

例如登入時, 只需要將右邊的區塊變更為登入頁.


登入頁 tiles 的設定如下, 只要更換 title 及 browse 二個變數的定義即可.
<!-- Login Page -->
<definition name="login" extends="indexTemplate">
    <put-attribute name="title" value="Login Page" />
    <put-attribute name="browse" value="/WEB-INF/views/tiles/login.jsp" />
</definition>


但考慮更複雜一點的情況呢?

例如電子商務中常見的, 點擊商品目錄.

此時商品目錄會展開, 且右邊會列出該目錄下的所有商品.

示意圖如下:


這時候就得在同一個 controller 裡處理商品及目錄的邏輯.
然後分別放入不同的 tiles 變數中.

等一下下...似乎有點奇怪, 目錄跟商品雖然有關係, 但畢竟各自有不同的處理邏輯.
放在同一個 controller 內處理似乎怪怪的...

如果再回頭看一下登入頁的例子, 目錄的頁面雖然不需變動, 但此時目錄頁應呈現第一層目錄結構.

第一層目錄結構的邏輯, 跟登入有什麼關係呢 ?


是否有辦法將各區塊的內容獨立處理, 讓彼此不相干的邏輯不要混在一起呢?


還好, tiles 提供了 View Preparer 來處理這種情況.




首先, 將tiles 的設定檔修改如下:
<tiles-definitions>
  <definition name="category" template="/WEB-INF/views/tiles/category.jsp" preparer="com.example.viewpreparer.Category" />

    <definition name="indexTemplate" template="/WEB-INF/views/tiles/indexTemplate.jsp">
    <put-attribute name="title" value="Welcome" />
    <put-attribute name="header" value="/WEB-INF/views/tiles/header.jsp" />
    <put-attribute name="category" value="category" />
    <put-attribute name="browse" value="/WEB-INF/views/tiles/browse.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/tiles/footer.jsp" />
  </definition>
</tiles-definitions>


接著撰寫 com.example.viewpreparer.Category, 如下:
package com.example.viewpreparer;

import java.util.Map;

import org.apache.tiles.AttributeContext;
import org.apache.tiles.context.TilesRequestContext;
import org.apache.tiles.preparer.ViewPreparer;
import org.apache.tiles.Attribute;

public class Category implements ViewPreparer {

    public void execute(TilesRequestContext tilesContext, AttributeContext attributeContext) {

        // retrieve parameter
        Map<String, String[]> map = tilesContext.getParamValues() ;
        String[] list = map.get("cid") ;
        if (list != null && list.length > 0 ) {
            System.out.println("cid=" + list[0]) ;
        }

        // put variable
        attributeContext.putAttribute("body", new Attribute("This is the value added by the ViewPreparer"));
    }

}


category.jsp的寫法如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>

<tiles:insertAttribute name="body" />



除了用 <tiles:insertAttribute 外也可以用 jstl, 作法如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>

<tiles:useAttribute id="mybody" name="body" classname="java.lang.String" />
<c:out value="${mybody}" />



沒有留言: