【SSH進階之路】一步步重構MVC實現Struts框架——完善轉向頁面,大功告成(六)

第四篇博客【SSH進階之路】一步步重構MVC實現Struts框架——封裝業務邏輯和跳轉路徑(四),我們解決了第一個問題:封裝業務邏輯和跳轉路徑。第五篇博客【SSH進階之路】一步步重構MVC實現Struts框架——徹底去掉Servlet中的邏輯判斷(五),我們解決了第二個問題:徹底去掉Servlet中的邏輯判斷。這篇我們解決最後一個問題,完善轉向頁面,顯示和控制分離。


比如添加用戶邏輯,成功不僅僅可以返回成功頁面,失敗也可以返回失敗頁面,代碼如下:


AddUserAction

[java] view plain copy
 print?
  1. package com.liang.action;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import com.liang.manager.UserManager;  
  7.   
  8. public class AddUserAction implements Action {  
  9.   
  10.     @Override  
  11.     public String execute(HttpServletRequest req, HttpServletResponse resp)  
  12.             throws Exception {  
  13.         //獲取參數  
  14.         String username = req.getParameter("username");  
  15.   
  16.         //調用業務邏輯  
  17.         UserManager userManager = new UserManager();  
  18.         try{  
  19.             //添加的業務邏輯  
  20.             userManager.add(username);  
  21.         }catch(Exception e){  
  22.             //返回添加失敗的界面  
  23.             return "/add_error.jsp";//轉向路徑可以通過配置文件讀取  
  24.         }     
  25.         //返回添加成功的界面  
  26.         return "/add_success.jsp";//轉向路徑可以通過配置文件讀取  
  27.     }  
  28.   
  29. }  

      從上篇博客中,我們知道,若想系統變的靈活,所有變化都配置到配置文件中,修改時,修改配置文件即可。因此,我們只需要在struts-config.xml中配置轉向頁面,不僅僅要有成功的轉向頁面,而且要有失敗的轉向頁面。


我們修改一下struts-config.xml,代碼如下:

[html] view plain copy
 print?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <action-config>  
  3.     <action-mappings>  
  4.         <!--根據不同的path路徑,訪問各自的Action  -->   
  5.         <action path="/servlet/addUser" type="com.liang.action.AddUserAction">  
  6.             <!-- 轉向頁面 -->  
  7.             <forward name="success" path="/add_success.jsp"></forward>  
  8.             <forward name="error" path="/add_error.jsp"></forward>  
  9.         </action>  
  10.           
  11.         <action path="/servlet/delUser" type="com.liang.action.DelUserAction">  
  12.             <forward name="success" path="/del_success.jsp"></forward>  
  13.             <forward name="error" path="/del_error.jsp"></forward>  
  14.         </action>  
  15.   
  16.         <action path="/servlet/modifyUser" type="com.liang.action.ModifyUserAction">  
  17.             <forward name="success" path="/modify_success.jsp"></forward>  
  18.             <forward name="error" path="/modify_error.jsp"></forward>  
  19.         </action>  
  20.           
  21.         <action path="/servlet/queryUser" type="com.liang.action.QueryUserAction">  
  22.             <forward name="success" path="/query_success.jsp">/</forward>  
  23.             <forward name="error" path="/query_error.jsp"></forward>  
  24.         </action>  
  25.     </action-mappings>  
  26. </action-config>  

      我們修改了配置文件,使用dom4j讀取配置,配置信息也需要放到一個map結構中,我們需要一個存儲轉向信息的map,因此,在ActionMapping中增加一個map。


ActionMapping

[java] view plain copy
 print?
  1. package com.liang.action;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. public class ActionMapping {  
  7.   
  8.     private String path;  
  9.     private String type;  
  10.     //存儲轉向信息的map  
  11.     Map forward = new HashMap();  
  12.       
  13.       
  14.     public Map getForward() {  
  15.         return forward;  
  16.     }  
  17.     public void setForward(Map forward) {  
  18.         this.forward = forward;  
  19.     }  
  20.     public String getType() {  
  21.         return type;  
  22.     }  
  23.     public void setType(String type) {  
  24.         this.type = type;  
  25.     }  
  26.     public String getPath() {  
  27.         return path;  
  28.     }  
  29.     public void setPath(String path) {  
  30.         this.path = path;  
  31.     }  
  32. }  

讀取配置需要發生相應的變化,但是我們有了上篇博客的例子,修改起來並不難。

