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

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

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

    當柳上原的風吹向天際的時候...

    真正的快樂來源于創造

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks

    我們知道,在Struts1.x中,大致的內部處理流程是這樣的:ActionServlet作為中央處理器,它配置在Web.xml中,接受所有*.do的請求,然后解析URI,得到*.do中的*部分,即path,然后根據path在struts-config.xml中找到具體處理業務的Action以及與之配套的ActionForm和ActionForward,再根據Action的type用Java反射機制生成Action的實例進行具體業務處理,如果Action有ActionForm也會用反射機制生成form傳遞到函數execute中,該函數返回一個ActionForward對象給ActionServlet,如果它不是空,ActionServlet會從中取出URl進行頁面跳轉,否則不采取行動。

    實際上,要拋開Struts框架,自己實現這樣一套流程并不很困難,利用Servlet,正則表達式,XML解析,反射和BeanUtils的相關知識就能實現一個。這樣不但能鞏固相關知識點的掌握,也能對Struts框架有進一步的理解。下面就是我按自己的理解完成的Struts內部流程的具體實現,事先聲明一下,Struts的源碼我沒有看過,其中具體的處理可能和其原本的處理不一致,有些能簡化的部分就簡化了,文中處理不正確的地方還請方家指出。

    1.ActionServlet的配置。
    ActionServlet是一個Servlet,它是Struts框架中的中央控制器,在App啟動時即載入,所有*.do的請求都會發給它,然后再由它派發給具體的業務處理Action,在我的模擬實現工程中,它是這樣配置的。

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    >

        
    <!-- 首頁 -->
        
    <welcome-file-list>
            
    <welcome-file>/web/page/first.jsp</welcome-file>
        
    </welcome-file-list>

        
    <!-- 總控Servlet -->
        
    <servlet>
            
    <servlet-name>DispatchServlet</servlet-name>
            
    <servlet-class>
                com.heyang.action.ActionServlet
            
    </servlet-class>
            
    <init-param>
                
    <description>Configuration File</description>
                
    <param-name>configFile</param-name>
                
    <param-value>web-inf\struts-config.xml</param-value>
            
    </init-param>
            
    <load-on-startup>0</load-on-startup>
        
    </servlet>

        
    <servlet-mapping>
            
    <servlet-name>DispatchServlet</servlet-name>
            
    <url-pattern>*.do</url-pattern>
        
    </servlet-mapping>
    </web-app>

    在這個Web.xml中,在servlet-mapping節點設置了所有*.do的請求都發給com.heyang.action.ActionServlet進行處理;init-param節點指定了配置文件Struts-conifg.xml的位置;在load-on-startup節點中,讓這個Servlet變成自啟動Servlet,這樣設置后,一旦WebApp被載入容器,它的init方法就會被容器調用,在這個方法中,我們要執行重要的處理--讀取配置文件struts-config.xml.

    2.配置文件的讀取。
    前面說了,ActionServlet的init方法中要讀取配置文件,讀取之前當然要找到文件的物理位置,這不難,先取得Webapp的物理路徑再加上param-value指定的相對路徑即可,代碼如下:

    public class ActionServlet extends HttpServlet {
        
    private static final long serialVersionUID = 56890894234786L;

        
    public void doPost(HttpServletRequest request, HttpServletResponse response)
                
    throws ServletException, java.io.IOException {
          ..
        }

            
        
    public void doGet(HttpServletRequest request, HttpServletResponse response)
                
    throws ServletException, java.io.IOException {
            doPost(request, response);
        }

        
        
    /**
         * 初始化,當容器加載Servlet時會首先調用這個函數
         * 因為設置了Servlet的load-on-startup部分
         
    */

        
    public void init() throws ServletException {
            
    // 通過ServletContext取得工程的絕對物理路徑
            ServletContext sct = getServletContext();
            String realPath 
    = sct.getRealPath("/");
            
            
    // 通過ServletConfig實例取得初始化參數configFile
            ServletConfig config=this.getServletConfig();        
            String strutsCfgFile
    =config.getInitParameter("configFile");
            
            
    // 組合配置文件全物理路徑
            strutsCfgFile=realPath+strutsCfgFile;
            System.out.println(
    "配置文件Struts-config.xml全物理路徑是"+strutsCfgFile);
            
            
    // 讀入配置文件
            StrutsConfiger.readConfigFile(strutsCfgFile);
        }

    }


    最后,將配置文件的全路徑裝配好后,交給StrutsConfiger類的靜態函數readConfigFile進行處理。

    StrutsConfiger類的readConfigFile的主要功能是從struts-config.xml讀出Action及與之配套的ActionForm和ActionForward的信息,然后存放在一個哈希表中。代碼如下:

    /**
         * 讀取filePathname指定的配置文件,找出其中Action,ActionForm和ActionForwad的信息
         * 放入一個ActionBean對象中,最后將這些對象放入哈希表actionMap
         * 
    @param filePathname
         
    */

        
    public static void readConfigFile(String filePathname){
            
    try {
                File file 
    = new File(filePathname);
                SAXReader reader 
    = new SAXReader();
                Document document 
    = reader.read(file);
                Element root 
    = document.getRootElement();
                
                
    // 找到Action將要用到的ActionForm
                Element formBeansElm=root.element("form-beans");            
                List formNodes
    =formBeansElm.elements("form-bean");    
                
                Map
    <String,String> formMap=new HashMap<String,String>();
                
                
    for(Iterator it=formNodes.iterator();it.hasNext();){
                    Element formElm
    =(Element)it.next();
                    
                    formMap.put(formElm.attributeValue(
    "name"), formElm.attributeValue("type"));
                }

                
                
    // 找到各Action及其下的ActionForward
                actionMap =new Hashtable<String,ActionBean>();
                
                Element actionMappingsElm
    =root.element("action-mappings");            
                List actionNodes
    =actionMappingsElm.elements("action");    
                
                
    for(Iterator it=actionNodes.iterator();it.hasNext();){
                    Element actionElm
    =(Element)it.next();
                    ActionBean actionBean
    =new ActionBean();
                    
                    actionBean.setPath(actionElm.attributeValue(
    "path"));
                    
                    actionBean.setType(actionElm.attributeValue(
    "type"));
                    
                    String formName
    =actionElm.attributeValue("name");
                    
    if(formName!=null){
                        actionBean.setName(formName);
                        actionBean.setFormType(formMap.get(formName));
                    }

                    
                    
    // Forward部分
                    try{
                        List forwardNodes
    =actionElm.elements("forward");    
                        
    for(Iterator iter=forwardNodes.iterator();it.hasNext();){
                            Element forwardElm
    =(Element)iter.next();
                        
                            
    if(forwardElm!=null){
                                ForwardBean bean
    =new ForwardBean();
                                bean.setName(forwardElm.attributeValue(
    "name"));
                                bean.setPath(forwardElm.attributeValue(
    "path"));
                                
                                actionBean.addForward(bean);
                            }

                        }

                    }

                    
    catch(Exception ex){
                        ;
    // 如果這里發生異常,說明Action節點中沒有forward子節點
                    }

                    
                    
                    actionMap.put(actionBean.getPath(), actionBean);
                    System.out.println(actionBean);
                }

            }
     catch (Exception ex) {
                
    throw new ReadStrutsCofigException("在使用dom4j閱讀解析文檔struts-config.xml時發生異常");
            }
            
        }


    這段代碼就是利用dom4j在Dom找到相應節點,有些特殊的地方如Action中可以有多個Forward或沒有Forword需要注意一下,做一點特殊處理。

    該函數執行完成后,配置文件的Action信息就被讀入了StrutsConfiger的靜態屬性actionMap中,在處理具體用戶請求時我們將會用到它。

    3.將用戶請求發給具體的Action。
    在Web.xml中,所有*.do的請求都被發給了ActionServlet,我們需要解析出*部分,再根據它找到具體處理的Action。解析使用正則表達式即可,代碼如下:

            // 取得請求的URI
            String reqUri=request.getRequestURI();
            
            
    // 取得模式匹配字符串,即go,do等
            String patternStr;
            
    if(reqUri.contains("?")){
                patternStr
    =StringUtil.getMatchedString("([.])(.*)?",reqUri);
            }

            
    else{
                patternStr
    =StringUtil.getMatchedString("([.])(.*)$",reqUri);
            }


            
    // 取得請求的path
            String requestPath=StringUtil.getMatchedString("/(.*)(/.*)[.]"+patternStr,reqUri);        
            System.out.println(
    "請求的path是"+requestPath);

     輔助函數getMatchedString:

    public static String getMatchedString(String regex,String text){
            Pattern pattern
    =Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
            
            Matcher matcher
    =pattern.matcher(text);
     
            
    while(matcher.find()){
                
    return matcher.group(2);
            }

            
            
    return null;
        }


    解析出requestPath之后,我們使用StrutsConfiger類的函數getActionBean就可以找到與之對應的ActionBean,在這個bean中,負責具體進行處理的Action路徑,ActionForm名和路徑,ActionForward等信息都包含到了這個bean中。

    接下來按流程進行處理,下面的代碼中注釋寫得很清楚,這里就不贅述了。值得一提的是在向ActionForm的屬性賦值時,Apche的工具類BeanUtils的使用,有了它的幫助,向一個實例的屬性賦值頓時變得輕松容易起來,全要自己靠反射去實現就太耗功夫了。

    // 找到處理這個請求的Action
            ActionBean actionBean=StrutsConfiger.getActionBean(requestPath);
            
    if(actionBean==null){
                
    throw new CannotFindActionException("找不到path"+requestPath+"對應的Action");
            }
            
            System.out.println(
    "處理請求的Action具體信息是"+actionBean);
            
            
    // 通過反射調用真正的Action類進行處理
            String actionClassName=actionBean.getType();
            
            
    try {
                Class cls 
    = Class.forName(actionClassName);
                Action action 
    = (Action)cls.newInstance();
                
                
    // 找到Action中的Form
                ActionForm form=null;
                
    if(actionBean.getFormType()!=null){
                    Class cls2 
    = Class.forName(actionBean.getFormType());
                    form
    =(ActionForm)cls2.newInstance();
                    
                    
    // 取得輸入參數并存入哈希表
                    Enumeration params=request.getParameterNames();        
                    
    while(params.hasMoreElements()){
                        String key
    =(String)params.nextElement();            
                        String value
    =request.getParameter(key);
                        
                        BeanUtils.setProperty(form, key, value);
                    }
                    
                }

            
                
    // 執行業務操作
                ActionForward actionForward = action.execute(StrutsConfiger.getMappin(requestPath), form, request, response);
            
                
    // 根據返回的actionForward翻頁
                if(actionForward!=null){
                    RequestDispatcher dispatcher 
    = request.getRequestDispatcher(actionForward.toString());
                    dispatcher.forward(request, response);
                    
    return;
                }
                
            }

            
    catch (ClassNotFoundException e) {
                
    throw new ReflectionException("無法通過反射的方式生成"+actionClassName+"的實例");
            }
     
            
    catch (Exception e) {
                
    throw new UnexpectedException("未預料到的異常"+e.getMessage());
            }

    到這里,主要工作就已經完成了。

    4.具體的Action示例。

    下面是有ActionForm的Action。

    package com.heyang.action;

    import java.util.LinkedHashMap;
    import java.util.Map;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import com.heyang.action.base.Action;
    import com.heyang.action.base.ActionForm;

    /**
     * 用于登錄處理的Servlet
     * 
    @author sitinspring
     *
     * @date 2008-2-12
     
    */

    public class LoginAction extends Action {
        
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                HttpServletRequest request, HttpServletResponse response)
                
    throws Exception {
            request.setCharacterEncoding(
    "UTF-8");
            
            Map
    <String,String> ht=new LinkedHashMap<String,String>();
            
            LoginForm inform
    =(LoginForm)form;
                
            ht.put(
    "Name:", inform.getName());
            ht.put(
    "Pswd:", inform.getPswd());
            
            request.setAttribute(
    "ht", ht);

            
    return mapping.findForward("loginResult");
        }

    }

     下面是不需要ActionForm的Action:

    package com.heyang.action;

    import java.util.LinkedHashMap;
    import java.util.Map;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import com.heyang.action.base.Action;
    import com.heyang.action.base.ActionForm;

    /**
     * 用于頁面跳轉處理的Servlet
     * 
    @author sitinspring
     *
     * @date 2008-2-12
     
    */

    public class ShowPageAction extends Action {
        
    private static final long serialVersionUID = 56890894234786L;

        
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                HttpServletRequest request, HttpServletResponse response)
                
    throws Exception {
            request.setCharacterEncoding(
    "UTF-8");
            
            String pageName
    =request.getParameter("page");
            
            Map
    <String,String> ht=new LinkedHashMap<String,String>();
            
            ht.put(
    """");
            
            request.setAttribute(
    "ht", ht);

            
    return new ActionForward("/web/page/"+pageName+".jsp");
        }

    }


    可以看出,這和Struts的Action寫法幾乎是完全一樣的。

    到這里,Struts內部流程模擬實現的主要細節就寫完了,有些代碼在工程里,如果有興趣可以下載來看看。

    Sturts模擬工程代碼下載:
    http://www.tkk7.com/Files/heyang/StrutsFlowSimulator.rar

    posted on 2009-02-12 15:12 何楊 閱讀(3975) 評論(1)  編輯  收藏

    Feedback

    # re: Struts內部流程(總控ActionServlet讀取Struts-config.xml后,將請求轉發到諸負責業務處理的Action流程)模擬實現 2012-08-17 15:26 葉楚鑫
    謝謝樓主分享,之前對這問題一直處于半疑半懂,看完很受用,謝謝啊。  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲熟伦熟女专区hd高清| EEUSS影院WWW在线观看免费 | 久久久久久免费视频| 亚洲乱码日产精品一二三| 久久成人免费电影| 波多野结衣亚洲一级| 亚洲一级特黄大片在线观看| 亚洲精品无码永久在线观看男男| 免费一级毛片一级毛片aa| 免费人成激情视频在线观看冫| 日韩免费一区二区三区| 久久亚洲国产伦理| 午夜私人影院免费体验区| 亚洲人成网站日本片| 亚洲人成网站18禁止一区| 每天更新的免费av片在线观看| 黄色免费网站在线看| 亚洲成a人一区二区三区| 亚洲精品免费在线观看| 亚洲视频在线播放| 日韩亚洲国产二区| 色哟哟国产精品免费观看| 亚洲性色成人av天堂| 国产成人亚洲综合无码| 国产桃色在线成免费视频| a毛片在线免费观看| 久久精品国产亚洲AV麻豆~| 97久久免费视频| 一级看片免费视频| 亚洲国产精品无码中文字| 日韩精品视频免费网址| 亚洲毛片在线免费观看| 两个人看的www免费高清| 97se亚洲综合在线| 最新国产AV无码专区亚洲 | 亚洲Av永久无码精品黑人| 亚洲伊人久久大香线蕉苏妲己| 免费看片在线观看| 女人体1963午夜免费视频| 精品久久久久久国产免费了| 亚洲国产成人久久精品动漫|