心的方向

          新的征途......
          posts - 75,comments - 19,trackbacks - 0

          Struts+Spring+Hibernate實(shí)現(xiàn)上傳下載(四)

          轉(zhuǎn)自:http://lihaiyan.javaeye.com/blog/127797

          Web層實(shí)現(xiàn)

            1、Web層的構(gòu)件和交互流程

            Web層包括主要3個(gè)功能:

            ·上傳文件。

            ·列出所有已經(jīng)上傳的文件列表,以供點(diǎn)擊下載。

            ·下載文件。

            Web層實(shí)現(xiàn)構(gòu)件包括與2個(gè)JSP頁面,1個(gè)ActionForm及一個(gè)Action:

            ·file-upload.jsp:上傳文件的頁面。

            ·file-list.jsp:已經(jīng)上傳文件的列表頁面。

            ·FileActionForm:file-upload.jsp頁面表單對(duì)應(yīng)的ActionForm。

            ·FileAction:繼承org.apache.struts.actions.DispatchAction的Action,這樣這個(gè)Action就可以通過一個(gè)URL參數(shù)區(qū)分中響應(yīng)不同的請(qǐng)求。

            Web層的這些構(gòu)件的交互流程如圖 6所示:

          420){this.resized=true;this.style.width=420;}" border=0 resized="true">
          圖 6 Web層Struts流程圖


            其中,在執(zhí)行文件上傳的請(qǐng)求時(shí),F(xiàn)ileAction在執(zhí)行文件上傳后,forward到loadAllFile出口中,loadAllFile加載數(shù)據(jù)庫(kù)中所有已經(jīng)上傳的記錄,然后forward到名為fileListPage的出口中,調(diào)用file-list.jsp頁面顯示已經(jīng)上傳的記錄。

            2、FileAction功能

            Struts 1.0的Action有一個(gè)弱項(xiàng):一個(gè)Action只能處理一種請(qǐng)求,Struts 1.1中引入了一個(gè)DispatchAction,允許通過URL參數(shù)指定調(diào)用Action中的某個(gè)方法,如http://yourwebsite/fileAction.do?method=upload即調(diào)用FileAction中的upload方法。通過這種方式,我們就可以將一些相關(guān)的請(qǐng)求集中到一個(gè)Action當(dāng)中編寫,而沒有必要為某個(gè)請(qǐng)求操作編寫一個(gè)Action類。但是參數(shù)名是要在struts-config.xml中配置的:

          1. <struts-config>
          2. <form-beans>
          3. <form-bean name="fileActionForm" type="sshfile.web.FileActionForm" />
          4. </form-beans>
          5. <action-mappings>
          6. <action name="fileActionForm" parameter="method" path="/fileAction"
          7. type="sshfile.web.FileAction">
          8. <forward name="fileListPage" path="/file-list.jsp" />
          9. <forward name="loadAllFile" path="/fileAction.do?method=listAllFile" />
          10. </action>
          11. </action-mappings>
          12. </struts-config>


            第6行的parameter="method"指定了承載方法名的參數(shù),第9行中,我們還配置了一個(gè)調(diào)用FileAction不同方法的Action出口。

            FileAction共有3個(gè)請(qǐng)求響應(yīng)的方法,它們分別是:

            ·upload(…):處理上傳文件的請(qǐng)求。

            ·listAllFile(…):處理加載數(shù)據(jù)庫(kù)表中所有記錄的請(qǐng)求。

            ·download(…):處理下載文件的請(qǐng)求。

            下面我們分別對(duì)這3個(gè)請(qǐng)求處理方法進(jìn)行講解。

            2.1 上傳文件

            上傳文件的請(qǐng)求處理方法非常簡(jiǎn)單,簡(jiǎn)之言之,就是從Spring容器中獲取業(yè)務(wù)層處理類FileService,調(diào)用其save(FileActionForm form)方法上傳文件,如下所示:

          1. public class FileAction
          2. extends DispatchAction
          3. {
          4. //將上傳文件保存到數(shù)據(jù)庫(kù)中
          5. public ActionForward upload(ActionMapping mapping, ActionForm form,
          6. HttpServletRequest request,
          7. HttpServletResponse response)
          8. {
          9. FileActionForm fileForm = (FileActionForm) form;
          10. FileService fileService = getFileService();
          11. fileService.save(fileForm);
          12. return mapping.findForward("loadAllFile");
          13. }
          14. //從Spring容器中獲取FileService對(duì)象
          15. private FileService getFileService()
          16. {
          17. ApplicationContext appContext = WebApplicationContextUtils.
          18. getWebApplicationContext(this.getServlet().getServletContext());
          19. return (FileService) appContext.getBean("fileService");
          20. }
          21. …
          22. }


            由于FileAction其它兩個(gè)請(qǐng)求處理方法也需要從Spring容器中獲取FileService實(shí)例,所以我們特別提供了一個(gè)getFileService()方法(第15~21行)。重構(gòu)的一條原則就是:"發(fā)現(xiàn)代碼中有重復(fù)的表達(dá)式,將其提取為一個(gè)變量;發(fā)現(xiàn)類中有重復(fù)的代碼段,將其提取為一個(gè)方法;發(fā)現(xiàn)不同類中有相同的方法,將其提取為一個(gè)類"。在真實(shí)的系統(tǒng)中,往往擁有多個(gè)Action和多個(gè)Service類,這時(shí)一個(gè)比較好的設(shè)置思路是,提供一個(gè)獲取所有Service實(shí)現(xiàn)對(duì)象的工具類,這樣就可以將Spring 的Service配置信息屏蔽在一個(gè)類中,否則Service的配置名字散落在程序各處,維護(hù)性是很差的。

            2.2 列出所有已經(jīng)上傳的文件

            listAllFile方法調(diào)用Servie層方法加載T_FILE表中所有記錄,并將其保存在Request域中,然后forward到列表頁面中:

          1. public class FileAction
          2. extends DispatchAction
          3. {
          4. …
          5. public ActionForward listAllFile(ActionMapping mapping, ActionForm form,
          6. HttpServletRequest request,
          7. HttpServletResponse response)
          8. throws ModuleException
          9. {
          10. FileService fileService = getFileService();
          11. List fileList = fileService.getAllFile();
          12. request.setAttribute("fileList",fileList);
          13. return mapping.findForward("fileListPage");
          14. }
          15. }


            file-list.jsp頁面使用Struts標(biāo)簽展示出保存在Request域中的記錄:

          1. <%@page contentType="text/html; charset=GBK"%>
          2. <%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
          3. <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
          4. <html>
          5. <head>
          6. <title>file-download</title>
          7. </head>
          8. <body bgcolor="#ffffff">
          9. <o(jì)l>
          10. <logic:iterate id="item" name="fileList" scope="request">
          11. <li>
          12. <a href='fileAction.do?method=download&fileId=
          13. <bean:write name="item"property="fileId"/>'>
          14. <bean:write name="item" property="fileName"/>
          15. </a>
          16. </li>
          17. </logic:iterate>
          18. </ol>
          19. </body>
          20. </html>


            展現(xiàn)頁面的每條記錄掛接著一個(gè)鏈接地址,形如:fileAction.do?method=download&fileId=xxx,method參數(shù)指定了這個(gè)請(qǐng)求由FileAction的download方法來響應(yīng),fileId指定了記錄的主鍵。

            由于在FileActionForm中,我們定義了fileId的屬性,所以在download響應(yīng)方法中,我們將可以從FileActionForm中取得fileId的值。這里涉及到一個(gè)處理多個(gè)請(qǐng)求Action所對(duì)應(yīng)的ActionForm的設(shè)計(jì)問題,由于原來的Action只能對(duì)應(yīng)一個(gè)請(qǐng)求,那么原來的ActionForm非常簡(jiǎn)單,它僅需要將這個(gè)請(qǐng)求的參數(shù)項(xiàng)作為其屬性就可以了,但現(xiàn)在一個(gè)Action對(duì)應(yīng)多個(gè)請(qǐng)求,每個(gè)請(qǐng)求所對(duì)應(yīng)的參數(shù)項(xiàng)是不一樣的,此時(shí)的ActionForm的屬性就必須是多請(qǐng)求參數(shù)項(xiàng)的并集了。所以,除了文件上傳請(qǐng)求所對(duì)應(yīng)的fileContent和remark屬性外還包括文件下載的fileId屬性:

          420){this.resized=true;this.style.width=420;}" border=0>
          圖 7 FileActionForm


            當(dāng)然這樣會(huì)造成屬性的冗余,比如在文件上傳的請(qǐng)求中,只會(huì)用到fileContent和remark屬性,而在文件下載的請(qǐng)求時(shí),只會(huì)使用到fileId屬性。但這種冗余是會(huì)帶來好處的--它使得一個(gè)Action可以處理多個(gè)請(qǐng)求。

            2.3 下載文件

            在列表頁面中點(diǎn)擊一個(gè)文件下載,其請(qǐng)求由FileAction的download方法來響應(yīng),download方法調(diào)用業(yè)務(wù)層的FileService方法,獲取文件數(shù)據(jù)并寫出到response的響應(yīng)流中。通過合理設(shè)置HTTP響應(yīng)頭參數(shù),將響應(yīng)流在客戶端表現(xiàn)為一個(gè)下載文件對(duì)話框,其代碼如下所示:

            代碼 10 業(yè)務(wù)接口實(shí)現(xiàn)類之download

          1. public class FileAction
          2. extends DispatchAction
          3. {
          4. …
          5. public ActionForward download(ActionMapping mapping, ActionForm form,
          6. HttpServletRequest request,
          7. HttpServletResponse response)
          8. throws ModuleException
          9. {
          10. FileActionForm fileForm = (FileActionForm) form;
          11. FileService fileService = getFileService();
          12. String fileName = fileService.getFileName(fileForm.getFileId());
          13. try
          14. {
          15. response.setContentType("application/x-msdownload");
          16. response.setHeader("Content-Disposition",
          17. "attachment;" + " filename="+
          18. new String(fileName.getBytes(), "ISO-8859-1"));
          19. fileService.write(response.getOutputStream(), fileForm.getFileId());
          20. }
          21. catch (Exception e)
          22. {
          23. throw new ModuleException(e.getMessage());
          24. }
          25. return null;
          26. }
          27. }


            第15~18行,設(shè)置HTTP響應(yīng)頭,將響應(yīng)類型設(shè)置為application/x-msdownload MIME類型,則響應(yīng)流在IE中將彈出一個(gè)文件下載的對(duì)話框,如圖 4所示。IE所支持的MIME類型多達(dá)26種,您可以通過這個(gè)網(wǎng)址查看其他的MIME類型:

          http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp

            如果下載文件的文件名含有中文字符,如果不對(duì)其進(jìn)行硬編碼,如第18行所示,客戶文件下載對(duì)話框中出現(xiàn)的文件名將會(huì)發(fā)生亂碼。
          第19行代碼獲得response的輸出流,作為FileServie write(OutputStream os,String fileId)的入?yún)ⅲ@樣文件的內(nèi)容將寫到response的輸出流中。

            3、web.xml文件的配置

            Spring容器在何時(shí)啟動(dòng)呢?我可以在Web容器初始化來執(zhí)行啟動(dòng)Spring容器的操作,Spring提供了兩種方式啟動(dòng)的方法:

            ·通過org.springframework.web.context .ContextLoaderListener容器監(jiān)聽器,在Web容器初始化時(shí)觸發(fā)初始化Spring容器,在web.xml中通過<listener></listener>對(duì)其進(jìn)行配置。

            ·通過Servlet org.springframework.web.context.ContextLoaderServlet,將其配置為自動(dòng)啟動(dòng)的Servlet,在Web容器初始化時(shí),通過這個(gè)Servlet啟動(dòng)Spring容器。

            在初始化Spring容器之前,必須先初始化log4J的引擎,Spring也提供了容器監(jiān)聽器和自動(dòng)啟動(dòng)Servlet兩種方式對(duì)log4J引擎進(jìn)行初始化:

            ·org.springframework.web.util .Log4jConfigListener

            ·org.springframework.web.util.Log4jConfigServlet

            下面我們來說明如何配置web.xml啟動(dòng)Spring容器:

            代碼 11 web.xml中對(duì)應(yīng)Spring的配置內(nèi)容

          1. <web-app>
          2. <context-param>
          3. <param-name>contextConfigLocation</param-name>
          4. <param-value>/WEB-INF/applicationContext.xml</param-value>
          5. </context-param>
          6. <context-param>
          7. <param-name>log4jConfigLocation</param-name>
          8. <param-value>/WEB-INF/log4j.properties</param-value>
          9. </context-param>
          10. <servlet>
          11. <servlet-name>log4jInitServlet</servlet-name>
          12. <servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
          13. <load-on-startup>1</load-on-startup>
          14. </servlet>
          15. <servlet>
          16. <servlet-name>springInitServlet</servlet-name>
          17. <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
          18. <load-on-startup>2</load-on-startup>
          19. </servlet>
          20. …
          21. </web-app>


            啟動(dòng)Spring容器時(shí),需要得到兩個(gè)信息:Spring配置文件的地址和Log4J屬性文件,這兩上信息分別通過contextConfigLocationWeb和log4jConfigLocation容器參數(shù)指定,如果有多個(gè)Spring配置文件,則用逗號(hào)隔開,如:

          /WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2

            由于在啟動(dòng)ContextLoaderServlet之前,必須事先初始化Log4J的引擎,所以Log4jConfigServlet必須在ContextLoaderServlet之前啟動(dòng),這通過<load-on-startup>來指定它們啟動(dòng)的先后順序。

            亂碼是開發(fā)Web應(yīng)用程序一個(gè)比較老套又常見問題,由于不同Web應(yīng)用服務(wù)器的默認(rèn)編碼是不一樣的,為了方便Web應(yīng)用在不同的Web應(yīng)用服務(wù)器上移植,最好的做法是Web程序自身來處理編碼轉(zhuǎn)換的工作。經(jīng)典的作法是在web.xml中配置一個(gè)編碼轉(zhuǎn)換過濾器,Spring就提供了一個(gè)編碼過濾器類CharacterEncodingFilter,下面,我們?yōu)閼?yīng)用配置上這個(gè)過濾器:

          1. <web-app>
          2. …
          3. <filter>
          4. <filter-name>encodingFilter</filter-name>
          5. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
          6. <init-param>
          7. <param-name>encoding</param-name>
          8. <param-value>GBK</param-value>
          9. </init-param>
          10. </filter>
          11. <filter-mapping>
          12. <filter-name>encodingFilter</filter-name>
          13. <url-pattern>/*</url-pattern>
          14. </filter-mapping>
          15. …
          16. </web-app>


            Spring的過濾器類是org.springframework.web.filter.CharacterEncodingFilter,通過encoding參數(shù)指定編碼轉(zhuǎn)換類型為GBK,<filter-mapping>的配置使該過濾器截獲所有的請(qǐng)示。

            Struts的框架也需要在web.xml中配置,想必讀者朋友對(duì)Struts的配置都很熟悉,故在此不再提及,請(qǐng)參見本文所提供的源碼。

            總結(jié)

            本文通過一個(gè)文件上傳下載的Web應(yīng)用,講解了如何構(gòu)建基于SSH的Web應(yīng)用,通過Struts和FormFile,Spring的LobHandler以及Spring為HibernateBlob處理所提供的用戶類BlobByteArrayType ,實(shí)現(xiàn)上傳和下載文件的功能僅需要廖廖數(shù)行的代碼即告完成。讀者只需對(duì)程序作稍許的調(diào)整,即可處理Clob字段:

            ·領(lǐng)域?qū)ο髮?duì)應(yīng)Clob字段的屬性聲明為String類型;

            ·映射文件對(duì)應(yīng)Clob字段的屬性聲明為org.springframework.orm.hibernate3.support.ClobStringType類型。

            本文通過SSH對(duì)文件上傳下載簡(jiǎn)捷完美的實(shí)現(xiàn)得以管中窺豹了解SSH強(qiáng)強(qiáng)聯(lián)合構(gòu)建Web應(yīng)用的強(qiáng)大優(yōu)勢(shì)。在行文中,還穿插了一些分層的設(shè)計(jì)經(jīng)驗(yàn),配置技巧和Spring所提供的方便類,相信這些知識(shí)對(duì)您的開發(fā)都有所裨益。

          作者:陳雄華出處:天極開發(fā)


          posted on 2008-04-10 15:03 阿偉 閱讀(370) 評(píng)論(0)  編輯  收藏 所屬分類: 框架整合
          主站蜘蛛池模板: 清流县| 九龙城区| 云阳县| 博兴县| 绥化市| 磐石市| 中牟县| 四子王旗| 博客| 喀喇沁旗| 达拉特旗| 普格县| 东方市| 冕宁县| 汝城县| 利辛县| 鄂伦春自治旗| 丰宁| 碌曲县| 大邑县| 忻州市| 开鲁县| 辽阳县| 武功县| 临沂市| 绥芬河市| 怀来县| 中方县| 昌江| 无锡市| 绵阳市| 满城县| 临清市| 会泽县| 通榆县| 吉林省| 白城市| 南京市| 宜都市| 宾阳县| 金塔县|