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

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

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

    JAVA—咖啡館

    ——歡迎訪問rogerfan的博客,常來《JAVA——咖啡館》坐坐,喝杯濃香的咖啡,彼此探討一下JAVA技術(shù),交流工作經(jīng)驗,分享JAVA帶來的快樂!本網(wǎng)站部分轉(zhuǎn)載文章,如果有版權(quán)問題請與我聯(lián)系。

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      447 Posts :: 145 Stories :: 368 Comments :: 0 Trackbacks

    11.1  Struts介紹

    11.1.1  Struts簡介

    Struts是一個基于Sun J2EE平臺的MVC框架,很好地實現(xiàn)了MVC模式,它由Craig McClanahan創(chuàng)建。Struts最早是作為Apache Jakarta項目的組成部分問世運作,Struts這個名字來源于在建筑中使用的金屬架。使用它的目的是為了減少運用MVC設計模型來開發(fā)Web應用的時間。它只有一個中心控制器,采用XML定制轉(zhuǎn)向的URL,采用Action來處理邏輯。

    Struts通過一個配置文件,即可把握整個系統(tǒng)各部分之間的聯(lián)系,但這樣做不容易查找錯誤。Struts 其實就是在Model2基礎上實現(xiàn)的一個MVC框架。Model2的示意圖如圖11.1所示。

    圖11.1  Model2的示意圖

    與Spring一樣,通過在web.xml中的配置,使得所有的視圖層請求都要通過ActionServlet,由它進行客戶端的請求處理。它主要通過struts-config.xml文件來進行用戶請求的動作和對應Action的請求,將請求傳遞給Action,并將處理后的結(jié)果返回給視圖層。Struts的體系結(jié)構(gòu)如圖11.2所示。

    圖11.2  Struts的體系結(jié)構(gòu)

    11.1.2  Struts和Spring比較

    可以看出:Struts的ActionServlet和Spring的DispatcherServlet類似,Struts的Action和Spring的Controller類似,Struts的配置文件struts-config.xml和Spring的dispatcherServlet- config.xml類似,Struts的DispatchAction和Spring的MultiActionController類似。

    11.1.3  下載Struts

    前面簡要講解了Struts的相關(guān)知識,當然最重要的還是練習,這里從Struts的下載開始講起。通過http://struts.apache.org/可以進入Struts的首頁,如圖11.3所示。

    圖11.3  Struts的首頁

    本書采用的版本是Struts 1.3.8單擊首頁的“Struts 1.3.8”鏈接,即可進入Struts1.3.8的下載頁面,如圖11.4所示。

    圖11.4  Struts1.3.8的下載頁面

    該頁面可下載Struts的相關(guān)版本。單擊“struts-1.3.8-all.zip”超鏈接,即可進行下載,大小約44MB。

    11.1.4  配置Struts

    解壓縮struts-1.3.8-all.zip,解壓縮完畢后,就可以在Eclipse中配置Struts了。具體實現(xiàn)思路如下:首先在Eclipse中建立一個項目myLogin,然后把Struts相關(guān)的jar配置到該項目中,最后在項目中建立3個包:com. myLogin.action用來存放控制器類。com. myLogin.bean用來存放實體類、com. myLogin.impl用來存放接口類。具體步驟如下:

    *  運行Eclipse,單擊菜單“File”命令,Eclipse將顯示“File”命令。

    *  選擇“New”|“Project”,單擊右鍵彈出“New Project”對話框,如圖11.5所示。

    圖11.5  “New Project”對話框

    *  選擇樹形“Java”|“Tomcat Project”節(jié)點,然后單擊“Next”按鈕,彈出“New Tomcat Project”對話框,如圖11.6所示。

    圖11.6  “New Tomcat Project”對話框

    *  在“Project name”文本框中輸入“myLogin”,然后單擊“Finish”按鈕,項目即建立成功,myLogin的目錄結(jié)構(gòu)如圖11.7所示。

      在myLogin上單擊右鍵,選擇菜單“New”|“Package”命令,彈出“New Java Package”對話框,如圖11.8所示。

            

    圖11.7  myLogin的目錄結(jié)構(gòu)                    圖11.8  “New Java Package”對話框

      在“Name”文本框中輸入“com. myLogin.action”,然后單擊“Finish”按鈕,即可建立com. myLogin.action包。

      用同樣的方法建立com. myLogin.bean和com. myLogin.impl包。

      在myLogin上單擊右鍵,選擇菜單“New”|“Folder”命令,彈出“New Folder”對話框,如圖11.9所示。

    圖11.9  “New Folder”對話框

      在“New Folder”對話框中的“Folder Name”文本框中輸入“jsp”,然后單擊“Finish”按鈕,即可建立jsp文件夾。

      把struts-1.3.8-all.zip解壓縮后struts-1.3.8目錄下的struts-core-1.3.8.jar,struts-el- 1.3.8.jar,struts-extras-1.3.8.jar,struts-faces-1.3.8.jar,struts-mailreader-dao-1.3.8.jar,struts-scripting- 1.3.8.jar,struts-taglib-1.3.8.jar,struts-tiles-1.3.8.jar,commons-beanutils-1.7.0.jar,commons-chain-1.1.jar,commons-digester-1.8.jar,commons-logging-1.0.4.jar12個jar從/WEB-INF/lib/中復制到myLogin/WEB-INF/lib目錄下,即CLASSPATH中。

      在myLogin上單擊右鍵,選擇“Properties”命令,彈出“Properties for myLogin”對話框,如圖11.10所示。

    圖11.10  “Properties for myLogin”對話框

      在對話框左邊的樹形菜單中,單擊“Java Build Path”節(jié)點,系統(tǒng)將在“Properties for myLogin”對話框的右邊出現(xiàn)“Java Build Path”的相關(guān)屬性,如圖11.11所示。

      在“Libraries”選項卡中,單擊“Add JARs…”按鈕,彈出“JAR Selection”對話框,如圖11.12所示。

       

    圖11.11 “Java Build Path”的相關(guān)屬性               圖11.12  “JAR Selection”對話框

      在“JAR Selection”對話框中,單擊“myLogin”節(jié)點,打開樹形菜單,如圖11.13所示。

      在打開的樹形菜單中,選擇struts-core-1.3.8.jar,struts-el-1.3.8.jar,struts-extras-1.3.8.jar, struts-faces-1.3.8.jar,struts-mailreader-dao-1.3.8.jar,struts-scripting-1.3.8.jar,struts-taglib-1.3.8.jar,struts-tiles-1.3.8.jar,commons-beanutils-1.7.0.jar,commons-chain-1.1.jar,commons-digester-1.8.jar,co- mmons-logging-1.0.4.jar,按住“Ctrl”鍵,選中這12個jar,然后單擊“OK”按鈕,返回“Properties for myLogin”對話框,如圖11.14所示。

     

    圖11.13  打開樹形菜單                 圖11.14  “Properties for myLogin”對話框

      在“Properties for myLogin”對話框,單擊“OK”按鈕,上述12個jar加入到CLASSPATH中,完成對Struts的配置。

      如果需要其他的jar,也要用這種方式加入到CLASSPATH中。

      最終配置好Struts的myLogin項目的目錄結(jié)構(gòu)如圖11.15所示。

    圖11.15  配置好Struts的myLogin項目的目錄結(jié)構(gòu)

    上述建立myLogin工程的步驟很長,目的是讓讀者不要在這上面耗費太多的時間,只要讀者按照上面介紹的步驟一步一步地來,在環(huán)境配置方面就不會有太多的問題。

    11.2  Struts的核心

    支持Struts的核心類主要包括:ActionServlet,Action,ActionForm,Action Mapping等,它們的運行機理如圖11.16所示。

    圖11.16  Struts核心類的運行機理

    從圖11-6可以看出這些核心類的運作模式,下面分別進行講解。

    11.2.1  ActionServlet(分發(fā)器)

    org.apache.struts.action.ActionServlet繼承于javax.servlet.http.HttpServlet,ActionServlet是MVC模式中的Controller,是一個FrontController。它是一個標準的Servlet,它將request轉(zhuǎn)發(fā)給RequestProcessor來處理,執(zhí)行該方法后會返回一個ActionForward。這和Spring的DispatcherServlet是類似的,只不過Spring的DispatcherServlet 返回的是一個ModelAndView。ActionServlet的示例代碼如下:

    //*******ActionServlet.java**************

    package org.apache.struts.action;

    //引入apache的commons包

    import org.apache.commons.beanutils.BeanUtils;

    import org.apache.commons.logging.LogFactory;

    //引入struts包

    import org.apache.struts.Globals;

    import org.apache.struts.util.RequestUtils;

    import org.xml.sax.SAXException;

    //引入servlet包

    import javax.servlet.ServletContext;

    import javax.servlet.http.HttpServletResponse;

    //引入io包

    import java.io.IOException;

    import java.io.InputStream;

    //引入math包

    import java.math.BigDecimal;

    import java.math.BigInteger;

    //引入net包

    import java.net.MalformedURLException;

    import java.net.URLConnection;

    //引入util包

    import java.util.ArrayList;

    import java.util.MissingResourceException;

    /** 該類是作為MVC的Controller來使用的,繼承于HttpServlet */

    public class ActionServlet extends HttpServlet {

        /** 定義日志 */

        protected static Log log = LogFactory.getLog(ActionServlet.class);

        /** 定義默認的配置文檔 */

        protected String config = "/WEB-INF/struts-config.xml";

        /** 定義默認的commons-chain 的配置文檔*/

        protected String chainConfig = "org/apache/struts/chain/chain-config.xml";

        /** 定義configDigester */

        protected Digester configDigester = null;

        /** 定義向后兼容性 */

        protected boolean convertNull = false;

        /** 定義消息資源 */

        protected MessageResources internal = null;

        /** 定義資源基類 */

        protected String internalName = "org.apache.struts.action.ActionResources";

        /** 定義DTD的有關(guān)配置信息的版本 */

        protected String[] registrations =

            {

                "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",

                "/org/apache/struts/resources/struts-config_1_0.dtd",

                "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",

                "/org/apache/struts/resources/struts-config_1_1.dtd",

                "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN",

                "/org/apache/struts/resources/struts-config_1_2.dtd",

                "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN",

                "/org/apache/struts/resources/struts-config_1_3.dtd",

                "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",

                "/org/apache/struts/resources/web-app_2_3.dtd"

            };

        /** 映射描述 */

    圓角矩形: 下面一段代碼定義了Struts在調(diào)用ActionServlet后,要銷毀的一些參數(shù)。

    protected String servletMapping = null; // :FIXME:                                                              - multiples?

        /** 定義Servlet的名稱 */

        protected String servletName = null;

        /** 覆寫destroy 方法,用來處理一些銷毀動作 */

        public void destroy() {

            if (log.isDebugEnabled()) {

                log.debug(internal.getMessage("finalizing"));

            }

            //銷毀模組

            destroyModules();

            //銷毀相關(guān)屬性

            destroyInternal();

            getServletContext().removeAttribute(Globals.ACTION_SERVLET_KEY);

            //獲取當前的加載類

            ClassLoader classLoader =

                Thread.currentThread().getContextClassLoader();

            //如果為空,則獲取ActionServlet

            if (classLoader == null) {

                classLoader = ActionServlet.class.getClassLoader();

            }

            //釋放日志類

            try {

                LogFactory.release(classLoader);

            } catch (Throwable t) {

                ;

            }

            //清空目錄日志工廠

            CatalogFactory.clear();

            //清空相關(guān)的屬性

            PropertyUtils.clearDescriptors();

    }

    ……

    上面的代碼主要是覆寫了Servlet的destroy()方法,用來進行一些銷毀的動作,如釋放相關(guān)的模組、日志等,接下來就要進行一些初始化的工作,代碼如下所示:

    圓角矩形: 下面一段代碼定義了Struts在調(diào)用業(yè)務邏輯前要初始化的一些參數(shù)。

……

    /**處理一些初始化動作*/

    public void init() throws ServletException {

        final String configPrefix = "config/";

        //獲取配置文檔的前綴為config的長度

        final int configPrefixLength = configPrefix.length() - 1;

        try {

            initInternal();

            initOther();

            //初始化servlet

            initServlet();

            initChain();

            //設定全局的servlet關(guān)鍵字

            getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);

            initModuleConfigFactory();

            //初始化模組

            ModuleConfig moduleConfig = initModuleConfig("", config);

            //初始化消息

            initModuleMessageResources(moduleConfig);

            initModulePlugIns(moduleConfig);

            //初始化formbean

            initModuleFormBeans(moduleConfig);

            //初始化forward

            initModuleForwards(moduleConfig);

            //初始化異常

            initModuleExceptionConfigs(moduleConfig);

            //初始化action

            initModuleActions(moduleConfig);

            moduleConfig.freeze();

            //獲取初始化的參數(shù)名

            Enumeration names = getServletConfig().getInitParameterNames();

            while (names.hasMoreElements()) {

                String name = (String) names.nextElement();

                //假如獲取的名稱前綴不是config,則繼續(xù)獲取

                if (!name.startsWith(configPrefix)) {

                    continue;

                }

            //獲取名稱的前綴

                 String prefix = name.substring(configPrefixLength);

                //初始化模組的配置信息

                moduleConfig =

                    initModuleConfig(prefix,

                        getServletConfig().getInitParameter(name));

                initModuleMessageResources(moduleConfig);

               initModulePlugIns(moduleConfig);

                    //初始化formbean

                initModuleFormBeans(moduleConfig);

                //初始化forward

                initModuleForwards(moduleConfig);

                initModuleExceptionConfigs(moduleConfig);

                //初始化action

                initModuleActions(moduleConfig);

                moduleConfig.freeze();

            }

            //初始化模組的前綴

            this.initModulePrefixes(this.getServletContext());

            this.destroyConfigDigester();

        } catch (UnavailableException ex) {

            throw ex;

        } catch (Throwable t) {

           //記錄處理異常的日志

            log.error("Unable to initialize Struts ActionServlet due to an "

                + "unexpected exception or error thrown, so marking the "

                + "servlet as unavailable.  Most likely, this is due to an "

                + "incorrect or missing library dependency.", t);

            throw new UnavailableException(t.getMessage());

        }

    }

    /** 初始化模組的前綴 */

    protected void initModulePrefixes(ServletContext context) {

        ArrayList prefixList = new ArrayList();

        //獲取相關(guān)的屬性名

        Enumeration names = context.getAttributeNames();

        //循環(huán)迭代屬性名

        while (names.hasMoreElements()) {

            String name = (String) names.nextElement();

            //如果前綴不是定義的全局關(guān)鍵字,則繼續(xù)

            if (!name.startsWith(Globals.MODULE_KEY)) {

                continue;

            }

            //獲取前綴

            String prefix = name.substring(Globals.MODULE_KEY.length());

            //如果有前綴,則加入到list中

            if (prefix.length() > 0) {

                prefixList.add(prefix);

            }

        }

        //將list轉(zhuǎn)換為數(shù)組

        String[] prefixes =

            (String[]) prefixList.toArray(new String[prefixList.size()]);

        //設定相關(guān)屬性

        context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);

    }

    ……

    上述代碼主要是進行初始化工作,如初始化Servlet、FormBean、異常、日志、模組等。為了轉(zhuǎn)發(fā)從視圖層傳來的請求,還必須覆寫doGet和doPost方法,然后這兩個方法同時調(diào)用了process方法,代碼如下所示:

    ……

    /** 覆寫doGet方法,接受用戶在頁面的請求,調(diào)用process */

    public void doGet(HttpServletRequest request, HttpServletResponse response)

        throws IOException, ServletException {

        process(request, response);

    }

    ** 覆寫doPost方法,接受用戶在頁面的請求,調(diào)用process */

    public void doPost(HttpServletRequest request, HttpServletResponse response)

        throws IOException, ServletException {

        process(request, response);

    }

    /** 增加servlet的映射 */

    public void addServletMapping(String servletName, String urlPattern) {

        if (servletName == null) {

            return;

        }

        //判斷傳入的servlet的名稱和本身的是否一致

        if (servletName.equals(this.servletName)) {

            if (log.isDebugEnabled()) {

                log.debug("Process servletName=" + servletName

                    + ", urlPattern=" + urlPattern);

            }

            //將url賦給servletMapping

    圓角矩形: 下面一段代碼定義了Struts要銷毀的模組。        this.servletMapping = urlPattern;

        }

    }

    /** 獲取消息資源 */

    public MessageResources getInternal() {

        return (this.internal);

    }

    /** 銷毀模組 */

    protected void destroyModules() {

        ArrayList values = new ArrayList();

        Enumeration names = getServletContext().getAttributeNames();

        //對名稱進行循環(huán),放在list中

        while (names.hasMoreElements()) {

            values.add(names.nextElement());

        }

        //將list轉(zhuǎn)換為Iterator

        Iterator keys = values.iterator();

        //進行迭代

        while (keys.hasNext()) {

            String name = (String) keys.next();

            Object value = getServletContext().getAttribute(name);

            //判斷獲取的名稱是否是ModuleConfig的實例

            if (!(value instanceof ModuleConfig)) {

                continue;

            }

            //如果是,則轉(zhuǎn)換為ModuleConfig

            ModuleConfig config = (ModuleConfig) value;

            if (this.getProcessorForModule(config) != null) {

                this.getProcessorForModule(config).destroy();

            }

            //在ServletContext中移除該屬性

            getServletContext().removeAttribute(name);

            PlugIn[] plugIns =

                (PlugIn[]) getServletContext().getAttribute(Globals.PLUG_INS_KEY

                    + config.getPrefix());

            //銷毀PlugIn

            if (plugIns != null) {

                for (int i = 0; i < plugIns.length; i++) {

                    int j = plugIns.length - (i + 1);

                    //銷毀PlugIn

                    plugIns[j].destroy();

                }

                //在ServletContext移除PLUG的關(guān)鍵字

                getServletContext().removeAttribute(Globals.PLUG_INS_KEY

                    + config.getPrefix());

            }

        }

    }

    /** 釋放configDigester */

    protected void destroyConfigDigester() {

        configDigester = null;

    }

    /** 釋放MessageResources */

    protected void destroyInternal() {

        internal = null;

    }

    /** 根據(jù)傳入的request,獲取ModuleConfig */

    protected ModuleConfig getModuleConfig(HttpServletRequest request) {

        ModuleConfig config = (ModuleConfig) request.getAttribute(Globals.MODULE_KEY);

        //如果為空,則獲取ServletContext中的內(nèi)容

        if (config == null) {

            config = (ModuleConfig) getServletContext().getAttribute(Globals.MODULE_KEY);

        }

        return (config);

    }

    /**獲取RequestProcessor */

    protected synchronized RequestProcessor getRequestProcessor(

        ModuleConfig config) throws ServletException {

        RequestProcessor processor = this.getProcessorForModule(config);

        //假如沒有,則創(chuàng)建一個新的RequestProcessor

        if (processor == null) {

            try {

                //創(chuàng)建一個新的RequestProcessor

                processor = (RequestProcessor) RequestUtils.applicationInstance(config. getControllerConfig().getProcessorClass());

            } catch (Exception e) {

                throw new UnavailableException(

                    "Cannot initialize RequestProcessor of class "

                    + config.getControllerConfig().getProcessorClass() + ": "

                    + e);

            }

            //對RequestProcessor進行初始化

            processor.init(this, config);

            //設定關(guān)鍵字

            String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();

    圓角矩形: 下面一段代碼實現(xiàn)了初始化模組配置的功能。        //將關(guān)鍵字加入到ServletContext中

            getServletContext().setAttribute(key, processor);

        }

        //返回RequestProcessor

        return (processor);

    }

    /** 初始化ModuleConfig */

    protected ModuleConfig initModuleConfig(String prefix, String paths)

        throws ServletException {

        if (log.isDebugEnabled()) {

            log.debug("Initializing module path '" + prefix

                + "' configuration from '" + paths + "'");

        }

        //解析ModuleConfig

        ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();

        ModuleConfig config = factoryObject.createModuleConfig(prefix);

        // 初始化Digester

        Digester digester = initConfigDigester();

        //獲取路徑

        List urls = splitAndResolvePaths(paths);

        URL url;

        //將配置信息加入到Digester

        for (Iterator i = urls.iterator(); i.hasNext();) {

            url = (URL) i.next();

            digester.push(config);

            //對Digester進行解析

            this.parseModuleConfigFile(digester, url);

        }

        //將配置前綴加入到ServletContext

        getServletContext().setAttribute(Globals.MODULE_KEY

            + config.getPrefix(), config);

        //返回config

        return config;

    }

    //……相關(guān)的異常處理配置和其他初始化的配置信息,這里不再進行講解

    /** 初始化servlet */

    protected void initServlet()

        throws ServletException {

        //獲取ervlet name

        this.servletName = getServletConfig().getServletName();

        // 準備一個Digester

        Digester digester = new Digester();

        //設定Digester的相關(guān)屬性

        digester.push(this);

        digester.setNamespaceAware(true);

        digester.setValidating(false);

        // 注冊DTDs

        for (int i = 0; i < registrations.length; i += 2) {

            URL url = this.getClass().getResource(registrations[i + 1]);

            //如果url不為空,則注冊

            if (url != null) {

                digester.register(registrations[i], url.toString());

            }

        }

        //配置相關(guān)的配置信息

        digester.addCallMethod("web-app/servlet-mapping", "addServletMapping", 2);

        digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);

    圓角矩形: 下面一段代碼實現(xiàn)了解析web. xml的功能。    digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);

        //記錄目前的進程

        if (log.isDebugEnabled()) {

            log.debug("Scanning web.xml for controller servlet mapping");

        }

        //獲取web.xml

        InputStream input =

            getServletContext().getResourceAsStream("/WEB-INF/web.xml");

        //如果沒有獲取到web.xml

        if (input == null) {

            log.error(internal.getMessage("configWebXml"));

            throw new ServletException(internal.getMessage("configWebXml"));

        }

        //解析web.xml

        try {

            digester.parse(input);

        } catch (IOException e) {

            log.error(internal.getMessage("configWebXml"), e);

            throw new ServletException(e);

        } catch (SAXException e) {

            //如果web.xml語法配置有錯誤

            log.error(internal.getMessage("configWebXml"), e);

            throw new ServletException(e);

        } finally {

            try {

                //關(guān)閉web.xml

                input.close();

            } catch (IOException e) {

                log.error(internal.getMessage("configWebXml"), e);

                throw new ServletException(e);

            }

        }

        // 記錄在web.xml中的Servlet名稱

        if (log.isDebugEnabled()) {

            log.debug("Mapping for servlet '" + servletName + "' = '"

                + servletMapping + "'");

        }

        //如果在web.xml中定義了映射

        if (servletMapping != null) {

            getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);

        }

    }

    ……

    通過前面的初始化工作及視圖層的請求轉(zhuǎn)發(fā),Struts即可進入process方法,從而開始具體的請求轉(zhuǎn)發(fā)工作,代碼如下所示:

        ……

         /** 具體負責用戶請求的進程 */

        protected void process(HttpServletRequest request,

            HttpServletResponse response)

            throws IOException, ServletException {

            ModuleUtils.getInstance().selectModule(request, getServletContext());

            //根據(jù)request獲取ModuleConfig

            ModuleConfig config = getModuleConfig(request);

            //根據(jù)ModuleConfig獲取RequestProcessor

            RequestProcessor processor = getProcessorForModule(config);

            //如果RequestProcessor為空,則根據(jù)request獲取

            if (processor == null) {

                processor = getRequestProcessor(config);

            }

            //執(zhí)行相關(guān)的處理進程

            processor.process(request, response);

        }

    }

    從示例代碼可以看出,在ActionServlet的doGet和doPost方法中,都調(diào)用了process方法,從而將請求交給RequestProcessor的process方法來進行處理。

    //*******RequestProcessor.java**************

    package org.apache.struts.action;

    //引入apache的日志

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.apache.struts.util.MessageResources;

    import org.apache.struts.util.RequestUtils;

    //引入servlet

    import javax.servlet.RequestDispatcher;

    import javax.servlet.ServletContext;

    import javax.servlet.ServletException;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import javax.servlet.http.HttpSession;

    //引入io

    import java.io.IOException;

    //引入util

    import java.util.HashMap;

    import java.util.Iterator;

    import java.util.Locale;

    /** 該類用來處理從request來的請求 */

    public class RequestProcessor {

        /** 定義include的路徑信息 */

        public static final String INCLUDE_PATH_INFO =

            "javax.servlet.include.path_info";

        /** 定義servlet的路徑信息 */

        public static final String INCLUDE_SERVLET_PATH =

            "javax.servlet.include.servlet_path";

        /** 定義日志 */

        protected static Log log = LogFactory.getLog(RequestProcessor.class);

        /** 定義要處理的action */

        protected HashMap actions = new HashMap();

        /** 定義配置信息 */

        protected ModuleConfig moduleConfig = null;

        /** 定義要使用的ActionServlet */

        protected ActionServlet servlet = null;

        /** 定義銷毀動作 */

        public void destroy() {

            synchronized (this.actions) {

                Iterator actions = this.actions.values().iterator();

                //銷毀每一個動作

                while (actions.hasNext()) {

                    Action action = (Action) actions.next();

                    //設定動作的內(nèi)容為null

                    action.setServlet(null);

                }

                //清空儲存動作的Map

                this.actions.clear();

            }

            //重置servlet為null

            this.servlet = null;

        }

        /** 初始化 */

        public void init(ActionServlet servlet, ModuleConfig moduleConfig)

            throws ServletException {

            //首先清空存儲動作的容器

            synchronized (actions) {

                actions.clear();

            }

            //然后設定servlet和配置信息

            this.servlet = servlet;

            this.moduleConfig = moduleConfig;

    }

    ……

    上述代碼主要用來做初始化和銷毀工作,也就是說每次在調(diào)用DispatcherServlet時,首先要將存儲的action清空,然后再將傳來的DispatcherServlet和相關(guān)配置檔注入RequestProcessor中,接著就要調(diào)用RequestProcessor的process方法,代碼如下所示:

    ……

        /** 處理進程 */

        public void process(HttpServletRequest request, HttpServletResponse response)

            throws IOException, ServletException {

            //封裝request

            request = processMultipart(request);

            //獲取映射的路徑

            String path = processPath(request, response);

            //如果沒有路徑,則停止執(zhí)行

            if (path == null) {

                return;

            }

            //記錄要處理的方法和路徑

            if (log.isDebugEnabled()) {

                log.debug("Processing a '" + request.getMethod() + "' for path '"

                    + path + "'");

            }

            //獲取request的Locale

            processLocale(request, response);

            //獲取request的Content

            processContent(request, response);

            processNoCache(request, response);

            // General purpose preprocessing hook

            if (!processPreprocess(request, response)) {

                return;

            }

            //從request獲取消息

            this.processCachedMessages(request, response);

            // 從request獲取映射

            ActionMapping mapping = processMapping(request, response, path);

    圓角矩形: 下面一段代碼實現(xiàn)了在調(diào)用具體業(yè)務邏輯前,先對ActionForm進行驗證。

        //如果沒有映射,則返回

            if (mapping == null) {

                return;

            }

            //檢查要執(zhí)行這個動作的角色

            if (!processRoles(request, response, mapping)) {

                return;

            }

            //將request和ActionForm關(guān)聯(lián)起來

            ActionForm form = processActionForm(request, response, mapping);

            //從request獲取ActionForm,進行封裝

            processPopulate(request, response, form, mapping);

            //驗證封裝的數(shù)據(jù)是否有問題

            try {

                if (!processValidate(request, response, form, mapping)) {

                    return;

                }

            } catch (InvalidCancelException e) {

                //如果有問題,則返回一個ActionForward

                ActionForward forward = processException(request, response, e, form, mapping);

                processForwardConfig(request, response, forward);

                return;

            } catch (IOException e) {

                throw e;

            } catch (ServletException e) {

                throw e;

            }

            //根據(jù)映射判斷是否包含了Forward

            if (!processForward(request, response, mapping)) {

                return;

            }

            //檢查是否包含Include

            if (!processInclude(request, response, mapping)) {

                return;

            }

            //創(chuàng)建一個動作實例

            Action action = processActionCreate(request, response, mapping);

            //如果創(chuàng)建的動作為空,則返回

            if (action == null) {

                return;

            }

            //執(zhí)行這個動作,返回ActionForward

            ActionForward forward =processActionPerform(request, response, action, form, mapping);

            //將ActionForward放入Config中

            processForwardConfig(request, response, forward);

        }

        /** 創(chuàng)建一個action */

        protected Action processActionCreate(HttpServletRequest request,

            HttpServletResponse response, ActionMapping mapping)

            throws IOException {

            //獲取action的名稱

            String className = mapping.getType();

            //記錄這個action的名稱

            if (log.isDebugEnabled()) {

                log.debug(" Looking for Action instance for class " + className);

    圓角矩形: 下面一段代碼實現(xiàn)了獲取要調(diào)用的業(yè)務邏輯類。        }

            Action instance;

            //同步action

            synchronized (actions) {

                //返回存在的action實例

                instance = (Action) actions.get(className);

                //如果實例不為空,則返回

                if (instance != null) {

                    if (log.isTraceEnabled()) {

                        log.trace("  Returning existing Action instance");

                    }

                    //返回action實例

                    return (instance);

                }

                // 如果實例為空,則重新創(chuàng)建一個

                if (log.isTraceEnabled()) {

                    log.trace("  Creating new Action instance");

                }

                //創(chuàng)建一個action實例

                try {

                    instance = (Action) RequestUtils.applicationInstance(className);

                } catch (Exception e) {

                    log.error(getInternal().getMessage("actionCreate",

                            mapping.getPath()), e);

            //發(fā)送錯誤信息        response.sendError(HttpServletResponse.SC_INTERNAL_ SERVER_ERROR,

                        getInternal().getMessage("actionCreate", mapping.getPath()));

                    //返回空

                    return (null);

                }

                //將action的名稱和實例存放在actions容器中

                actions.put(className, instance);

            }

    圓角矩形: 下面一段代碼實現(xiàn)了將頁面的數(shù)據(jù)封裝成ActionForm。        //如果實例的servlet為空,則添加

            if (instance.getServlet() == null) {

                instance.setServlet(this.servlet);

            }

            //返回action的實例

            return (instance);

        }

        /** 封裝ActionForm */

        protected ActionForm processActionForm(HttpServletRequest request,

            HttpServletResponse response, ActionMapping mapping) {

            //創(chuàng)建一個ActionForm

            ActionForm instance =

                RequestUtils.createActionForm(request, mapping, moduleConfig,

                    servlet);

            //如果創(chuàng)建不成功,就返回null

            if (instance == null) {

                return (null);

            }

           //假如request中沒有,則添加

            if ("request".equals(mapping.getScope())) {

                request.setAttribute(mapping.getAttribute(), instance);

            } else {

                //否則獲取session

                HttpSession session = request.getSession();

                //在session中存入

                session.setAttribute(mapping.getAttribute(), instance);

            }

            //返回ActionForm實例

            return (instance);

        }

        /** 處理Forward */

        protected void processForwardConfig(HttpServletRequest request,

            HttpServletResponse response, ForwardConfig forward)

            throws IOException, ServletException {

            if (forward == null) {

                return;

            }

            //獲取forward的路徑

            String forwardPath = forward.getPath();

            String uri;

            // 獲取路徑

    圓角矩形: 下面一段代碼實現(xiàn)了設定要返回視圖層的頁面的功能。        String actionIdPath = RequestUtils.actionIdURL                    (forward, request, servlet);

            if (actionIdPath != null) {

                forwardPath = actionIdPath;

                ForwardConfig actionIdForward = new ForwardConfig(forward);

                //設定路徑

                actionIdForward.setPath(actionIdPath);

                forward = actionIdForward;

            }

            //假如路徑中有/

            if (forwardPath.startsWith("/")) {

                //處理后再獲取

                uri = RequestUtils.forwardURL(request, forward, null);

            } else {

                uri = forwardPath;

            }

            //如果有設定Redirect

            if (forward.getRedirect()) {

                //對設定的Redirect進程處理

                if (uri.startsWith("/")) {

                    uri = request.getContextPath() + uri;

                }

                //執(zhí)行response的sendRedirect方法

                response.sendRedirect(response.encodeRedirectURL(uri));

            } else {

                //執(zhí)行doForward,返回視圖

                doForward(uri, request, response);

            }

        }

        /** 執(zhí)行Action */

        protected ActionForward processActionPerform(HttpServletRequest request,

            HttpServletResponse response, Action action, ActionForm form,

            ActionMapping mapping)

            throws IOException, ServletException {

            try {

                //執(zhí)行action的execute方法

                return (action.execute(mapping, form, request, response));

            } catch (Exception e) {

                return (processException(request, response, e, form, mapping));

            }

        }

        /** 處理信息 */

        protected void processCachedMessages(HttpServletRequest request,

            HttpServletResponse response) {

            HttpSession session = request.getSession(false);

            //如果沒有session,則返回

            if (session == null) {

                return;

            }

            //獲取ActionMessages

            ActionMessages messages =

                (ActionMessages) session.getAttribute(Globals.MESSAGE_KEY);

            //如果消息不為空,則移除

            if (messages != null) {

                if (messages.isAccessed()) {

                    session.removeAttribute(Globals.MESSAGE_KEY);

                }

            }

            //獲取session中的錯誤消息

            messages = (ActionMessages) session.getAttribute(Globals.ERROR_KEY);

            //如果錯誤消息不為空,則移除

            if (messages != null) {

                if (messages.isAccessed()) {

                    session.removeAttribute(Globals.ERROR_KEY);

                }

            }

        }

        /** 處理Content */

        protected void processContent(HttpServletRequest request,

            HttpServletResponse response) {

            //獲取contentType

            String contentType =

                moduleConfig.getControllerConfig().getContentType();

    圓角矩形: 下面一段代碼描述了Struts如何處理異常的功能。        //如果contentType不為空

            if (contentType != null) {

                response.setContentType(contentType);

            }

        }

        /** 處理異常 */

        protected ActionForward processException(HttpServletRequest request,

            HttpServletResponse response, Exception exception, ActionForm form,

            ActionMapping mapping)

            throws IOException, ServletException {

            //獲取異常句柄

            ExceptionConfig config = mapping.findException(exception.getClass());

            //如果句柄為空

            if (config == null) {

                log.warn(getInternal().getMessage("unhandledException",exception. getClass()));

                //判斷異常類型

                if (exception instanceof IOException) {

                    throw (IOException) exception;

                } else if (exception instanceof ServletException) {

                    throw (ServletException) exception;

                } else {

                    throw new ServletException(exception);

                }

            }

            // 創(chuàng)建一個異常處理的實例

            try {

                ExceptionHandler handler = (ExceptionHandler) RequestUtils.applicationInstance (config.getHandler());

                //執(zhí)行實例的execute方法

                return (handler.execute(exception, config, mapping, form, request,

                    response));

            } catch (Exception e) {

                throw new ServletException(e);

            }

        }

        /** 處理Forward */

        protected boolean processForward(HttpServletRequest request,

            HttpServletResponse response, ActionMapping mapping)

            throws IOException, ServletException {

            //獲取Forward

    圓角矩形: 下面一段代碼描述了Struts如何實現(xiàn)返回視圖層的功能。        String forward = mapping.getForward();

            //如果Forward為空

            if (forward == null) {

                return (true);

            }

            //獲取Forward

            String actionIdPath = RequestUtils.actionIdURL(forward, this.moduleConfig, this.servlet);

            if (actionIdPath != null) {

                forward = actionIdPath;

            }

            //建立關(guān)聯(lián)

            internalModuleRelativeForward(forward, request, response);

            //返回false

            return (false);

        }

        /** 處理Include */

        protected boolean processInclude(HttpServletRequest request,

            HttpServletResponse response, ActionMapping mapping)

            throws IOException, ServletException {

            //從映射中獲取include

            String include = mapping.getInclude();

            //如果include為空,則返回

            if (include == null) {

                return (true);

            }

            //如果forward在action中有別名

            String actionIdPath = RequestUtils.actionIdURL(include, this.moduleConfig, this.servlet);

            if (actionIdPath != null) {

                include = actionIdPath;

            }

            //建立關(guān)聯(lián)

            internalModuleRelativeInclude(include, request, response);

            //返回false

            return (false);

        }

        /** 處理Locale */

        protected void processLocale(HttpServletRequest request,

            HttpServletResponse response) {

            //判斷配置里是否有Locale

            if (!moduleConfig.getControllerConfig().getLocale()) {

                return;

            }

            //如果已經(jīng)有一個Locale

            HttpSession session = request.getSession();

            //查看session里是否使用存儲了Locale,如果有就不需要了

            if (session.getAttribute(Globals.LOCALE_KEY) != null) {

                return;

            }

            //獲取Locale

            Locale locale = request.getLocale();

            //如果Locale不為空

            if (locale != null) {

                if (log.isDebugEnabled()) {

                    log.debug(" Setting user locale '" + locale + "'");

    圓角矩形: 下面一段代碼描述了Struts如何實現(xiàn)映射的功能。            }

                //加入到session中

                session.setAttribute(Globals.LOCALE_KEY, locale);

            }

        }

        /** 處理映射 */

        protected ActionMapping processMapping(HttpServletRequest request,

            HttpServletResponse response, String path)

            throws IOException {

            //獲取ActionMapping

            ActionMapping mapping = (ActionMapping) moduleConfig.findActionConfig(path);

            //判斷request里是否有映射

            if (mapping != null) {

                request.setAttribute(Globals.MAPPING_KEY, mapping);

                //如果有,就返回

                return (mapping);

            }

            //獲取ActionConfig

            ActionConfig[] configs = moduleConfig.findActionConfigs();

            //獲取映射,存入request中

            for (int i = 0; i < configs.length; i++) {

                if (configs[i].getUnknown()) {

                    mapping = (ActionMapping) configs[i];

                    request.setAttribute(Globals.MAPPING_KEY, mapping);

                    //返回映射

                    return (mapping);

                }

            }

            //如果沒有映射,則返回一個消息

            String msg = getInternal().getMessage("processInvalid");

            //記錄這個錯誤消息

            log.error(msg + " " + path);

            response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);

            return null;

        }

        /** 處理組件 */

        protected HttpServletRequest processMultipart(HttpServletRequest request) {

           //如果獲取的request方法不是post

           if (!"POST".equalsIgnoreCase(request.getMethod())) {

                return (request);

            }

            //獲取contentType

            String contentType = request.getContentType();

            //如果contentType的類型是multipart/form-data,則封裝

            if ((contentType != null)&& contentType.startsWith("multipart/form-data")) {

                //對request進行封裝

                return (new MultipartRequestWrapper(request));

            } else {

                return (request);

            }

        }

        /** 處理NoCache */

        protected void processNoCache(HttpServletRequest request,

            HttpServletResponse response) {

            //設定Nocache

            if (moduleConfig.getControllerConfig().getNocache()) {

                //設定頭

                response.setHeader("Pragma", "No-cache");

                response.setHeader("Cache-Control", "no-cache,no-store,max-age=0");

                response.setDateHeader("Expires", 1);

            }

        }

        /** 處理路徑*/

        protected String processPath(HttpServletRequest request,

            HttpServletResponse response)

            throws IOException {

            String path;

            //獲取path

            path = (String) request.getAttribute(INCLUDE_PATH_INFO);

    圓角矩形: 下面一段代碼描述了Struts如何實現(xiàn)獲取相對和絕對路徑的功能。

        //如果path為空

            if (path == null) {

                path = request.getPathInfo();

            }

            //如果不為空,則返回這個path

            if ((path != null) && (path.length() > 0)) {

                return (path);

            }

            //獲取servlet 的path

            path = (String) request.getAttribute(INCLUDE_SERVLET_PATH);

            //如果為空

            if (path == null) {

                path = request.getServletPath();

            }

            //如果不為空

            String prefix = moduleConfig.getPrefix();

            //獲取前綴

            if (!path.startsWith(prefix)) {

                String msg = getInternal().getMessage("processPath");

                //記錄錯誤信息

                log.error(msg + " " + request.getRequestURI());

                response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);

                //返回空

                return null;

            }

            //截取path

            path = path.substring(prefix.length());

            //根據(jù)/和.進行截取

            int slash = path.lastIndexOf("/");

            int period = path.lastIndexOf(".");

            //截取path

            if ((period >= 0) && (period > slash)) {

                path = path.substring(0, period);

            }

            //返回path

            return (path);

    }

    ……

    上述代碼主要展示了process方法是如何進行轉(zhuǎn)發(fā)視圖層的請求的。下面主要展示process方法是如何處理模型層處理后要返回視圖層的動作的,代碼如下所示:

    ……

        //……其他的一些處理器,這里不再進行詳細說明

        /**根據(jù)url進行farword*/

        protected void doForward(String uri, HttpServletRequest request,

            HttpServletResponse response)

            throws IOException, ServletException {

            //使用RequestDispatcher返回視圖層

            RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);

            //判斷RequestDispatcher是否為空

            if (rd == null) {

                //返回錯誤信息

               response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,

                    getInternal().getMessage("requestDispatcher", uri));

                return;

            }

            //使用RequestDispatcher的forward方法

            rd.forward(request, response);

        }

        /** 根據(jù)url,進行Include*/

        protected void doInclude(String uri, HttpServletRequest request,

            HttpServletResponse response)

            throws IOException, ServletException {

            //使用RequestDispatcher返回視圖層

            RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);

            //判斷RequestDispatcher是否為空

            if (rd == null) {

              //返回錯誤信息 

        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,

                    getInternal().getMessage("requestDispatcher", uri));

                return;

            }

            //使用RequestDispatcher的include方法

            rd.include(request, response);

        }

        /** 返回MessageResources */

        protected MessageResources getInternal() {

            return (servlet.getInternal());

        }

        /** 返回ServletContext */

        protected ServletContext getServletContext() {

            return (servlet.getServletContext());

        }

    }

    通過上面的代碼分析,可以看出,這里主要使用web.xml配置文件,也就是說,在Struts中,主要是通過配置文件來完成的,web.xml的示例代碼如下:

    <?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">

        <servlet>

            <servlet-name>actionServlet</servlet-name>

            <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

            <init-param>

                <!--配置文件的位置和名稱-->

                <param-name>config</param-name>

                <param-value>/WEB-INF/struts-config.xml</param-value>

                <!--應用程序的資源集合的類-->

                <param-name> application </param-name>

                <param-value>null</param-value>    

            </init-param>

            <load-on-startup>1</load-on-startup>

        </servlet> 

        <servlet-mapping>

             <servlet-name>actionServlet</servlet-name>

             <url-pattern>*.do</url-pattern>

        </servlet-mapping>

    </web-app>

    代碼說明:

    — 這里的初始化參數(shù)<init-param>可以定義多個。

    在web.xml里定義了servlet的映射和要使用的Struts配置文件,這里再給出一個struts-config.xml的示例代碼:

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>    

        <action-mappings>

            <action path="/helloWorld" type="com.gf.action.HelloWorldAction">

                 <forward name="index" path="/WEB-INF/jsp/index.jsp"/>

            </action>

        </action-mappings>

    </struts-config>

    可以看出,在控制器部分,Struts和Spring很相似。Struts controller基本功能如下:

    (1)截獲用戶的Http請求。

    (2)把這個請求映射到相應的Action類,如果這是此類收到的第一個請求,則將初始化實例緩存。

    (3)根據(jù)配置文件是否定義來創(chuàng)建或發(fā)現(xiàn)一個ActionForm bean實例,然后將請求過程移植到Bean。

    (4)調(diào)用Action實例的exectue方法,并將ActioForm,Action Mapping,Request和Response對象傳給它。

    (5)exectue返回一個ActionForward對象,然后返回視圖層。

    11.2.2  Action(控制器)

    如果要使用Struts,就離不開Action,但每個Action都只建立一個實例,所以Action不是線程安全的。Struts提供了多種Action供選擇使用。普通的Action只能通過調(diào)用execute執(zhí)行一項任務,而DispatchAction可以根據(jù)配置參數(shù)執(zhí)行,而不是僅進入execute()函數(shù),這樣可以執(zhí)行多種任務。LookupDispatchAction可以根據(jù)提交表單按鈕的名稱來執(zhí)行函數(shù),所有的控制器都繼承于Action,它的示例源代碼如下:

    //*******Action.java**************

    package org.apache.struts.action;

    //引入struts的util包

    import org.apache.struts.Globals;

    import org.apache.struts.config.ModuleConfig;

    import org.apache.struts.util.MessageResources;

    import org.apache.struts.util.ModuleUtils;

    import org.apache.struts.util.RequestUtils;

    import org.apache.struts.util.TokenProcessor;

    //引入servlet包

    import javax.servlet.ServletContext;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import javax.servlet.http.HttpSession;

    import java.util.Locale;

    /** 該類作為頁面請求和后臺處理的適配器 */

    public class Action {

        /** 定義一個TokenProcessor 實例 */

        private static TokenProcessor token = TokenProcessor.getInstance();

        /** 定義一個ActionServlet */

        protected transient ActionServlet servlet = null;

        /** 獲取一個ActionServlet */

        public ActionServlet getServlet() {

            return (this.servlet);

        }

        /** 設定ActionServlet */

        public void setServlet(ActionServlet servlet) {

            this.servlet = servlet;

        }

        /** 接受頁面請求,然后轉(zhuǎn)入處理的方法 */

        public ActionForward execute(ActionMapping mapping, ActionForm form,

            ServletRequest request, ServletResponse response)

            throws Exception {

            try {

                //執(zhí)行execute方法

                return execute(mapping, form, (HttpServletRequest) request,

    圓角矩形: 下面一段代碼定義了要繼承Action,則必須實現(xiàn)execute方法。                (HttpServletResponse) response);

            } catch (ClassCastException e) {

                return null;

            }

        }

        /** 接受頁面請求,然后轉(zhuǎn)入處理的方法,要繼承類來實現(xiàn)該方法 */

        public ActionForward execute(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

            return null;

        }

        /** 添加消息 */

        protected void addMessages(HttpServletRequest request,

            ActionMessages messages) {

            if (messages == null) {

                return;

            }

            //獲取已經(jīng)存在的消息類

            ActionMessages requestMessages = (ActionMessages) request.getAttribute (Globals.MESSAGE_KEY);

            //如果沒有,則創(chuàng)建一個新的

            if (requestMessages == null) {

                requestMessages = new ActionMessages();

            }

            //增加消息

            requestMessages.add(messages);

            //如果仍然沒有消息,則去除消息

            if (requestMessages.isEmpty()) {

                request.removeAttribute(Globals.MESSAGE_KEY);

                return;

            }

            //將消息置入request

            request.setAttribute(Globals.MESSAGE_KEY, requestMessages);

        }

        /** 添加錯誤 */

        protected void addErrors(HttpServletRequest request, ActionMessages errors) {

            if (errors == null) {

                return;

            }

            //獲取已經(jīng)存在的錯誤類

            ActionMessages requestErrors =

                (ActionMessages) request.getAttribute(Globals.ERROR_KEY);

            //如果沒有,則創(chuàng)建一個新的

            if (requestErrors == null) {

                requestErrors = new ActionMessages();

            }

            //添加錯誤信息

            requestErrors.add(errors);

            //如果仍然為空,則去除消息

            if (requestErrors.isEmpty()) {

                request.removeAttribute(Globals.ERROR_KEY);

                return;

            }

            //將錯誤信息置入request

            request.setAttribute(Globals.ERROR_KEY, requestErrors);

        }

        /** 產(chǎn)生一個Token */

        protected String generateToken(HttpServletRequest request) {

            return token.generateToken(request);

        }

        /** 獲取錯誤信息 */

        protected ActionMessages getErrors(HttpServletRequest request) {

            ActionMessages errors = (ActionMessages) request.getAttribute(Globals.ERROR_KEY);

    圓角矩形: 下面一段代碼描述了要獲取的本地資源和消息。        //如果沒有,則創(chuàng)建一個新的

            if (errors == null) {

                errors = new ActionMessages();

            }

            //返回錯誤信息

            return errors;

        }

        /** 獲取當前的Locale */

        protected Locale getLocale(HttpServletRequest request) {

            return RequestUtils.getUserLocale(request, null);

        }

        /** 獲取消息 */

        protected ActionMessages getMessages(HttpServletRequest request) {

            ActionMessages messages =ActionMessages) request.getAttribute(Globals. MESSAGE_KEY);

            //如果沒有,則創(chuàng)建一個新的消息

            if (messages == null) {

                messages = new ActionMessages();

            }

            //返回消息

            return messages;

        }

        /** 返回資源 */

        protected MessageResources getResources(HttpServletRequest request) {

            return ((MessageResources) request.getAttribute(Globals.MESSAGES_KEY));

        }

        /** 返回資源 */

        protected MessageResources getResources(HttpServletRequest request,

            String key) {

            //獲取當前ServletContext

            ServletContext context = getServlet().getServletContext();

            ModuleConfig moduleConfig =ModuleUtils.getInstance().getModuleConfig(request, context);

            // 返回MessageResources

            return (MessageResources) context.getAttribute(key+ moduleConfig.getPrefix());

        }

        /** 返回Cancelled */

        protected boolean isCancelled(HttpServletRequest request) {

            return (request.getAttribute(Globals.CANCEL_KEY) != null);

        }

        /** 返回TokenValid */

        protected boolean isTokenValid(HttpServletRequest request) {

            return token.isTokenValid(request, false);

        }

        /** 返回TokenValid */

        protected boolean isTokenValid(HttpServletRequest request, boolean reset) {

    圓角矩形: 下面一段代碼實現(xiàn)了保存消息和錯誤信息的功能。        return token.isTokenValid(request, reset);

        }

        /** 重置Token */

        protected void resetToken(HttpServletRequest request) {

            token.resetToken(request);

        }

        /** 保存錯誤信息 */

        protected void saveErrors(HttpServletRequest request, ActionMessages errors) {

            //如果錯誤信息為空,則去除

            if ((errors == null) || errors.isEmpty()) {

                request.removeAttribute(Globals.ERROR_KEY);

                //返回空

                return;

            }

            //將錯誤信息置入request

            request.setAttribute(Globals.ERROR_KEY, errors);

        }

        /** 保存消息 */

        protected void saveMessages(HttpServletRequest request,ActionMessages messages) {

            // 如果消息為空,則去除

            if ((messages == null) || messages.isEmpty()) {

                request.removeAttribute(Globals.MESSAGE_KEY);

                return;

            }

            //將消息置入request

            request.setAttribute(Globals.MESSAGE_KEY, messages);

        }

        /** 保存消息 */

        protected void saveMessages(HttpSession session, ActionMessages messages) {

            //如果消息為空,則去除

            if ((messages == null) || messages.isEmpty()) {

                request.removeAttribute(Globals.MESSAGE_KEY);

                return;

            }

            //將消息置入request

            session.setAttribute(Globals.MESSAGE_KEY, messages);

        }

        /** 保存錯誤 */

        protected void saveErrors(HttpSession session, ActionMessages errors) {

            //如果錯誤信息為空,則去除

            if ((errors == null) || errors.isEmpty()) {

                request.removeAttribute(Globals.ERROR_KEY);

                //返回空

                return;

            }

            //將錯誤信息置入request

            session.setAttribute(Globals.ERROR_KEY, errors);

        }

        /** 保存Token */

        protected void saveToken(HttpServletRequest request) {

            token.saveToken(request);

        }

        /** 設定Locale */

        protected void setLocale(HttpServletRequest request, Locale locale) {

            HttpSession session = request.getSession();

            //如果為空,則使用默認的

            if (locale == null) {

                locale = Locale.getDefault();

            }

            //將locale置入session

            session.setAttribute(Globals.LOCALE_KEY, locale);

        }

    }

    11.2.3  Action Mapping(映射)

    ActionMapping是ActionConfig的子類,實質(zhì)上是對struts-config.xml的一個映射,從中可以取得所有的配置信息。

    ActionServelt將ActionMapping傳遞給Action,主要是通過配置文件來實現(xiàn)的,在Struts中,默認的配置文件是WEB-INF下的struts-config.xml。通過配置文件struts-config.xml可以定義全局轉(zhuǎn)發(fā)的方式、ActionMapping、ActionForm和數(shù)據(jù)源。先來看前面的示例代碼:

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>    

        <action-mappings>

            <!--請求的url對應于< action>中的path屬性-->

            <action path="/helloWorld" type="com.gc.action.HelloWorldAction">

                <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="index" path="/WEB-INF/jsp/index.jsp"/>

            </action>

        </action-mappings>

    </struts-config>

    代碼說明如下:

    —  <action-mappings>用來描述ActionMapping,在<action-mappings>下的每一個<action>都是一個ActionMapping對象。當客戶端發(fā)出請求至ActionServlet時,請求的url對應于< action>中的path屬性,而要執(zhí)行的Action則是type屬性所設定的內(nèi)容。執(zhí)行完Action后,返回的ActionForward則在< forward >中設定。

    — 上面配置文件的訪問路徑是:http://localhost:8080/myStruts/ helloWorld.do。

    (1)全局轉(zhuǎn)發(fā)的定義方式

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>

        <!-- forward的屬性name表示全局轉(zhuǎn)發(fā)的名稱,path表示全局轉(zhuǎn)發(fā)的相對路徑-->   

        <global-forwards>        

            <forward  name="welcome" path="/WEB-INF/jsp/welcome.jsp"/>    

        </global-forwards>

        <action-mappings>

            <!--請求的url對應于< action>中的path屬性-->

            <action path="/helloWorld" type="com.gc.action.HelloWorldAction">

                <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="index" path="/WEB-INF/jsp/index.jsp"/>

            </action>

        </action-mappings>

    </struts-config>

    代碼說明:

    —  <global-forwards>中,forward的屬性name表示全局轉(zhuǎn)發(fā)的名稱,path表示全局轉(zhuǎn)發(fā)的相對路徑。

    —  forward除了name和path屬性外,還可以設定redirect屬性,如果redirect屬性設置為true,則ActionServlet會使用sendRedirect方法來轉(zhuǎn)發(fā)資源。

    (2)定義ActionMapping

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>  

        <!--全局路徑--> 

        <global-forwards>        

            <forward  name="welcome" path="/WEB-INF/jsp/welcome.jsp"/>    

        </global-forwards>

        <action-mappings>

            <!--請求的url對應于< action>中的path屬性-->

            <action path="/helloWorld" type="com.gc.action.HelloWorldAction">

                <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="index" path="/WEB-INF/jsp/index.jsp"/>

            </action>

            <action path="/regedit" type="com.gc.action.RegeditAction">

                <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="regedit" path="/WEB-INF/jsp/regedit.jsp"/>

            </action>

        </action-mappings>

    </struts-config>

    代碼說明:

    —  <action-mappings>中的每一個<action>都對應一個ActionMapping對象。

    —  <action>除了path和type屬性外,還可以設定很多屬性:name屬性,用來表示與Action相關(guān)聯(lián)的ActionForm;scope屬性,用來表示ActionForm的作用域;prefix屬性,用來表示ActionForm的前綴;suffix屬性,用來表示ActionForm的后綴;input屬性,用來表示當ActionForm發(fā)生錯誤時,必須返回的表單路徑;unknown屬性,設為true時,所有沒有定義ActionMapping的操作都將轉(zhuǎn)到這里來;validate屬性,設為true時,表示在執(zhí)行Action前,會調(diào)用ActionForm的validate方法來檢查輸入值。

    (3)定義ActionForm

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>   

        <!--全局路徑-->

        <global-forwards>        

            <!-- forward 表示執(zhí)行完畢后返回的頁面-->

            <forward  name="welcome" path="/WEB-INF/jsp/welcome.jsp"/>    

        </global-forwards>

        <form-beans>

            <form-bean name="user" type=" com.gc.action.User"/>

        </form-beans>

        <action-mappings>

            <!--請求的url對應于< action>中的path屬性-->

            <action path="/helloWorld" type="com.gc.action.HelloWorldAction">

                <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="index" path="/WEB-INF/jsp/index.jsp"/>

            </action>

            <action path="/regedit" type="com.gc.action.RegeditAction" name=”user”>

                <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="regedit" path="/WEB-INF/jsp/regedit.jsp"/>

                <forward name="success" path="/WEB-INF/jsp/success.jsp"/>

            </action>

        </action-mappings>

    </struts-config>

    代碼說明:

    —  <form-beans>用來定義用到的ActionForm,<form-bean>的屬性包括name和type。

    — 在path屬性為regedit的action中,定義name屬性為user。

    (4)定義數(shù)據(jù)源

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config> 

        <!--全局路徑-->  

        <global-forwards>        

            <forward  name="welcome" path="/WEB-INF/jsp/welcome.jsp"/>    

        </global-forwards>

        <form-beans>

            <form-bean name="user" type=" com.gc.action.User"/>

        </form-beans>

        <action-mappings>

            <!--請求的url對應于< action>中的path屬性-->

            <action path="/helloWorld" type="com.gc.action.HelloWorldAction">

                 <forward name="index" path="/WEB-INF/jsp/index.jsp"/>

            </action>

            <action path="/regedit" type="com.gc.action.RegeditAction" name=”user”>

                 <!-- forward 表示執(zhí)行完畢后返回的頁面-->

                 <forward name="regedit" path="/WEB-INF/jsp/regedit.jsp"/>

                <forward name="success" path="/WEB-INF/jsp/success.jsp"/>

            </action>

        </action-mappings>

        <!--在Action中可以通過getDataSource(request, "conPool")來取得DataSource-->

        <data-sources>

            <data-source  key=”conPool”  type=” org.apache.commons.dbcp.BasicDataSource”

                <set-property

                    autoCommit="true"

                    description="數(shù)據(jù)庫連接池"

                    driverClass="com.microsoft.jdbc.sqlserver.SQLServerDriver"

                    maxCount="150"

                    minCount="20"

                    url="jdbc:microsoft:sqlserver://localhost:1433/stdb"

                    username="admin"

                    password="admin" />

            <data-source/>

        </data-sources>

    </struts-config>

    代碼說明:

    — 定義<data-source>的屬性key為conPool,則在Action中可以通過getDataSource(request, "conPool")來取得DataSource。

    — 定義<data-source>的屬性type為org.apache.commons.dbcp.BasicDataSource,表示使用的是DBCP連接池。

    — 在<set-property>中定義了與數(shù)據(jù)庫相關(guān)的屬性,因為相關(guān)屬性和其他數(shù)據(jù)庫類似,這里就不再解釋了。

    //******* ActionMapping.java**************

    package org.apache.struts.action;

    //引入日志

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.apache.struts.config.ActionConfig;

    import org.apache.struts.config.ForwardConfig;

    import java.util.ArrayList;

    /** 該類用于映射,繼承于ActionConfig */

    public class ActionMapping extends ActionConfig {

        /** 定義日志類 */

        private static Log log = LogFactory.getLog(ActionMapping.class);

        /** 獲取ActionForward */

        public ActionForward findForward(String forwardName) {

            ForwardConfig config = findForwardConfig(forwardName);

            //如果ForwardConfig為空

            if (config == null) {

                config = getModuleConfig().findForwardConfig(forwardName);

            }

            //如果ForwardConfig為空,記錄警告

            if (config == null) {

                if (log.isWarnEnabled()) {

                    log.warn("Unable to find '" + forwardName + "' forward.");

                }

            }

            //返回ActionForward

            return ((ActionForward) config);

        }

        /** 返回Forwards */

        public String[] findForwards() {

            ArrayList results = new ArrayList();

            ForwardConfig[] fcs = findForwardConfigs();

            //添加ForwardConfig

            for (int i = 0; i < fcs.length; i++) {

                results.add(fcs[i].getName());

            }

            //將list轉(zhuǎn)換為數(shù)組

            return ((String[]) results.toArray(new String[results.size()]));

        }

        /** 獲取InputForward */

        public ActionForward getInputForward() {

            if (getModuleConfig().getControllerConfig().getInputForward()) {

                return (findForward(getInput()));

            } else {

                //如果沒有,則創(chuàng)建一個新的

                return (new ActionForward(getInput()));

            }

        }

    }

    11.2.4  ActionForm(表單控制器)

    ActionForm使用了ViewHelper模式,是對HTML中Form的一個封裝,其中包含有validate方法,用于驗證Form數(shù)據(jù)的有效性。ActionForm是一個符合JavaBean規(guī)范的類,所有的屬性都應與get和set對應。對于一些復雜的系統(tǒng),還可以采用DynaActionForm來構(gòu)造動態(tài)的Form,即通過預制參數(shù)來生成Form,這樣可以更靈活地擴展程序。ActionForm.java的示例代碼如下:

    //******* ActionForm.java**************

    package org.apache.struts.action;

    import org.apache.struts.upload.MultipartRequestHandler;

    import javax.servlet.ServletRequest;

    import javax.servlet.http.HttpServletRequest;

    import java.io.Serializable;

    /** 該類用于數(shù)據(jù)表單的封裝 */

    public abstract class ActionForm implements Serializable {

        /** 定義一個ActionServlet */

        protected transient ActionServlet servlet = null;

        /** 定義MultipartRequestHandler */

        protected transient MultipartRequestHandler multipartRequestHandler;

        /** 獲取ActionServlet */

        protected ActionServlet getServlet() {

            return (this.servlet);

        }

        /** 獲取ServletWrapper*/

        public ActionServletWrapper getServletWrapper() {

            return new ActionServletWrapper(getServlet());

        }

        /** 返回MultipartRequestHandler */

        public MultipartRequestHandler getMultipartRequestHandler() {

            return multipartRequestHandler;

        }

        /** 設定 ActionServlet */

        public void setServlet(ActionServlet servlet) {

            this.servlet = servlet;

        }

        /** 設定MultipartRequestHandler */

        public void setMultipartRequestHandler(

            MultipartRequestHandler multipartRequestHandler) {

            this.multipartRequestHandler = multipartRequestHandler;

        }

        /** 重置 */

        public void reset(ActionMapping mapping, ServletRequest request) {

            try {

                //將Bean的屬性值置為空

                reset(mapping, (HttpServletRequest) request);

            } catch (ClassCastException e) {

                ;

            }

        }

        /** 重置 */

        public void reset(ActionMapping mapping, HttpServletRequest request) {

            //要繼承類實現(xiàn)該方法

        }

        /** 對數(shù)據(jù)進行驗證 */

        public ActionErrors validate(ActionMapping mapping, ServletRequest request) {

            try {

                //驗證數(shù)據(jù)是否符合定義

                return (validate(mapping, (HttpServletRequest) request));

            } catch (ClassCastException e) {

                return (null);

            }

        }

        /** 驗證數(shù)據(jù),要繼承類實現(xiàn) */

        public ActionErrors validate(ActionMapping mapping,

            HttpServletRequest request) {

            return (null);

        }

    }

    從代碼中可以看出,開發(fā)人員應該在自己的Bean里覆蓋validate方法,并在配置文件里設置<action>元素的validate為true。在ActionServlet調(diào)用Action類前,它會調(diào)用validate(),如果返回的ActionErrors不是null,則ActinForm會根據(jù)錯誤關(guān)鍵字將ActionErrors存儲在請求屬性列表中。

    如果返回的不是null,而且長度大于0,則根據(jù)錯誤關(guān)鍵字將實例存儲在請求的屬性列表中,然后ActionServlet將響應轉(zhuǎn)發(fā)到配置文件<action>元素的input屬性所指向的目標。如果需要執(zhí)行特定的數(shù)據(jù)有效性檢查,最好在Action類中進行這個操作,而不是在ActionForm類中進行。

    典型的ActionFrom Bean只有屬性的設置與讀取方法,而沒有實現(xiàn)事務邏輯的方法,只有簡單的輸入檢查邏輯,使用的目的是為了存儲用戶在相關(guān)表單中輸入的最新數(shù)據(jù),以便可以將同一網(wǎng)頁進行再生,同時提供一組錯誤信息,這樣就可以讓用戶修改不正確的輸入數(shù)據(jù)。而真正對數(shù)據(jù)有效性進行檢查的是Action類或適當?shù)氖聞者壿婤ean。

    示例的具體實現(xiàn)思路是:在前面已經(jīng)建立的myLogin工程的基礎上進行開發(fā),web.xml還采用原來的配置不變。首先編寫提交數(shù)據(jù)的頁面和輸出提交內(nèi)容的頁面,再編寫一個用來存放提交內(nèi)容的Bean,然后編寫繼承ActionFrom的控制器,再編寫Struts的配置文檔,最后啟動Tomcat,運行示例即可。具體步驟如下:

    *  編寫提交數(shù)據(jù)的頁面submit.jsp,該頁面主要用來提交用戶輸入的內(nèi)容。為了演示方便,這里只提交一個內(nèi)容,該頁面放在myLogin/jsp目錄下,submit.jsp的示例代碼如下:

    <%@page contentType="text/html;charset=GBK"%>

    <html>

    <head><title>練習使用ActionFrom</title></head>

    <body>

        <form name="HelloWorld" action="/myLogin/submit.do" method="post">

            請輸入要提交的內(nèi)容:<input type="text" name="helloWorld" value=""/><br>

            <input type="submit" value="提交"/>

        </form>

    </body>

    </html>

    *  編寫輸出提交內(nèi)容的頁面helloWorld.jsp,該頁面主要用來顯示用戶提交的內(nèi)容。為了演示方便,這里只是簡單演示一下helloWorld.jsp,該頁面放在myLogin/jsp目錄下,helloWorld.jsp的示例代碼如下:

    <%@page contentType="text/html;charset=GBK"%>

    <html>

    <head><title>利用Struts輸出HelloWorld</title></head>

    <%

    String str = (String)request.getAttribute("helloWorld");

    %>

    <body>

        <font size='22'><%=str%></font>

    </body> 

    </html>

    *  編寫一個用來存放提交內(nèi)容的類HelloWorld,Struts就是通過它來進行數(shù)據(jù)的動態(tài)綁定的。首先新建一個包com.myLogin.bean,將該類放在此包下,HelloWorld.java的示例代碼如下:

    //******* HelloWorld.java**************

    package com.myLogin.bean;

    import org.apache.struts.action.ActionForm;

    public class HelloWorld extends ActionForm {

        //定義變量helloWorld

        private String helloWorld = null;

        //設定helloWorld

        public void setHelloWorld(String helloWorld) {

            this.helloWorld = helloWorld;

        }

        //獲得helloWorld

        public String getHelloWorld() {

            return this.helloWorld;

        }

    }

    *  編寫繼承Action的控制器HelloWorldAction,該控制器實現(xiàn)execute方法,該類放在com.myLogin.action包下,HelloWorldAction的示例代碼如下:

    //******* HelloWorldAction.java**************

    package com.myLogin.action;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.struts.action.Action;

    import org.apache.struts.action.ActionForm;

    import org.apache.struts.action.ActionForward;

    import org.apache.struts.action.ActionMapping;

    import com.myLogin.bean.HelloWorld;

    public class HelloWorldAction  extends Action{

        public ActionForward execute(ActionMapping mapping, ActionForm form, Http ServletRequest request, HttpServletResponse response)  throws Exception {  

            //將頁面提交的進行轉(zhuǎn)換成form

            HelloWorld helloWorld = (HelloWorld)form;

            //將獲取的頁面內(nèi)容注入request

            request.setAttribute("helloWorld", helloWorld.getHelloWorld());

            //返回到helloWorld.jsp頁面

            return mapping.findForward("helloWorld");   

        }

    }

      編寫Struts的配置文檔struts-config.xml,該文件放在WEB-INF目錄下,struts-config.xml的示例代碼如下:

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>

         <!--定義formbean-->

         <form-beans>

             <form-bean name="helloWorld" type="com.myLogin.bean.HelloWorld"/>

         </form-beans>

        <action-mappings>

        <!--定義提交時訪問的路徑-->

            <action path="/submit" type="com.myLogin.action.HelloWorldAction" name="helloWorld">

                <forward name="helloWorld" path="/jsp/helloWorld.jsp"/>

            </action>

            <!--定義初次訪問時的路徑-->

            <action path="/input"

                type="org.apache.struts.actions.ForwardAction"

                parameter="/jsp/submit.jsp"/>

        </action-mappings>

    </struts-config>

      建立web.xml,該文件放在WEB-INF目錄下,web.xml的示例代碼如下:

    <?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">

        <servlet>

            <servlet-name>actionServlet</servlet-name>

            <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

            <!--初始參數(shù)-->

            <init-param>

                <param-name>config</param-name>

                <param-value>/WEB-INF/struts-config.xml</param-value>      

            </init-param>

            <load-on-startup>1</load-on-startup>

    </servlet> 

    <!--處理所有后綴為do的請求-->

        <servlet-mapping>

             <servlet-name>actionServlet</servlet-name>

             <url-pattern>*.do</url-pattern>

        </servlet-mapping>

    </web-app>

      啟動Tomcat,運行示例。

    在瀏覽器輸入http://localhost:8080/myLogin/input.do,瀏覽器即出現(xiàn)提示用戶輸入內(nèi)容的畫面,如圖11.17所示。

      在瀏覽器輸入“ggggg”,然后單擊“提交”按鈕,即可看到在輸出頁面輸出了剛才輸入的信息“ggggg”,如圖11.18所示。

            

    圖11.17  提示用戶輸入內(nèi)容的畫面                圖11.18  輸出了剛才輸入的信息“ggggg”

    通過ActionForm的示例,讀者可以看到,Struts通過ActionForm實現(xiàn)了對數(shù)據(jù)的封裝,這樣從頁面取值和將值返回頁面時就非常方便。

    11.2.5  ActionErrors(錯誤處理)

    ActionErrors是對錯誤信息的包裝,一旦在執(zhí)行action或者form.validate中出現(xiàn)異常,即可產(chǎn)生一個ActionError并最終加入到ActionErrors。在Form驗證的過程中,如果有Error發(fā)生,則會將頁面重新導向至輸入頁,并提示錯誤。ActionErrors的源代碼如下:

    //******* ActionErrors.java**************

    package org.apache.struts.action;

    import java.io.Serializable;

    /** 該類對錯誤信息進行封裝 */

    public class ActionErrors extends ActionMessages implements Serializable {

           /** 構(gòu)造函數(shù) */

        public ActionErrors() {

            super();

        }

        /** 構(gòu)造函數(shù) */

        public ActionErrors(ActionErrors messages) {

            super(messages);

        }

    }

    從上面的代碼中可以看出,該類繼承于ActionMessages,只是用來處理錯誤信息,所以關(guān)鍵還要看ActionMessages類,ActionMessages的源代碼如下:

    //******* ActionMessages.java**************

    package org.apache.struts.action;

    import java.io.Serializable;

    /** 該類對信息進行封裝和序列化 */

    public class ActionMessage implements Serializable {

        /** 定義消息的關(guān)鍵字 */

        protected String key = null;

        /** 定義消息的值 */

        protected Object[] values = null;

        /** 定義resource */

        protected boolean resource = true;

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key) {

            this(key, null);

        }

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key, Object value0) {

            this(key, new Object[] { value0 });

        }

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key, Object value0, Object value1) {

            this(key, new Object[] { value0, value1 });

        }

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key, Object value0, Object value1, Object value2) {

            this(key, new Object[] { value0, value1, value2 });

        }

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key, Object value0, Object value1,

            Object value2, Object value3) {

            this(key, new Object[] { value0, value1, value2, value3 });

        }

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key, Object[] values) {

            this.key = key;

            this.values = values;

            this.resource = true;

        }

        /** 構(gòu)造函數(shù) */

        public ActionMessage(String key, boolean resource) {

            this.key = key;

            this.resource = resource;

        }

        /** 獲得消息的關(guān)鍵字 */

        public String getKey() {

            return (this.key);

        }

        /** 獲得消息的值 */

        public Object[] getValues() {

            return (this.values);

        }

        /** 獲取Resource */

        public boolean isResource() {

            return (this.resource);

        }

    }

    可以看出這里的ActionMessages類,類似于Java里面的Map,有關(guān)鍵字和值,只是這里進行了封裝,這和Spring的Model比較類似。

    11.2.6  DispatchAction(多動作控制器)

    前面講Action時,曾經(jīng)講過所有繼承它的類都要實現(xiàn)execute方法,然后在此方法里進行相應的邏輯處理。它的局限性是頁面中只有一個按鈕,如果有多個就沒有辦法,因為每個按鈕提交后,都要執(zhí)行execute方法??赡茏x者就會有疑問了,如果頁面中有多個按鈕,該怎么操作呢?Struts提供的DispatchAction就可以實現(xiàn)這樣的功能,先來看一下DispatchAction的源代碼,看它是如何實現(xiàn)這樣的操作的,DispatchAction的源代碼如下所示:

    //******* DispatchAction.java**************

    package org.apache.struts.actions;

    //引入日志類

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.apache.struts.action.ActionForm;

    import org.apache.struts.action.ActionForward;

    import org.apache.struts.action.ActionMapping;

    //引入servlet

    import javax.servlet.ServletException;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    //引入反射包

    import java.lang.reflect.InvocationTargetException;

    import java.lang.reflect.Method;

    import java.util.HashMap;

    /** 該類用來實現(xiàn)多動作處理,繼承于BaseAction */

    public abstract class DispatchAction extends BaseAction {

        /** 定義日志 */

        protected static Log log = LogFactory.getLog(DispatchAction.class);

        /** 定義類的實例 */

        protected Class clazz = this.getClass();

        /** 定義多個方法的存儲器 */

        protected HashMap methods = new HashMap();

        /** 定義類型 */

        protected Class[] types =

            {

                ActionMapping.class, ActionForm.class, HttpServletRequest.class,

                HttpServletResponse.class

            };

        /** 定義execute方法 */

        public ActionForward execute(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

           //如果提交的是取消按鈕

           if (isCancelled(request)) {

                ActionForward af = cancelled(mapping, form, request, response);

    圓角矩形: 下面一段代碼實現(xiàn)了根據(jù)傳入的方法名參數(shù)來實現(xiàn)多動作的調(diào)用功能。

            //返回ActionForward

                if (af != null) {

                    return af;

                }

            }

            //獲取根據(jù)request獲取的參數(shù)

            String parameter = getParameter(mapping, form, request, response);

            //獲取方法的名稱

            String name =

                getMethodName(mapping, form, request, response, parameter);

            // 判斷方法名是否為execute或perform

            if ("execute".equals(name) || "perform".equals(name)) {

                String message =messages.getMessage("dispatch.recursive", mapping.getPath());

                //如果是,報錯

                log.error(message);

                throw new ServletException(message);

            }

            // 反射調(diào)用該方法

            return dispatchMethod(mapping, form, request, response, name);

        }

        /** 未指定方法名時調(diào)用的方法 */

        protected ActionForward unspecified(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

            String message =messages.getMessage("dispatch.parameter", mapping.getPath(), mapping.getParameter());

            //如果未指定方法名,則報錯

            log.error(message);

            //拋出異常

            throw new ServletException(message);

        }

        /** 當提交的是取消按鈕時執(zhí)行的方法 */

        protected ActionForward cancelled(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

    圓角矩形: 下面一段代碼描述了利用Java反射機制實現(xiàn)方法調(diào)用的細節(jié)。        throws Exception {

            return null;

        }

        /** 反射調(diào)用方法 */

        protected ActionForward dispatchMethod(ActionMapping mapping,

            ActionForm form, HttpServletRequest request,

            HttpServletResponse response, String name)

            throws Exception {

            //如果沒有指定方法名,則調(diào)用unspecified

            if (name == null) {

                return this.unspecified(mapping, form, request, response);

            }

            //指定被調(diào)用的方法

            Method method = null;

            try {

                //根據(jù)方法名獲取該方法

                method = getMethod(name);

            } catch (NoSuchMethodException e) {

                String message =messages.getMessage("dispatch.method", mapping.getPath(), name);

                //記錄錯誤

                log.error(message, e);

                //添加錯誤信息

                String userMsg =messages.getMessage("dispatch.method.user", mapping.getPath());

                throw new NoSuchMethodException(userMsg);

            }

            ActionForward forward = null;

            //定義參數(shù)

            try {

                Object[] args = { mapping, form, request, response };

                //反射調(diào)用指定的方法

                forward = (ActionForward) method.invoke(this, args);

            } catch (ClassCastException e) {

                String message =messages.getMessage("dispatch.return", mapping.getPath(), name);

                //記錄錯誤

                log.error(message, e);

                throw e;

            } catch (IllegalAccessException e) {

                String message =messages.getMessage("dispatch.error", mapping.getPath(), name);

                //記錄錯誤

                log.error(message, e);

                throw e;

            } catch (InvocationTargetException e) {

                Throwable t = e.getTargetException();

                //如果拋出的異常是Exception的實例

                if (t instanceof Exception) {

                    throw ((Exception) t);

                } else {

                    String message =messages.getMessage("dispatch.error", mapping.getPath(),

                            name);

                    //記錄錯誤

                    log.error(message, e);

                    throw new ServletException(t);

    圓角矩形: 下面一段代碼描述了如何獲取視圖層傳來的參數(shù),并獲取方法名。

            }

            }

            // 返回ActionForward 的實例

            return (forward);

        }

        /**返回參數(shù)*/

        protected String getParameter(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

            // 從映射中獲取參數(shù)

            String parameter = mapping.getParameter();

            //如果參數(shù)為空

            if (parameter == null) {

                String message =messages.getMessage("dispatch.handler", mapping.getPath());

                //記錄錯誤

                log.error(message);

                //拋出異常

                throw new ServletException(message);

            }

            //返回參數(shù)

            return parameter;

        }

        /** 根據(jù)方法名獲取方法 */

        protected Method getMethod(String name)

            throws NoSuchMethodException {

            synchronized (methods) {

                Method method = (Method) methods.get(name);

                //如果方法名為空

                if (method == null) {

                    method = clazz.getMethod(name, types);

                    methods.put(name, method);

                }

                //返回指定的方法

                return (method);

            }

        }

        /** 根據(jù)參數(shù)值獲取方法名 */

        protected String getMethodName(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response,

            String parameter) throws Exception {

            // 獲取方法名

            return request.getParameter(parameter);

        }

    }

    前面了解了多動作的實現(xiàn)機理,下面將通過具體的示例來深入講解實現(xiàn)方式。具體實現(xiàn)思路是:仍然在前面myLogin工程的繼承上進行,首先編寫多動作提交的頁面,信息輸出的頁面仍然采用前面的輸出頁面,然后編寫控制器,繼承DispatchAction,再編寫配置文件struts-config.xml,最后啟動Tomcat,運行示例,具體步驟如下:

    *  編寫JSP頁面multiActionSubmit.jsp,該頁面有多個提交動作,用來演示多動作提交的處理方式,該頁面放在myLogin/jsp目錄下,multiActionSubmit.jsp的示例代碼如下:

    <%@page contentType="text/html;charset=GBK"%>

    <html>

    <head><title>練習使用DispatchAction</title></head>

    <body>

        <form name="HelloWorld" action="/myLogin/helloWorldMultiAction.do" method="post">

            請輸入要提交的內(nèi)容:<input type="text" name="helloWorld" value=""/><br>

            <input type="submit" name="method" value="insert"/>

            <input type="submit" name="method" value="update"/>

            <input type="submit" name="method" value="delete"/>

        </form>

    </body>

    </html>

    *  仍然使用前面輸出信息的頁面helloWorld.jsp,helloWorld.jsp的示例代碼如下:

    <%@page contentType="text/html;charset=GBK"%>

    <html>

    <head><title>利用Struts輸出HelloWorld</title></head>

    <%

    String str = (String)request.getAttribute("helloWorld");

    %>

    <body>

        <font size='22'><%=str%></font>

    </body>

    </html>

    *  編寫控制器HelloWorldMultiAction,繼承DispatchAction,HelloWorldMultiAction.java的示例代碼如下:

    //******* HelloWorldMultiAction.java**************

    package com.myLogin.action;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.struts.action.ActionForm;

    import org.apache.struts.action.ActionForward;

    import org.apache.struts.action.ActionMapping;

    import org.apache.struts.actions.DispatchAction;

    import com.myLogin.bean.HelloWorld;

    public class HelloWorldMultiAction extends DispatchAction {

        //新增動作

        public ActionForward insert(ActionMapping mapping, ActionForm form, HttpServlet Request request, HttpServletResponse response)  throws Exception {  

            HelloWorld helloWorld = (HelloWorld)form;

            request.setAttribute("helloWorld", "您執(zhí)行的是新增動作:" + helloWorld. getHelloWorld());

            return mapping.findForward("helloWorld");   

        }

        //修改動作

        public ActionForward update(ActionMapping mapping, ActionForm form, HttpServlet Requestrequest, HttpServletResponse response)  throws Exception {  

            HelloWorld helloWorld = (HelloWorld)form;

            request.setAttribute("helloWorld", "您執(zhí)行的是修改動作:" + helloWorld. getHelloWorld());

            return mapping.findForward("helloWorld");   

        }

        //刪除動作

        public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServlet Requestrequest, HttpServletResponse response)  throws Exception {  

            HelloWorld helloWorld = (HelloWorld)form;

            request.setAttribute("helloWorld", "您執(zhí)行的是刪除動作:" + helloWorld. getHelloWorld());

            return mapping.findForward("helloWorld");   

        }

    }

    *  修改配置文檔struts-config.xml,示例代碼如下:

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>

         <!--定義formbean-->

         <form-beans>

             <form-bean name="helloWorld" type="com.myLogin.bean.HelloWorld"/>

         </form-beans>

        <action-mappings>

        <!--定義提交時訪問的路徑-->

            <action path="/submit" type="com.myLogin.action.HelloWorldAction" name= "helloWorld">

                <forward name="helloWorld" path="/jsp/helloWorld.jsp"/>

            </action>

            <!--定義提交時訪問的路徑-->

            <action path="/helloWorldMultiAction" type="com.myLogin.action.HelloWorld MultiAction" name="helloWorld" parameter="method">

                <forward name="helloWorld" path="/jsp/helloWorld.jsp"/>

            </action>

            <!--定義初次訪問時的路徑-->

            <action path="/input"

                type="org.apache.struts.actions.ForwardAction"

                parameter="/jsp/submit.jsp"/>

        <!--定義初次訪問多動作時的路徑-->

            <action path="/inputTemp"

                type="org.apache.struts.actions.ForwardAction"

                parameter="/jsp/multiActionSubmit.jsp"/>

        </action-mappings>

    </struts-config>

      啟動Tomcat,在瀏覽器輸入http://localhost:8080/myLogin/inputTemp.do,按Enter鍵后,瀏覽器即可出現(xiàn)提示用戶輸入的畫面,如圖11.19所示。

      輸入“dddd”,然后單擊“insert”按鈕,即可轉(zhuǎn)入輸出新增的畫面,如圖11.20所示。

          

             圖11.19  提示用戶輸入的畫面                       圖11.20  輸出新增的畫面

      單擊“update”按鈕,即可轉(zhuǎn)入輸出修改的畫面,如圖11.21所示。

      單擊“delete”按鈕,即可轉(zhuǎn)入輸出刪除的畫面,如圖11.22所示。

          

               圖11.21  輸出修改的畫面                        圖11.22  輸出刪除的畫面

    11.3  利用Struts實現(xiàn)用戶登錄的示例

    前面對Struts的核心類進行了講解,下面將講解一個利用Struts實現(xiàn)用戶登錄的示例,使讀者對Struts的運行機理有更深的了解。

    實現(xiàn)思路是:本示例仍然在前面myLogin工程的基礎上進行,首先新建一個登錄頁面,增加提交按鈕,接著新建一個ActionForm為User.java類,然后新建一個登錄的控制器,接著修改配置文檔,最后驗證上述功能。

    11.3.1  編寫實現(xiàn)登錄的頁面login.jsp

    新建一個登錄頁面login.jsp,增加提交按鈕,放在myLogin"jsp目錄下,login.jsp的示例代碼如下:

    <%@page contentType="text/html;charset=GBK"%>

    <html>

    <head><title>實現(xiàn)用戶登錄的Struts實例</title></head>

    <body>

        <font size=’22’> "${msg}"<br> </font>

        <form name="form1" action="/myLogin/login.do" method="post">

            用戶名:<input type="text" name="username" value="${user.username}"/><br>

           密碼:<input type="password" name="password" value="${user.password}"/><br>

            <input type="submit" name=”method” value="提交"/>

        </form>

    </body>

    </html>

    11.3.2  編寫存儲登錄用戶信息的類User.java

    在com.myLogin.bean包上,新建一個存儲登錄用戶信息的類User.java,該類繼承ActionForm,User.java的示例代碼如下:

    //******* User.java**************

    package com.myLogin.bean;

    import org.apache.struts.action.ActionForm;

    //該類繼承ActionForm

    public class User extends ActionForm {

        //定義用戶名

        private String username = null;

        //定義密碼

        private String password = null;

        //設定用戶名

        public void setUsername(String username) {

            this.username = username;

        }

        //獲取用戶名

        public String getUsername() {

            return this.username;

        }

        //設定密碼

        public void setPassword(String password) {

            this.password = password;

        }

        //獲取密碼

        public String getPassword() {

            return this.password;

        }

    }

    11.3.3  編寫控制器LoginAction.java

    在com.myLogin.action包上,新建一個控制器LoginAction.java,該類繼承Action,LoginAction.java的示例代碼如下:

    //******* LoginAction.java**************

    package com.myLogin.action;

    import java.io.IOException;

    import java.util.HashMap;

    import java.util.Map;

    import javax.servlet.ServletException;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.struts.action.*;

    import com.myLogin.bean.*;

    public class LoginAction extends Action  {

        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)  throws Exception {  

            String forwardJsp = "login";

            //將頁面提交的內(nèi)容進行封裝

            String username = ((User) form).getUsername();

            String password = ((User) form).getPassword();

            if (username == null && password == null) {

                request.setAttribute("msg", "請輸入用戶名和密碼");

            } else if ("".equals(username) || "".equals(password)) {

                request.setAttribute("msg", "必須輸入用戶名或密碼");

            } else if ("gf2008".equals(username) && "888888".equals(password)) {

                request.setAttribute("msg", "登錄成功");

            } else if (!"gf2008".equals(username)) {

                request.setAttribute("msg", "用戶名填寫錯誤");

            }

             request.setAttribute("user",(User) form);

            //返回到登錄畫面,顯示相關(guān)信息

            return mapping.findForward(“login”);

        }

    }

    11.3.4  配置Struts文檔struts-config.xml

    修改前面的配置文檔struts-config.xml,修改后的示例代碼如下:

    <?xml version="1.0" encoding="ISO-8859-1" ?>

    <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

    <struts-config>

         <!--定義formbean-->

         <form-beans>

             <form-bean name="helloWorld" type="com.myLogin.bean.HelloWorld"/>

            <form-bean name="user" type="com.myLogin.bean.User"/>

         </form-beans>

        <action-mappings>

        <!--定義提交時訪問的路徑-->

            <action path="/submit" type="com.myLogin.action.HelloWorldAction" name= "helloWorld">

                <forward name="helloWorld" path="/jsp/helloWorld.jsp"/>

            </action>

            <!--定義提交時訪問的路徑-->

            <action path="/helloWorldMultiAction" type="com.myLogin.action.HelloWorld MultiAction" name="helloWorld" parameter="method">

                <forward name="helloWorld" path="/jsp/helloWorld.jsp"/>

            </action>

        <!--定義登錄時訪問的路徑-->

            <action path="/login" type="com.myLogin.action.LoginAction" name="user">

                <forward name="login" path="/jsp/login.jsp"/>

            </action>

            <!--定義初次訪問時的路徑-->

            <action path="/input"

                type="org.apache.struts.actions.ForwardAction"

                parameter="/jsp/submit.jsp"/>

        <!--定義初次訪問多動作時的路徑-->

            <action path="/inputTemp"

                type="org.apache.struts.actions.ForwardAction"

                parameter="/jsp/multiActionSubmit.jsp"/>

        <!--定義初次訪問登錄時的路徑-->

            <action path="/loginTemp"

                type="org.apache.struts.actions.ForwardAction"

                parameter="/jsp/login.jsp"/>

        </action-mappings>

    </struts-config>

    11.3.5  配置web.xml

    仍然使用前面的配置文檔web.xml,示例代碼如下:

    <?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">

        <servlet>

            <!--定義映射關(guān)系-->

            <servlet-name>actionServlet</servlet-name>

            <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

            <!--定義初始化參數(shù)-->

            <init-param>

                <param-name>config</param-name>

                <param-value>/WEB-INF/struts-config.xml</param-value>      

            </init-param>

            <load-on-startup>1</load-on-startup>

        </servlet> 

        <!--定義訪問時的后綴,所有為do的都被截取-->

        <servlet-mapping>

             <servlet-name>actionServlet</servlet-name>

             <url-pattern>*.do</url-pattern>

        </servlet-mapping>

    </web-app>

    11.3.6  啟動Tomcat運行示例

    具體步驟如下:

    *  啟動Tomcat,在瀏覽器的地址欄中輸入http://localhost:8080/myLogin/loginTemp.do,按Enter鍵即可看到登錄畫面,如圖11.23所示。

    *  如果用戶名輸入錯誤(這里輸入gf3008),即可看到提示用戶名填寫錯誤的畫面,如圖11.24所示。

            

               圖11.23  登錄畫面                            圖11.24  提示用戶名填寫錯誤的畫面

    *  輸入用戶名“gf2008”,密碼“888888”,即可看到登錄成功的畫面,如圖11.25所示。

    圖11.25  登錄成功的畫面

    posted on 2009-03-06 10:32 rogerfan 閱讀(1942) 評論(0)  編輯  收藏 所屬分類: 【Java知識】 、【開源技術(shù)】
    主站蜘蛛池模板: 成人免费的性色视频| 亚洲国产精品无码久久青草 | 亚洲欧洲尹人香蕉综合| 免费一级毛片在线播放放视频 | 久久亚洲AV无码西西人体| 亚洲午夜无码毛片av久久京东热 | 久久成人国产精品免费软件| 国内精品久久久久久久亚洲| 亚洲а∨精品天堂在线| 亚欧在线精品免费观看一区| 国产AV无码专区亚洲A∨毛片| 全部在线播放免费毛片| 午夜高清免费在线观看| 亚洲国产情侣一区二区三区| 无码免费一区二区三区免费播放| 亚洲性久久久影院| 真正全免费视频a毛片| 成人在线免费观看| 亚洲制服丝袜精品久久| 日韩免费无码一区二区三区| 亚洲无码在线播放| 一级毛片a免费播放王色| 国产片免费在线观看| 亚洲人成未满十八禁网站| 无码av免费毛片一区二区| 久久亚洲AV成人出白浆无码国产| a级毛片在线免费看| 国产亚洲精品激情都市| 一级毛片a免费播放王色| 亚洲国产精品不卡毛片a在线| 精品久久久久亚洲| 日本免费网站在线观看| 亚洲免费网站观看视频| 欧美大尺寸SUV免费| 亚洲人配人种jizz| 免费国产作爱视频网站| 久久精品亚洲AV久久久无码| 2020久久精品国产免费| 亚洲不卡中文字幕| 在线观看特色大片免费视频| 亚洲人成77777在线观看网|