<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    設計自己的MVC框架

    Posted on 2007-02-06 11:54 dennis 閱讀(2425) 評論(2)  編輯  收藏 所屬分類: 模式與架構

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

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

    (一)完整的類圖如下:

    ????? 10fd68bb171.jpg

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

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

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

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

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

    (二)源代碼分析:

    ?1。Action接口,只有一個execute方法,任何一個action都只要實現此接口,并實現相應的業務邏輯,最后返回一個ActionForward,提供給Dispacher調用。

    ?

    package ?com.strutslet.core;

    import ?javax.servlet.ServletContext;
    import ?javax.servlet.http.HttpServletRequest;

    import ?com.strutslet.model.ActionForward;

    /**
    ?*?command接口
    ?*?
    @author ?dennis
    ?*
    ?
    */

    public ? interface ?Action? {
    ?
    public ?ActionForward?execute(HttpServletRequest?request,ServletContext?context);?
    }


    ?

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

    package ?com.strutslet.demo;

    import ?javax.servlet.ServletContext;
    import ?javax.servlet.http.HttpServletRequest;

    import ?com.strutslet.core.Action;
    import ?com.strutslet.model.ActionForward;

    public ? class ?LoginAction? implements ?Action? {

    ?
    private ?String?name = "" ;
    ?
    public ?ActionForward?execute(HttpServletRequest?request,
    ???ServletContext?context)?
    {
    ??String?userName
    = request.getParameter( " userName " );
    ??String?password
    = request.getParameter( " password " );
    ????????
    if (userName.equals( " dennis " ) && password.equals( " 123 " )) {
    ??????request.setAttribute(
    " name " ,?name);
    ??????
    return ?ActionForward.SUCCESS;?? // 登陸成功,返回success
    ????????}
    else
    ?????????
    return ?ActionForward.FAIL;???? // 否則,返回fail
    ?}


    }



    2。還是先來看下兩個模型:ActionForward和ActionModel,沒什么東西,屬性以及相應的getter,setter方法:

    package ?com.strutslet.model;

    /**
    ?*?類說明:轉向模型
    ?*?
    @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) {
    ??
    this .name = name;
    ?}


    ?
    public ?ActionForward(String?name,?String?viewUrl)? {
    ??
    super ();
    ??
    this .name? = ?name;
    ??
    this .viewUrl? = ?viewUrl;
    ?}


    ?
    // name和viewUrl的getter和setter方法

    }
    ???

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

    // ActionModel.java

    package ?com.strutslet.model;

    import ?java.util.Map;

    /**
    ?*?類說明:
    ?*?
    @author ?dennis
    ?*
    ?
    */


    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 ();
    ??
    this .path? = ?path;
    ??
    this .className? = ?className;
    ??
    this .forwards? = ?forwards;
    ?}



    ?
    // 相應的getter和setter方法?????

    }



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

    ?

    <? xml?version = " 1.0 " ?encoding = " UTF-8 " ?>
    < actions >
    ??
    < action?path = " /login "
    ??????????
    class = " com.strutslet.demo.LoginAction " >
    ?????
    < forward?name = " success " ?url = " hello.jsp " />
    ?????
    < forward?name = " fail " ?url = " fail.jsp " />
    ???
    </ action > ???????
    </ actions >

    ?

    path是在應用中將被調用的路徑,class指定了調用的哪個action,forward元素指定了轉向,比如我們這里如果是success就轉向hello.jsp,失敗的話轉向fail.jsp,這里配置了demo用到的LoginAction。

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

    package ?com.strutslet.core;


    import ?javax.servlet.ServletContext;
    import ?javax.servlet.http.HttpServletRequest;

    /**
    ?*?service?to?worker模式,提供給FrontController使用
    ?*?負責流程轉發
    ?*?
    @author ?dennis
    ?*
    ?
    */

    public ? interface ?Dispatcher? {
    ?
    public ? void ?setServletContext(ServletContext?context);
    ?
    public ?String?getNextPage(HttpServletRequest?request,ServletContext?context);
    }



    5。原先書中實現了一個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(Constant.ACTIONS_ATTR);???
    // 從ServletContext得到所有action信息
    ??String?reqPath? = ?(String)?request.getAttribute(Constant.REQUEST_ATTR); // 發起請求的path
    ??ActionModel?actionModel? = ?actions.get(reqPath);?? // 根據path得到相應的action
    ??String?forward_name? = ? "" ;
    ??ActionForward?actionForward;
    ??
    try ? {
    ???Class?c?
    = ?Class.forName(actionModel.getClassName());?? // 每個請求對應一個action實例

    ???Action?action?
    = ?(Action)?c.newInstance();
    ???actionForward?
    = ?action.execute(request,?context);?? // 執行action的execute方法
    ???forward_name? = ?actionForward.getName();
    ???
    ??}
    ? catch ?(Exception?e)? {
    ???log.error(
    " can?not?find?action? " + actionModel.getClassName());
    ???e.printStackTrace();
    ??}


    ??actionForward?
    = ?actionModel.getForwards().get(forward_name);
    ??
    if ?(actionForward? == ? null )? {
    ???log.error(
    " can?not?find?page?for?forward? " + forward_name);
    ???
    return ? null ;
    ??}
    ? else
    ???
    return ?actionForward.getViewUrl();?????? // 返回ActionForward的viewUrl
    ?}



    6。前端控制器(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_file.equals( "" ))
    ???config_file?
    = ? " /WEB-INF/strutslet-config.xml " ;? // 默認是/WEB-INF/下面的strutslet-config
    ?? if (dispatcher_name == null || dispatcher_name.equals( "" ))
    ???dispatcher_name
    = Constant.DEFAULT_DISPATCHER;
    ????
    ??
    try ? {
    ???Map
    < String,?ActionModel > ?resources? = ?ConfigUtil.newInstance()?? // 工具類解析配置文件
    ?????.parse(config_file,?context);
    ???context.setAttribute(Constant.ACTIONS_ATTR,?resources);??
    // 存儲在ServletContext中
    ???log.info( " 初始化strutslet配置文件成功 " );
    ??}
    ? catch ?(Exception?e)? {
    ???log.error(
    " 初始化strutslet配置文件失敗 " );
    ???e.printStackTrace();
    ??}


    ??
    // 實例化Dispacher

    ??
    try {
    ???Class?c?
    = ?Class.forName(dispatcher_name);
    ??????Dispatcher?dispatcher?
    = ?(Dispatcher)?c.newInstance();
    ??????context.setAttribute(Constant.DISPATCHER_ATTR,?dispatcher);?
    // 放在ServletContext
    ??????log.info( " 初始化Dispatcher成功 " );
    ??}
    catch (Exception?e)? {
    ????log.error(
    " 初始化Dispatcher失敗 " );
    ??????e.printStackTrace();
    ??}


    ??..


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

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

    ????????
    // 獲取action的path?
    ??String?reqURI? = ?request.getRequestURI();
    ??
    int ?i = reqURI.lastIndexOf( " . " );
    ??String?contextPath
    = request.getContextPath();
    ??String?path
    = reqURI.substring(contextPath.length(),i);
    ??
    ??request.setAttribute(Constant.REQUEST_ATTR,?path);
    ??Dispatcher?dispatcher?
    = ?(Dispatcher)?context.getAttribute(Constant.DISPATCHER_ATTR);

    ??
    // ?make?sure?we?don't?cache?dynamic?data
    ??response.setHeader( " Cache-Control " ,? " no-cache " );
    ??response.setHeader(
    " Pragma " ,? " no-cache " );

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

    ??
    // ?forward?control?to?the?view
    ??RequestDispatcher?forwarder? = ?request.getRequestDispatcher( " / "
    ????
    + ?nextPage);
    ??forwarder.forward(request,?response);??
    // 轉發頁面
    ?}



    7。最后,web.xml的配置就非常簡單了,配置前端控制器,提供啟動參數(配置文件所在位置,為空就查找/WEB-INF/下面的strutslet-config.xml文件),我們把所有以action結尾的請求都交給FrontController處理:

    ?

    < servlet >
    ????
    < servlet - name > StrutsletController </ servlet - name >
    ????
    < servlet - class > com.strutslet.core.FrontController </ servlet - class >
    ????
    <!-- ??
    ????
    < init - param >
    ?????????
    < param - name > config </ param - name >
    ?????????
    < param - value >/ WEB - INF / strutslet - config.xml </ param - value >
    ????
    </ init - param >
    ????
    -->
    ???????
    < load - on - startup > 0 </ load - on - startup >
    ??
    </ servlet >
    ?
    < servlet - mapping >
    ????
    < servlet - name > StrutsletController </ servlet - name >
    ????
    < url - pattern >* .action </ url - pattern >
    ?
    </ servlet - mapping >

    ?

    最后,讓我們看看整個框架圖:

    ?test.jpg


    評論

    # re: 設計自己的MVC框架  回復  更多評論   

    2007-03-25 00:06 by Cherokee
    不錯最近正好在研究MVC

    # re: 設計自己的MVC框架  回復  更多評論   

    2012-02-22 10:26 by mu00000
    不知道源碼還有不。想學習下,樓主能幫忙嗎。312558613@qq.com,萬分感激。
    主站蜘蛛池模板: 亚洲精品第一国产综合境外资源| 亚洲最大成人网色香蕉| 亚洲AV无码久久精品成人| 最新亚洲成av人免费看| 亚洲AV无码一区二区三区DV| 久久亚洲sm情趣捆绑调教| 国产精品亚洲综合五月天| 在线观看亚洲专区| 四虎国产精品免费永久在线| 24小时日本电影免费看| 精品国产精品久久一区免费式| 亚洲成人免费网站| 免费毛片在线看片免费丝瓜视频| 久久久久久国产精品免费无码| 一级毛片a女人刺激视频免费| 国产精品手机在线亚洲| 成全视成人免费观看在线看| 色欲国产麻豆一精品一AV一免费 | 两性色午夜视频免费播放| 四虎国产精品永久免费网址 | 中文字幕免费视频精品一| 1000部拍拍拍18勿入免费视频下载 | 亚洲日本一区二区三区在线| 亚洲精品免费在线| 国产精品亚洲а∨无码播放不卡| 亚洲精品无码日韩国产不卡av| 亚洲校园春色另类激情| 国产成人无码免费网站| 69堂人成无码免费视频果冻传媒| h片在线免费观看| 国产在线播放免费| 亚洲国产人成在线观看69网站| 亚洲男人的天堂在线播放| 国产亚洲欧美在线观看| 91免费国产精品| 国产jizzjizz视频全部免费| 久久丫精品国产亚洲av不卡| 曰批免费视频播放免费| 我的小后妈韩剧在线看免费高清版| 免费无码又爽又刺激聊天APP| 青春禁区视频在线观看直播免费|