標籤:struts ssh 重構 架構 map
目錄:
【SSH進階之路】Struts基本原理 + 實現簡單登入(二)
【SSH進階之路】一步步重構MVC實現Struts架構——從一個簡單MVC開始(三)
【SSH進階之路】一步步重構MVC實現Struts架構——封裝商務邏輯和跳轉路徑(四)
【SSH進階之路】一步步重構MVC實現Struts架構——徹底去掉邏輯判斷(五)
【SSH進階之路】一步步重構MVC實現Struts架構——完善轉向頁面,大功告成(六)
第四篇部落格【SSH進階之路】一步步重構MVC實現Struts架構——封裝商務邏輯和跳轉路徑(四),我們解決了第一個問題:封裝商務邏輯和跳轉路徑。第五篇部落格【SSH進階之路】一步步重構MVC實現Struts架構——徹底去掉Servlet中的邏輯判斷(五),我們解決第二個問題:徹底去掉Servlet中的邏輯判斷。這篇我們解決最後一個問題,完善轉向頁面,顯示和控制分離。
比如添加使用者邏輯,成功不僅僅可以返回成功頁面,失敗也可以返回失敗頁面,代碼如下:
AddUserAction
package com.liang.action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.liang.manager.UserManager;public class AddUserAction implements Action {@Overridepublic String execute(HttpServletRequest req, HttpServletResponse resp)throws Exception {//擷取參數String username = req.getParameter("username");//調用商務邏輯UserManager userManager = new UserManager();try{//添加的商務邏輯userManager.add(username);}catch(Exception e){//返回添加失敗的介面return "/add_error.jsp";//轉向路徑可以通過設定檔讀取}//返回添加成功的介面return "/add_success.jsp";//轉向路徑可以通過設定檔讀取}}
從上篇部落格中,我們知道,若想系統變的靈活,所有變化都配置到設定檔中,修改時,修改設定檔即可。因此,我們只需要在struts-config.xml中配置轉向頁面,不僅僅要有成功的轉向頁面,而且要有失敗的轉向頁面。
我們修改一下struts-config.xml,代碼如下:
<?xml version="1.0" encoding="UTF-8"?><action-config><action-mappings> <!--根據不同的path路徑,訪問各自的Action --> <action path="/servlet/addUser" type="com.liang.action.AddUserAction"><!-- 轉向頁面 --><forward name="success" path="/add_success.jsp"></forward><forward name="error" path="/add_error.jsp"></forward></action><action path="/servlet/delUser" type="com.liang.action.DelUserAction"><forward name="success" path="/del_success.jsp"></forward><forward name="error" path="/del_error.jsp"></forward></action><action path="/servlet/modifyUser" type="com.liang.action.ModifyUserAction"><forward name="success" path="/modify_success.jsp"></forward><forward name="error" path="/modify_error.jsp"></forward></action><action path="/servlet/queryUser" type="com.liang.action.QueryUserAction"><forward name="success" path="/query_success.jsp">/</forward><forward name="error" path="/query_error.jsp"></forward></action></action-mappings></action-config>
我們修改了設定檔,使用dom4j讀取配置,配置資訊也需要放到一個map結構中,我們需要一個儲存轉向資訊的map,因此,在ActionMapping中增加一個map。
ActionMapping
package com.liang.action;import java.util.HashMap;import java.util.Map;public class ActionMapping {private String path;private String type;//儲存轉向資訊的mapMap forward = new HashMap();public Map getForward() {return forward;}public void setForward(Map forward) {this.forward = forward;}public String getType() {return type;}public void setType(String type) {this.type = type;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}}
讀取配置需要發生相應的變化,但是我們有了上篇部落格的例子,修改起來並不難。
ConfigInit
package com.liang.servlet;import java.io.File;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import com.liang.action.*;public class ConfigInit {public static void init(String config) {// 建立saxReader對象SAXReader reader = new SAXReader();File f = new File(config);try {// 通過read方法讀取xml檔案, 轉換成Document對象Document doc = reader.read(f);// 得到設定檔的根結點Element root = doc.getRootElement();Element actionmappings = (Element) root.element("action-mappings");// 解析action結點的所有參數for (Iterator j = actionmappings.elementIterator("action"); j.hasNext();) {Element am = (Element) j.next();ActionMapping actionMapping = new ActionMapping();// 設定actionMapping的path和typeactionMapping.setPath(am.attributeValue("path"));actionMapping.setType(am.attributeValue("type"));Map forward = new HashMap();// 解析forward結點的所有參數for (Iterator k = am.elementIterator("forward"); k.hasNext();) {Element fo = (Element) k.next();forward.put((String) fo.attributeValue("name"), (String) fo.attributeValue("path"));}// 設定forward//如果是添加ActionMapping的儲存如下;/* * actionMapping{ path="/servlet/addUser"; * type="com.liang.action.AddUserAction" <span style="white-space:pre"></span> *forwardMap{ * <span style="white-space:pre"></span>key="success",value="/add_success.jsp" * <span style="white-space:pre"></span>key="error",value="/add_error.jsp" } <span style="white-space:pre"></span> *} */actionMapping.setForward(forward);/* * 上面Mappings.actions的儲存結構相當於將配置資訊與映射一一對應 * map.put("/servlet/delUser", actionMapping); * map.put("/servlet/addUser", actionMapping); * map.put("/servlet/modifyUser", actionMapping); * map.put("/servlet/queryUser", actionMapping); */Mappings.actions.put((String) am.attributeValue("path"),actionMapping);}} catch (Exception e) {e.printStackTrace();}}}
我們的TestServlet只需要增加一句話,如下所示:
TestServlet
package com.liang.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.liang.action.Action;import com.liang.action.ActionMapping;import com.liang.action.Mappings;/** * 使用servlet做相關的控制,轉向多個(V)視圖 * @author liang * */public class TestServlet extends HttpServlet {//需要讀取的檔案名稱protected static String config = "/WEB-INF/struts-config.xml";public void init() throws ServletException {//獲得檔案的路徑//initialize();//根據web.xml中映射的目錄獲得檔案在對應伺服器中的真實路徑config = getServletContext().getRealPath("/")+ getInitParameter("config");//解析struts-config.xml設定檔ConfigInit.init(config);}//根據web.xml中映射的目錄獲得檔案在對應伺服器中的真實路徑//private void initialize() {//try {//config = getServletContext().getRealPath("/")//+ getInitParameter("config");//} catch (Exception e) {//e.printStackTrace();//}//}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//取得訪問的URIString reqeuestURI = request.getRequestURI();//截取URI,獲得路徑String path = reqeuestURI.substring(reqeuestURI.indexOf("/",1), reqeuestURI.indexOf("."));Mappings mapings = new Mappings();// 根據截取的URL請求,到Map中取得本次請求對應的Action類ActionMapping actionMapping = (ActionMapping)mapings.actions.get(path); //取得本請求對應的Action類的完整路徑String type = actionMapping.getType(); //com.liang.action.DelUserAction//採用反射,動態執行個體化Actiontry {Action action = (Action)Class.forName(type).newInstance();// 採用多態的機制,動態調用Action中的execute方法,返迴轉向路徑String result = action.execute(request, response);//獲得真實轉向頁面String forward =(String)actionMapping.getForward().get(result);//根據轉向路徑完成轉向request.getRequestDispatcher(forward).forward(request, response);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} }@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request,response);}}
最後,我們看一下AddUserAction已經變得非常靈活了。
package com.liang.action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.liang.manager.UserManager;public class AddUserAction implements Action {@Overridepublic String execute(HttpServletRequest req, HttpServletResponse resp)throws Exception {//擷取參數String username = req.getParameter("username");//調用商務邏輯UserManager userManager = new UserManager();try{//添加的商務邏輯userManager.add(username);}catch(Exception e){//返回添加失敗的介面return "error";//和設定檔的配置一致}//返回添加成功的介面return "success";//和設定檔的配置一致}}
大功告成,如果我們想換一個視圖顯示,我們只需要修改一個設定檔即可。我們用一張類圖回顧一下我們重構和封裝的曆程。
到此刻為止,我們重構MVC實現Struts架構的所有步驟都做完了。不難發現,其實架構並不難,只是咋一看特別神秘,當我們一步步重構,不斷封裝,不斷完善,Struts的雛形已經展現在我們的面前了。架構就是封裝的高度化,抽象的高度化。
當然,它既然是一個雛形就絕對還有不完美的地方,比如,我們沒有像Struts一樣封裝ActionForm,自動完成資料類型的轉化,當然我們也可以從現在的基礎上進一步完善,但是我們就不再往下做了,我們瞭解它的基本思想就好,況且我們後面還有更加艱巨的任務。
經過幾篇部落格的重構,我們實現了一個Struts的雛形,它可以讓我們認識mvc和struts的異同點,以及struts的封裝過程,對我們更加深入struts埋下了伏筆。下篇部落格【SSH進階之路】Struts詳細實現流程,深入Struts(七),通過學習Struts的流程,進一步深入Struts。下篇部落格見!
【SSH進階之路】一步步重構MVC實現Struts架構——完善轉向頁面,大功告成(六)