Petstore原始碼記縱記(3)一矞業邏輯處理 By歐亘修renshaw@ms4hinet.net 前官 透過前面的介貂’我們能夠了解 Petstore中 Model、 Controller丶Ⅵiew是如 何相互合作·現在讓筆者來說明 Petstore矞業邏輯( Business logic)的處理方式 首先讓我們先了解爲什麼要將矞業邏輯與資料展現( Presentation分開如此做有 下列的好處 1.減少程式變動的衝墼∶矞業邏輯及資料展現彼此獨立’不因蔄業邏輯改變而影 響資料展現的程式碼,反之亦然。 2.易於雜護∶將矞業邏輯集中管理’一旦日後有修改·僅須修改一個地方。 3.重複使用∶矞業邏輯若與資料展現層程式混在一趄·如仳矞業邏輯只能服務 種使用者介面( Client)·若將兩者分離’我們可以很容易擴充第二種使用者介面 4各司其職∶資料展現的設計人員與矞業邏輯的設計人員通常是不一樣的·彼此 獨立讓術業有專攻’品質及效率皆能提升。 隱形角色 在追縱 Petstore矞業邏輯處理方式前·我們先來看看 Petstore中的隱形角 色’這些隱形魚色在伺服器(RⅠ)啓動時即默默凖備好·待適當畤機爲 Petstore中 藺業邏輯處理服務’所以筆者須先介紹它們 請開啓 Petstore home(註 ) srclapps'petstorelsrcldocrootlWEB-INF\web. xml,我們可以看到 <I- Encoding filter declaration Start--> filter>/第一個 Fliter <filter-name> Encoding</filter-name> <display-name> Encoding Filter</display-name> description>no description</description> <filter-class>com. sun j2ee blueprints. encodingfilter web Encoding Filter <init-param <param-name>encoding</pa ram-name> <param-value>UTF-8</param-value> <-- Encoding filter declaration End--> <I- Signon filter declaration Start --> < filter>2.第二個 Filter
Petstore 原始碼記縱記(3)-商業邏輯處理 By 歐亘修 senshaw@ms4.hinet.net 前言 透過前面的介紹,我們能夠了解 Petstore 中 Model、Controller、View 是如 何相互合作,現在讓筆者來說明 Petstore 商業邏輯(Business Logic)的處理方式, 首先讓我們先了解為什麼要將商業邏輯與資料展現(Presentation)分開,如此做有 下列的好處: 1.減少程式變動的衝擊:商業邏輯及資料展現彼此獨立,不因商業邏輯改變而影 響資料展現的程式碼,反之亦然。 2.易於維護:將商業邏輯集中管理,一旦日後有修改,僅須修改一個地方。 3.重複使用:商業邏輯若與資料展現層程式混在一起,如此商業邏輯只能服務一 種使用者介面(Client),若將兩者分離,我們可以很容易擴充第二種使用者介面。 4.各司其職:資料展現的設計人員與商業邏輯的設計人員通常是不一樣的,彼此 獨立讓術業有專攻,品質及效率皆能提升。 隱形角色 在追縱 Petstore 商業邏輯處理方式前,我們先來看看 Petstore 中的隱形角 色,這些隱形角色在伺服器(RI)啟動時即默默準備好,待適當時機為 Petstore 中 商業邏輯處理服務,所以筆者須先介紹它們。 請開啟 Petstore_home(註 一)\src\apps\petstore\src\docroot\WEB-INF\web.xml,我們可以看到: <!-- Encoding Filter Declaration Start --> <filter> //1.第一個 Fliter <filter-name>EncodingFilter</filter-name> <display-name>EncodingFilter</display-name> <description>no description</description> <filter-class>com.sun.j2ee.blueprints.encodingfilter.web.EncodingFilter </filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <!-- Encoding Filter Declaration End --> <!-- Signon Filter Declaration Start --> <filter> //2.第二個 Filter
<filter-name>SignOn Filter</filter-name> <display-name>Sign</display-name> ription-no on</description> <filter-class>com.sun j2ee blueprints. signon web SignOn Filter</filter-class> <filter> <1--Signon Filter Declaration End--> <l-- Encoding Filter Mapping Start--> < filter-mapping>1第一個 Filter對應 <filter-name> Encoding Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <1--Encoding Filter Mapping End <1-- Signon Filter Mapping Start--> filter-mapping>∥第二個 Filter對應 <filter-name>SignOn Filter</filter-name> atter <l-- Signon Filter Mapping End--> <I--ComponentManager Listener--> listener.>/3.第一個 Listerner <listener-class>com.sun j2ee blueprints. petstore controller. web. Petstore Compon entManager</listener-class> </listener> <l-- SignOn Attribute Listener-> listener>/4.第二個 Listerner <listener-class>com. sun j2ee blueprints. petstore controller. web. SignOnNotifier</ listener-class> </listener> Filter與 Listener是 Servlet2.3增加的功能, Filter可以在接受使用者的 Request 之後,做一些檢査處理·若沒問題則把使用者要求的 Response丟回給使用者 反之則丟回系锍預設的處理畫面’最常使用的情況就是登入·在網頁應用系統中
<filter-name>SignOnFilter</filter-name> <display-name>SignOnFilter</display-name> <description>no description</description> <filter-class>com.sun.j2ee.blueprints.signon.web.SignOnFilter</filter-class> </filter> <!-- Signon Filter Declaration End --> <!-- Encoding Filter Mapping Start--> <filter-mapping> //第一個 Filter 對應 <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Encoding Filter Mapping End --> <!-- Signon Filter Mapping Start--> <filter-mapping> //第二個 Filter 對應 <filter-name>SignOnFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Signon Filter Mapping End --> <!-- ComponentManager Listener --> <listener> //3.第一個 Listerner <listener-class>com.sun.j2ee.blueprints.petstore.controller.web.PetstoreCompon entManager</listener-class> </listener> <!-- SignOn Attribute Listener --> <listener> //4.第二個 Listerner <listener-class>com.sun.j2ee.blueprints.petstore.controller.web.SignOnNotifier</ listener-class> </listener> Filter與Listener是Servlet2.3增加的功能,Filter可以在接受使用者的Request 之後,做一些檢查處理,若沒問題則把使用者要求的 Response 丟回給使用者, 反之則丟回系統預設的處理畫面,最常使用的情況就是登入,在網頁應用系統中
有些功能是必須登入扌能使用·過去的做法我們會將登廴檢查寫在這些個別功能 上’如此會造成登廴檢查若要修正’則必須逐支修改’造成時間浪費’運用Fier 我們可將登廴檢査程式與其他程式獨立’日後容易雜護σ Listener則是増加對 Context. session生命週期的控制’例如我們能夠在 Session初始化時’將所需使 用的資料一起產生’並將 Reference存廴 Session, seesion關閉時可順便將相關 資源移除’如此資源集中控管’容易雜護 Encoding Filter 它的程式碼位置在 Petstore homelsrclcomponentslencodingfilter\\\sun j2eelblueprintslencodingfil terlweb\Encoding Filter. java,它會再讀取 web. xm(位置在 Petstore home\\\petstorelsrcldocrootIWEB- INF\web. xm)中的參數,決定編 碼方式再將其設入 Request中 <I- Encoding filter Declaration Start --> <filter-name>Encoding Filter</filter-name> <display-name> Encoding Filter</display-name> description>no description</description> <filter-class>com. sun. 2ee blueprints. encodingfilter web Encoding Filter </filter-class> <init-param>/設定糯碼方式参數 <param-name>encoding</param-name> param-value>UTF-8</param-value> <init-param> Encoding Filter. java public class Encoding Filter implements Filter i private Filter Config config=null ∥/ default to ascll private String targetEncoding="ASCII", 初始化時讀取参數 public void init(Filter Config config) throws Servlet Exception this config= confi
有些功能是必須登入才能使用,過去的做法我們會將登入檢查寫在這些個別功能 上,如此會造成登入檢查若要修正,則必須逐支修改,造成時間浪費,運用 Filter, 我們可將登入檢查程式與其他程式獨立,日後容易維護。Listener 則是增加對 Context,Session 生命週期的控制,例如我們能夠在 Session 初始化時,將所需使 用的資料一起產生,並將 Reference 存入 Session,Seesion 關閉時可順便將相關 資源移除,如此資源集中控管,容易維護。 Encoding Filter 它的程式碼位置在 Petstore_home\src\components\encodingfilter\src\com\sun\j2ee\blueprints\encodingfil ter\web\EncodingFilter.java,它會再讀取 web.xml(位置在 Petstore_home\src\apps\petstore\src\docroot\WEB-INF\web.xml)中的參數,決定編 碼方式再將其設入 Request 中: web.xml <!-- Encoding Filter Declaration Start --> <filter> <filter-name>EncodingFilter</filter-name> <display-name>EncodingFilter</display-name> <description>no description</description> <filter-class>com.sun.j2ee.blueprints.encodingfilter.web.EncodingFilter </filter-class> <init-param> //設定編碼方式參數 <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> EncodingFilter.java public class EncodingFilter implements Filter { private FilterConfig config = null; // default to ASCII private String targetEncoding = "ASCII"; //初始化時讀取參數 public void init(FilterConfig config) throws ServletException { this.config = config;
this target Encoding- config. getInitParameter("encoding") public void destroy( config= null target Encoding=null; /將糯碼方式参數存入 reqeust;結束此 Filter public void do Filter(ServletRequest srequest, ServletResponse response FilterChain chain) throws IOException, Servlet Exception t HttpservletrEquestrequest=(httpServletrequest)sreqUest; request. setCharacter Encoding(target Encoding) ∥/ move on to the next chain. doFilter(srequest, response) 筆者覺得這個 Filter滿有用的ν可以單獨運用在傳統 JSPHJavaBεas的web Application在 Tomcat3.2ⅹ·預設編碼是UTF-8·所以我們處理中文時’必須自 行在程式中處理·在存廴資料庫前須將中文字編碼由 Unicode轉成Big5;到了 Tomcat33x; Tomcat會從OS取得預設編碼方式’所以我們不必再自行處理;到 了 Tomcat4.0x之後,情況又回到與 Tomcat3.2.x一樣,筆者開發 Web application 就碰到這個情況·歴經三個版本的 Tomaα·程式改過來改過去的’儘做些白工 後來筆者改運用這個 Filter’就不需在存廴資料庫前須將中文字編碼由 Unicode 轉成Big5。 ComponentManager Listener 第二個 Filter主要掌管登入’與本次主題有密切關係’爲使流程順暢’所以 稍後再說明我們來看第一個 Listener,它的主要功能是作爲服務連結提供者 當使用者進入本系統時·應用伺服器( Application Sever)會在 Session產生時會建 置儲存服務連結容器’並將其置廴 Session·待後續程式服務產生後使用 Default Component Manager. java,原始碼在 Petstore homelsrclwaflsrclcontrollerIcomlsunlj2eelblueprintslwaf\controllerlweb
this.targetEncoding = config.getInitParameter("encoding"); } public void destroy() { config = null; targetEncoding = null; } //將編碼方式參數存入 reqeust,結束此 Filter public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)srequest; request.setCharacterEncoding(targetEncoding); // move on to the next chain.doFilter(srequest,sresponse); } } 筆者覺得這個 Filter 滿有用的,可以單獨運用在傳統 JSP+JavaBeans 的 Web Application,在 Tomcat3.2.x,預設編碼是 UTF-8,所以我們處理中文時,必須自 行在程式中處理,在存入資料庫前須將中文字編碼由 Unicode 轉成 Big5;到了 Tomcat3.3.x,Tomcat 會從 OS 取得預設編碼方式,所以我們不必再自行處理;到 了 Tomcat4.0.x 之後,情況又回到與 Tomcat3.2.x 一樣,筆者開發 Web Application 就碰到這個情況,歷經三個版本的 Tomcat,程式改過來改過去的,儘做些白工, 後來筆者改運用這個 Filter,就不需在存入資料庫前須將中文字編碼由 Unicode 轉成 Big5。 ComponentManager Listener 第二個 Filter 主要掌管登入,與本次主題有密切關係,為使流程順暢,所以 稍後再說明。我們來看第一個 Listener,它的主要功能是作為服務連結提供者, 當使用者進入本系統時,應用伺服器(Application Sever)會在 Session 產生時會建 置儲存服務連結容器,並將其置入 Session,待後續程式服務產生後使用。 DefaultComponentManager.java,原始碼在 Petstore_home\src\waf\src\controller\com\sun\j2ee\blueprints\waf\controller\web
oublicvoidsessioncreated(httpsessionEventse)i Httpsession session=se. getsessiono /產生服務連結容器 sl= ServiceLocator. getInstanceo /腐本 Listener存入 Session session.setAttribute( WebKeys COMPONENT MANAGER, this) ServiceLacator. java,原始碼在 Petstore homesrclcomponents\servicelocatorlsrcIcom\sun j2eeblueprintsserviceloca torlweb’此類別寫法滿特別的大家又可多學種程式設計技巧·追縱前輩原始 碼·除了能夠了解各種功能如何設計之外’程式碼分解( Refactor丶撰寫風格 設計技巧·對我們來說都是很重要的收穫! Servicelacator基本上它是一個BJB 及JMS資源連結服務提供者·且它的服務不因使用者不同而有所改變,所以它 使用 static寫法來達到這個效果。 public class ServiceLocator i private InitialContext ic; private Map cache; //used to hold references to EJBHomes/JMS Resources for private static Servicelocator me /初次宣告此物件時會執行初始化動作 me = new Servicelocator(; i catch(ServiceLocator Exception se)( System. err println(se); seprintStackTrace(System. err); /建構子產生JNDI連結及同步化 Hash Map容器 private ServicelocatorO throws ServiceLocator Exception ic= new InitialContexto cache= Collections. synchronizedMap(new HashMapo); i catch(Naming Exception ne)i
public void sessionCreated(HttpSessionEvent se) { HttpSession session = se.getSession(); //產生服務連結容器 sl = ServiceLocator.getInstance(); //將本 Listener 存入 Session session.setAttribute(WebKeys.COMPONENT_MANAGER, this); } ServiceLacator.java,原始碼在 Petstore_home\src\components\servicelocator\src\com\sun\j2ee\blueprints\serviceloca tor\web,此類別寫法滿特別的,大家又可多學一種程式設計技巧,追縱前輩原始 碼,除了能夠了解各種功能如何設計之外,程式碼分解(Refactor)、撰寫風格、 設計技巧,對我們來說都是很重要的收穫!ServiceLacator 基本上它是一個 EJB 及 JMS 資源連結服務提供者,且它的服務不因使用者不同而有所改變,所以它 使用 static 寫法來達到這個效果。 public class ServiceLocator { private InitialContext ic; private Map cache; //used to hold references to EJBHomes/JMS Resources for //re-use private static ServiceLocator me; //初次宣告此物件時會執行初始化動作 static { try { me = new ServiceLocator(); } catch(ServiceLocatorException se) { System.err.println(se); se.printStackTrace(System.err); } } //建構子,產生 JNDI 連結及同步化 HashMap 容器 private ServiceLocator() throws ServiceLocatorException { try { ic = new InitialContext(); cache = Collections.synchronizedMap(new HashMap()); } catch (NamingException ne) {