ConfigInit

[java] view plain copy
 print?
  1. package com.liang.servlet;  
  2.   
  3. import java.io.File;  
  4. import java.util.HashMap;  
  5. import java.util.Iterator;  
  6. import java.util.Map;  
  7.   
  8. import org.dom4j.Document;  
  9. import org.dom4j.Element;  
  10. import org.dom4j.io.SAXReader;  
  11.   
  12. import com.liang.action.*;  
  13.   
  14. public class ConfigInit {  
  15.   
  16.     public static void init(String config) {  
  17.         // 創建saxReader對象  
  18.         SAXReader reader = new SAXReader();  
  19.         File f = new File(config);  
  20.         try {  
  21.             // 通過read方法讀取xml文件, 轉換成Document對象  
  22.             Document doc = reader.read(f);  
  23.             // 得到配置文件的根結點  
  24.             Element root = doc.getRootElement();  
  25.             Element actionmappings = (Element) root.element("action-mappings");  
  26.             // 解析action結點的所有參數  
  27.             for (Iterator j = actionmappings.elementIterator("action"); j  
  28.                     .hasNext();) {  
  29.                 Element am = (Element) j.next();  
  30.                 ActionMapping actionMapping = new ActionMapping();  
  31.   
  32.                 // 設置actionMapping的path和type  
  33.                 actionMapping.setPath(am.attributeValue("path"));  
  34.                 actionMapping.setType(am.attributeValue("type"));  
  35.   
  36.                 Map forward = new HashMap();  
  37.                 // 解析forward結點的所有參數  
  38.                 for (Iterator k = am.elementIterator("forward"); k.hasNext();) {  
  39.                     Element fo = (Element) k.next();  
  40.                     forward.put((String) fo.attributeValue("name"), (String) fo  
  41.                             .attributeValue("path"));  
  42.                 }  
  43.                 // 設置forward  
  44.                 //如果是添加ActionMapping的存儲如下;  
  45.                 /* 
  46.                  * actionMapping{ path="/servlet/addUser"; 
  47.                  * type="com.liang.action.AddUserAction"  
  48. <span style="white-space:pre">                </span> *forwardMap{ 
  49.                  * <span style="white-space:pre"> </span>key="success",value="/add_success.jsp" 
  50.                  * <span style="white-space:pre"> </span>key="error",value="/add_error.jsp" }  
  51. <span style="white-space:pre">                </span> *} 
  52.                  */  
  53.                 actionMapping.setForward(forward);  
  54.                 /* 
  55.                  * 上面Mappings.actions的存儲結構相當於將配置信息與映射一一對應 
  56.                  * map.put("/servlet/delUser", actionMapping); 
  57.                  * map.put("/servlet/addUser", actionMapping); 
  58.                  * map.put("/servlet/modifyUser", actionMapping); 
  59.                  * map.put("/servlet/queryUser", actionMapping); 
  60.                  */  
  61.                 Mappings.actions.put((String) am.attributeValue("path"),  
  62.                         actionMapping);  
  63.                   
  64.             }  
  65.         } catch (Exception e) {  
  66.             e.printStackTrace();  
  67.         }  
  68.     }  
  69. }  

我們的TestServlet只需要增加一句話,如下所示:


TestServlet

