個人覺得,工作可以是一種信仰、一種宗教,而一間公司可能同時存在有多種信仰;
信仰間是會有衝突的,有些信仰無法容下其他的信仰而有衝突,發生衝突時也難免會因較為激進的派系而交火;在人數極多時,我想這無可避免。
但如果一間人數極少而每個人竟都有不同的信仰,這個組合應該是一件蠢事。
這蠢事居然就在我眼前。
蠢!
個人覺得,工作可以是一種信仰、一種宗教,而一間公司可能同時存在有多種信仰;
信仰間是會有衝突的,有些信仰無法容下其他的信仰而有衝突,發生衝突時也難免會因較為激進的派系而交火;在人數極多時,我想這無可避免。
但如果一間人數極少而每個人竟都有不同的信仰,這個組合應該是一件蠢事。
這蠢事居然就在我眼前。
蠢!
Tiles是一個分割網頁的Library,提供了一個除了使用<jsp:include>之外的JSP組合工具;
透過xml設定檔,將重覆不需變動的頁面分割後定為Template,讓開發人員專注在各個模組中不同的頁面並使其具有組合性。
通常一個頁面基本的格局大概如下圖
這次的Demo就以table來分割而不以div方式來制定,簡單的html如下
<html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title></title> </head> <body> <table> <tr> <td colspan="2">Header</td> </tr> <tr> <td>Menu</td><td>Body</td> </tr> <tr> <td colspan="2">Footer</td> </tr> </table> </body> </html>
寫成JSP的include大概會變成下面這樣
<%@ page language="java" pageEncoding="UTF-8"%> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title></title> </head> <body> <table> <tr> <td colspan="2"><jsp:include file="/WEB-INF/jsp/common/header.jsp"></jsp:include></td> </tr> <tr> <td><jsp:include file="/WEB-INF/jsp/common/menu.jsp"></jsp:include></td><td>Body</td> </tr> <tr> <td colspan="2"><jsp:include file="/WEB-INF/jsp/common/footer.jsp"></jsp:include></td> </tr> </table> </body> </html>
看起來還不錯,但是個一個jsp都必需重覆include header,menu,footer這三個jsp,而且萬一哪天出了什麼事,例如要加個ad在畫面的最右側,那所有的jsp都必需要被修正.....嗯,如果以部份認為PG死不完,班是應該的管理人員來看,也許也不是什麼大事吧....
但是Tiles提供了一個反其道而行的方式,先要求我們產生一個基本的jsp做為layout,將header,menu,body,footer當成是變數,再利用xml設定每個變數是要指到哪一個jsp,就讓我們一步一步看下去(。。。有點藍色xx網的感覺
(1)Library
先在pom.xml中加入要使用的library,如果僅是使用基本的tiles功能,只要加入一項即可
<dependency>
<dependency> <groupid>org.apache.tiles</groupid> <artifactid>tiles-jsp</artifactid> <version>2.2.2</version> </dependency>
(2)建立Template Layout JSP -- layout.jsp
簡單來說,就是利用tiles:insertAttribute來取代jsp:include
加入ignore="true"代表可以不給值。
<%@ include file="/WEB-INF/jsp/common/base.jsp"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" /> <title><tiles:insertattribute ignore="true" name="title"></tiles:insertattribute></title> </head> <body> <table> <tr> <td colspan="2"><tiles:insertattribute name="header"> </tiles:insertattribute></td> </tr> <tr> <td><tiles:insertattribute name="menu"></tiles:insertattribute></td><td><tiles:insertattribute name="body"></tiles:insertattribute></td> </tr> <tr> <td colspan="2"><tiles:insertattribute name="footer"></tiles:insertattribute></td> </tr> </table> </body> </html>
(3)設定Tiles的Template XML -- tiles.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN" "http://tiles.apache.org/dtds/tiles-config_2_0.dtd"> <tiles-definitions> <!--採用/WEB-INF/jsp/common/layout.jsp做為基本版型,--> <definition name="base.definition" template="/WEB-INF/jsp/common/layout.jsp"> <put-attribute name="title" value=""> </put-attribute><put-attribute name="header" value="/WEB-INF/jsp/common/header.jsp"> </put-attribute><put-attribute name="menu" value="/WEB-INF/jsp/common/menu.jsp"> </put-attribute><put-attribute name="body" value=""> </put-attribute><put-attribute name="footer" value="/WEB-INF/jsp/common/footer.jsp"> </put-attribute></definition> <!-- 延用基本版型,改變title與body的值 --> <definition name="hello" extends="base.definition"> <put-attribute name="title" value="Say Hello to Tiles"> </put-attribute><put-attribute name="body" value="/WEB-INF/jsp/helloTiles.jsp"> </put-attribute></definition> </tiles-definitions>
而其中/WEB-INF/jsp/common/下的header.jsp,menu.jsp,footer.jsp,helloTiles.jsp就隨你寫入內容囉
(4)更改SpringMVC 的ViewReslover -- spring-servlet.xml
將先前採用的JstlView改為TilesView,並加入tilesConfigurer指定tiles設定檔
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="viewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"> </property></bean> <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer"> <property name="definitions"> <list> <value>/WEB-INF/tiles.xml</value> </list> </property> </bean>
這樣就完成最簡單的SpringMVC與Tiles設定囉
因為專案需要,但是專案沒有wiki的系統(說來Redmine真的不錯用!),就稍為利用這裡記錄關於SpringMVC想說明的部份
(1)library
要開始一個SpringMVC很容易,第一請先建立一個web project,要利用mvn eclipse:eclipse或直接在ide裡開都ok,pom.xml裡的dependency只需要
<dependencies> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-webmvc</artifactid> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupid>javax.servlet</groupid> <artifactid>jstl</artifactid> <version>1.2</version> </dependency> </dependencies>
(2)web.xml
web.xml也很容易,只要將SpringMVC要用的front controller -- DispatcherServlet喚起就可以,而serlvet-mapping就看你高興,不喜歡以.do結尾也可用asp,php或html來混淆他人...下列的設定代表所有http://host/module/XXXX.do的url皆會由Spring的DispatcherServlet處理
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
(3)spring-servlet.xml
如果你有沒有在web.xml利用ContextLoaderListener來載入的spring configuration,SpringMVC則會自動載入/WEB-INF/spring-servlet.xml,如果沒用ContextLoaderListener也找不到該檔就會顯示錯誤
<?xml version="1.0" encoding="UTF-8"?> <beans xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"> <context:component-scan base-package="idv.elliot.web.controller"/> <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="viewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"> </property><property name="prefix" value="/WEB-INF/jsp/"> </property><property name="suffix" value=".jsp"> </property></bean> </beans>
簡單來說,利用component-scan來找出利用annotation標示的Spring components,當中也包含了皆下來要提的Controller,然後建立一個viewResolver,這是用最基本的UrlBasedViewResolver
如此一來,當Controller的method回傳abc時,SpringMVC就會將其導向http://host/module/WEB-INF/jsp/abc.jsp
至於為什麼要把jsp放到/WEB-INF/下,則是因為這只要/WEB-INF/裡的所有東西必需是自系統內的servlet forward過去才能取得,一般人無法直接以url接觸到該resource
(4)建立Controller
先用個helloworld吧,Struts用Action,SpringMVC則是用Controller,
而要把Class當SpringMVC的Controller只要在Class前加上@Controller的annotation即可
基本的method則是return ModelAndView,然後在method前加上@RequestMapping的Annotation
下列這個Class說明當使用者輸入http://host/module/sayHello.do時即會呼叫HelloController.sayHello(),而回傳ModelAndView("hello")則是讓SpringMVC的ViewReslover找到對應的jsp。
package idv.elliot.web.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class HelloController { @RequestMapping("/sayHello") public ModelAndView sayHello() { return new ModelAndView("hello"); } }
(5)hello.jsp
重點是jsp存放的位置,而不是jsp,請記得之前viewResolver的設定,要放在/WEB-INF/jsp/下即可
只要輸入http://host/module/sayHello.do就可以看到結果,而所有專案資料的截圖如下