熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

設計模式:設計自己的MVC框架

2013-11-23 19:52:43  來源: Java高級技術 
源代碼放在的郵箱的收件箱裡用戶名:sharesource密碼:javafans
希望保留給有用的人謝謝

    取這樣一個標題太大吸引眼球嘛@_@

    事實是最近讀《JEE設計模式》講述表達層模式的那幾章書中有一個前端控制器+command模式的workflow例子就琢磨著可以很簡單地擴展成一個MVC框架花了一個下午改寫了下對書中所述的理解更為深入我想這也許對於學習和理解設計模式以及初次接觸struts等MVC框架的人可能有點幫助因為整個模型類似於struts我把它取名叫strutslet^_^學習性質切勿認真

(一)完整的類圖如下


前端控制器(FrontController):前端控制器提供了一個統一的位置來封裝公共請求處理它的任務相當簡單執行公共的任務然後把請求轉交給相應的控制器在strutslet中前端控制器主要作用也在於此它初始化並解析配置文件接受每個請求並簡單地把請求委托給調度器(Dispatcher)由調度器執行相應的動作(Action)調度器把action返回的url返回給FrontControllerFrontController負責轉發

Action接口command模式很好的例子它是一個命令接口每一個實現了此接口的action都封裝了某一個請求新增一條數據記錄並更新model或者把某個文件寫入磁盤命令解耦了發送者和接受者之間聯系 發送者調用一個操作接受者接受請求執行相應的動作因為使用Command模式解耦發送者無需知道接受者任何接口

Dispatcher調度器負責流程的轉發負責調用action去執行業務邏輯由調度器選擇頁面和action它去除了應用行為和前端控制器間的耦合調度器服務於前端控制器它把model的更新委托給action又提供頁面選擇給FrontController

ActionForward封裝了轉向操作所需要信息的一個模型包括name和轉向url

ActionModel解析配置文件後將每一個Action封裝成一個ActionModel對象所有ActionModel構成一個map並存儲在ServletContext中供整個框架使用


(二)源代碼簡單分析
Action接口只有一個execute方法任何一個action都只要實現此接口並實現相應的業務邏輯最後返回一個ActionForward提供給Dispacher調用



    public interface Action {
     public ActionForward execute(HttpServletRequest requestServletContext context); 
    }