[java] view plain copy
 print?
  1. package com.liang.servlet;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import com.liang.action.Action;  
  11. import com.liang.action.ActionMapping;  
  12. import com.liang.action.Mappings;  
  13.   
  14.   
  15.   
  16. /** 
  17.  * 使用servlet做相關的控制,轉向多個(V)視圖 
  18.  * @author liang 
  19.  * 
  20.  */  
  21. public class TestServlet extends HttpServlet {  
  22.   
  23.     //需要讀取的文件名  
  24.     protected static String config = "/WEB-INF/struts-config.xml";  
  25.   
  26.     public void init() throws ServletException {  
  27.         //獲得文件的路徑  
  28.         //initialize();  
  29.         //根據web.xml中映射的目錄獲得文件在對應服務器中的真實路徑  
  30.         config = getServletContext().getRealPath("/")+ getInitParameter("config");  
  31.         //解析struts-config.xml配置文件  
  32.         ConfigInit.init(config);  
  33.     }  
  34.   
  35.     //根據web.xml中映射的目錄獲得文件在對應服務器中的真實路徑  
  36. //  private void initialize() {  
  37. //      try {  
  38. //          config = getServletContext().getRealPath("/")  
  39. //                  + getInitParameter("config");  
  40. //      } catch (Exception e) {  
  41. //          e.printStackTrace();  
  42. //      }  
  43. //  }  
  44.     @Override  
  45.     protected void doGet(HttpServletRequest request, HttpServletResponse response)  
  46.             throws ServletException, IOException {  
  47.           
  48.         //取得訪問的URI  
  49.         String reqeuestURI = request.getRequestURI();  
  50.         //截取URI,獲得路徑  
  51.         String path = reqeuestURI.substring(reqeuestURI.indexOf("/",1), reqeuestURI.indexOf("."));  
  52.           
  53.         Mappings mapings = new Mappings();  
  54.         // 根據截取的URL請求,到Map中取得本次請求對應的Action類  
  55.         ActionMapping actionMapping = (ActionMapping)mapings.actions.get(path);    
  56.         //取得本請求對應的Action類的完整路徑  
  57.         String type = actionMapping.getType(); //com.liang.action.DelUserAction  
  58.         //採用反射,動態實例化Action  
  59.         try {  
  60.             Action action = (Action)Class.forName(type).newInstance();  
  61.             // 採用多態的機制,動態調用Action中的execute方法,返回轉向路徑  
  62.             String result = action.execute(request, response);  
  63.               
  64.             //獲得真實轉向頁面  
  65.             String forward =(String)actionMapping.getForward().get(result);  
  66.               
  67.             //根據轉向路徑完成轉向  
  68.             request.getRequestDispatcher(forward).forward(request, response);  
  69.         } catch (InstantiationException e) {  
  70.             e.printStackTrace();  
  71.         } catch (IllegalAccessException e) {  
  72.             e.printStackTrace();  
  73.         } catch (ClassNotFoundException e) {  
  74.             e.printStackTrace();  
  75.         } catch (Exception e) {  
  76.             e.printStackTrace();  
  77.         }  
  78.              
  79.     }  
  80.   
  81.     @Override  
  82.     protected void doPost(HttpServletRequest request, HttpServletResponse response)  
  83.             throws ServletException, IOException {  
  84.         doGet(request,response);  
  85.     }  
  86.   
  87. }  


最後,我們看一下AddUserAction已經變得非常靈活了。

  

[java] view plain copy
 print?
  1. package com.liang.action;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import com.liang.manager.UserManager;  
  7.   
  8. public class AddUserAction implements Action {  
  9.   
  10.     @Override  
  11.     public String execute(HttpServletRequest req, HttpServletResponse resp)  
  12.             throws Exception {  
  13.         //獲取參數  
  14.         String username = req.getParameter("username");  
  15.   
  16.         //調用業務邏輯  
  17.         UserManager userManager = new UserManager();  
  18.         try{  
  19.             //添加的業務邏輯  
  20.             userManager.add(username);  
  21.         }catch(Exception e){  
  22.             //返回添加失敗的界面  
  23.             return "error";//和配置文件的配置一致  
  24.         }     
  25.         //返回添加成功的界面  
  26.         return "success";//和配置文件的配置一致  
  27.   
  28.     }  
  29.   
  30. }  


      大功告成,如果我們想換一個視圖顯示,我們只需要修改一個配置文件即可。我們用一張類圖回顧一下我們重構和封裝的歷程。


 

      到此刻爲止,我們重構MVC實現Struts框架的所有步驟都做完了。不難發現,其實框架並不難,只是咋一看特別神祕,當我們一步步重構,不斷封裝,不斷完善,Struts的雛形已經展現在我們的面前了。框架就是封裝的高度化,抽象的高度化。

       當然,它既然是一個雛形就絕對還有不完美的地方,比如,我們沒有像Struts一樣封裝ActionForm,自動完成數據類型的轉化,當然我們也可以從現在的基礎上進一步完善,但是我們就不再往下做了,我們瞭解它的基本思想就好,況且我們後面還有更加艱鉅的任務。

 

     經過幾篇博客的重構,我們實現了一個Struts的雛形,它可以讓我們認識mvc和struts的異同點,以及struts的封裝過程,對我們更加深入struts埋下了伏筆。下篇博客【SSH進階之路】Struts詳細實現流程,深入Struts(七),通過學習Struts的流程,進一步深入Struts。下篇博客見!


源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章