第四篇博客【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 {
- @Override
- public 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;
- //存儲轉向信息的map
- Map 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和type
- actionMapping.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();
- // }
- // }
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //取得訪問的URI
- String 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
- //採用反射,動態實例化Action
- try {
- 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();
- }
- }
- @Override
- protected 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 {
- @Override
- public 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。下篇博客見!