比如我們要實現一個登陸系統(demo的例子)LoginAction驗證用戶名和密碼如果正確返回success頁面如果登陸失敗返回fail頁面



    public class LoginAction implements Action {

     private String name=;
     public ActionForward execute(HttpServletRequest request
       ServletContext context) {
      String userName=requestgetParameter(userName);
      String password=requestgetParameter(password);
            if(userNameequals(dennis)&&passwordequals()){
          requestsetAttribute(name name);
          return ActionForwardSUCCESS;  //登陸成功返回success
            }else
             return ActionForwardFAIL;    //否則返回fail
     }

  還是先來看下兩個模型ActionForward和ActionModel沒什麼東西屬性以及相應的gettersetter方法




    /**
     * 類說明:轉向模型
     * @author dennis
     *
     * */
    public class ActionForward {
     private String name;      //forward的name
     private String viewUrl;   //forward的url
     public static final ActionForward SUCCESS=new ActionForward(success);
     public static final ActionForward FAIL=new ActionForward(fail);

     public  ActionForward(String name){
      thisname=name;
     }

     public ActionForward(String name String viewUrl) {
      super();
      thisname = name;
      thisviewUrl = viewUrl;
     }

     //name和viewUrl的getter和setter方法

    }   

我們看到ActionForward預先封裝了SUCCESS和FAIL對象



    public class ActionModel {
     private String path; // action的path

     private String className; // action的class

     private Map<String ActionForward> forwards; // action的forward

     public ActionModel(){}

     public ActionModel(String path String className
       Map<String ActionForward> forwards) {
      super();
      thispath = path;
      thisclassName = className;
      thisforwards = forwards;
     }


     //相應的getter和setter方法     

    }


知道了兩個模型是什麼樣也應該可以猜到我們的配置文件大概是什麼樣的了與struts的配置文件格式類似



    <?xml version= encoding=UTF?>
    <actions>
      <action path=/login
              class=comstrutsletdemoLoginAction>
         <forward name=success url=hellojsp/>
         <forward name=fail url=failjsp/>
       </action>       
    </actions>

path是在應用中將被調用的路徑class指定了調用的哪個actionforward元素指定了轉向比如我們這裡如果是success就轉向hellojsp失敗的話轉向failjsp這裡配置了demo用到的LoginAction

Dispacher接口主要是getNextPage方法此方法負責獲得下一個頁面將導向哪裡提供給前端控制器轉發



    public interface Dispatcher {
     public void setServletContext(ServletContext context);
     public String getNextPage(HttpServletRequest requestServletContext context);
    }


原先書中實現了一個WorkFlow的Dispatcher按照順序調用action實現工作流調用而我們所需要的是根據請求的path調用相應的action執行action的execute方法返回一個ActionForward然後得到ActionForward的viewUrl將此viewUrl提供給前端控制器轉發看看它的getNextPage方法




    public String getNextPage(HttpServletRequest request ServletContext context) {
      setServletContext(context);

      Map<String ActionModel> actions = (Map<String ActionModel>) context
        getAttribute(ConstantACTIONS_ATTR);   //從ServletContext得到所有action信息
      String reqPath = (String) requestgetAttribute(ConstantREQUEST_ATTR);//發起請求的path
      ActionModel actionModel = actionsget(reqPath);  //根據path得到相應的action
      String forward_name = ;
      ActionForward actionForward;
      try {
       Class c = ClassforName(actionModelgetClassName());  //每個請求對應一個action實例

       Action action = (Action) cnewInstance();
       actionForward = actionexecute(request context);  //執行action的execute方法
       forward_name = actionForwardgetName();
       
      } catch (Exception e) {
       logerror(can not find action +actionModelgetClassName());
       eprintStackTrace();
      }

      actionForward = actionModelgetForwards()get(forward_name);
      if (actionForward == null) {
       logerror(can not find page for forward +forward_name);
       return null;
      } else
       return actionForwardgetViewUrl();      //返回ActionForward的viewUrl
     }

  前端控制器(FrontController)它的任務我們已經很清楚初始化配置文件存儲所有action到ServletContext供整個框架使用得到發起請求的path提供給Dispachter查找相應的action調用Dispatcher執行getNextPage方法得到下一個頁面的url並轉發




    public void init() throws ServletException {

      //初始化配置文件

      ServletContext context=getServletContext();
      String config_file =getServletConfig()getInitParameter(config);
      String dispatcher_name=getServletConfig()getInitParameter(dispatcher);
      if (config_file == null || config_fileequals())
       config_file = /WEBINF/strutsletconfigxml//默認是/WEBINF/下面的strutsletconfig
      if(dispatcher_name==null||dispatcher_nameequals())
       dispatcher_name=ConstantDEFAULT_DISPATCHER;
        
      try {
       Map<String ActionModel> resources = ConfigUtilnewInstance()  //工具類解析配置文件
         parse(config_file context);
       contextsetAttribute(ConstantACTIONS_ATTR resources);  //存儲在ServletContext中
       (初始化strutslet配置文件成功);
      } catch (Exception e) {
       logerror(初始化strutslet配置文件失敗);
       eprintStackTrace();
      }

      //實例化Dispacher

      try{
       Class c = ClassforName(dispatcher_name);
          Dispatcher dispatcher = (Dispatcher) cnewInstance();
          contextsetAttribute(ConstantDISPATCHER_ATTR dispatcher); //放在ServletContext
          (初始化Dispatcher成功);
      }catch(Exception e) {
        logerror(初始化Dispatcher失敗);
          eprintStackTrace();
      }

      


doGet()和doPost方法我們都讓它調用process方法



    protected void process(HttpServletRequest request
       HttpServletResponse response) throws ServletException IOException {
      ServletContext context = getServletContext();

            //獲取action的path 
      String reqURI = requestgetRequestURI();
      int i=reqURIlastIndexOf();
      String contextPath=requestgetContextPath();
      String path=reqURIsubstring(contextPathlength()i);
      
      requestsetAttribute(ConstantREQUEST_ATTR path);
      Dispatcher dispatcher = (Dispatcher) contextgetAttribute(ConstantDISPATCHER_ATTR);

      // make sure we dont cache dynamic data
      responsesetHeader(CacheControl nocache);
      responsesetHeader(Pragma nocache);

      // use the dispatcher to find the next page
      String nextPage = dispatchergetNextPage(request context);//調用Dispatcher的getNextPage

      // forward control to the view
      RequestDispatcher forwarder = requestgetRequestDispatcher(/
        + nextPage);
      forwarderforward(request response);  //轉發頁面
     }


最後webxml的配置就非常簡單了配置前端控制器提供啟動參數(配置文件所在位置為空就查找/WEBINF/下面的strutsletconfigxml文件)我們把所有以action結尾的請求都交給FrontController處理



    <servlet>
        <servletname>StrutsletController</servletname>
        <servletclass>reFrontController</servletclass>
        <!  
        <initparam>
             <paramname>config</paramname>
             <paramvalue>/WEBINFstrutsletconfigxml</paramvalue>
        </initparam>
        >
           <loadonstartup></loadonstartup>
      </servlet>
     <servletmapping>
        <servletname>StrutsletController</servletname>
        <urlpattern>*action</urlpattern>
     </servletmapping>


最後讓我們看看整個框架圖
 


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27610.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.