Struts+Spring+Hibernate上傳下載 --之四

來源:互聯網
上載者:User

Web層實現

  1、Web層的構件和互動流程

  Web層包括主要3個功能:

  ·上傳檔案。

  ·列出所有已經上傳的檔案清單,以供點擊下載。

  ·下載檔案。

  Web層實現構件包括與2個JSP頁面,1個ActionForm及一個Action:

  ·file-upload.jsp:上傳檔案的頁面。

  ·file-list.jsp:已經上傳檔案的列表頁面。

  ·FileActionForm:file-upload.jsp頁面表單對應的ActionForm。

  ·FileAction:繼承org.apache.struts.actions.DispatchAction的Action,這樣這個Action就可以通過一個URL參數區分中響應不同的請求。

  Web層的這些構件的互動流程 6所示


圖 6 Web層Struts流程圖

  其中,在執行檔案上傳的請求時,FileAction在執行檔案上傳後,forward到loadAllFile出口中,loadAllFile載入資料庫中所有已經上傳的記錄,然後forward到名為fileListPage的出口中,調用file-list.jsp頁面顯示已經上傳的記錄。
     2、FileAction功能

  Struts 1.0的Action有一個弱項:一個Action只能處理一種請求,Struts 1.1中引入了一個DispatchAction,允許通過URL參數指定調用Action中的某個方法,如http://yourwebsite/fileAction.do?method=upload即調用FileAction中的upload方法。通過這種方式,我們就可以將一些相關的請求集中到一個Action當中編寫,而沒有必要為某個請求操作編寫一個Action類。但是參數名是要在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"指定了承載方法名的參數,第9行中,我們還配置了一個調用FileAction不同方法的Action出口。

  FileAction共有3個請求響應的方法,它們分別是:

  ·upload(…):處理上傳檔案的請求。

  ·listAllFile(…):處理載入資料庫表中所有記錄的請求。

  ·download(…):處理下載檔案的請求。

  下面我們分別對這3個請求處理方法進行講解。

  2.1 上傳檔案

  上傳檔案的請求處理方法非常簡單,簡之言之,就是從Spring容器中擷取業務層處理類FileService,調用其save(FileActionForm form)方法上傳檔案,如下所示:

1. public class FileAction
2. extends DispatchAction
3. {
4. //將上傳檔案儲存到資料庫中
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對象
15. private FileService getFileService()
16. {
17. ApplicationContext appContext = WebApplicationContextUtils.
18. getWebApplicationContext(this.getServlet().getServletContext());
19. return (FileService) appContext.getBean("fileService");
20. }
21. …
22. }

  由於FileAction其它兩個請求處理方法也需要從Spring容器中擷取FileService執行個體,所以我們特別提供了一個getFileService()方法(第15~21行)。重構的一條原則就是:"發現代碼中有重複的運算式,將其提取為一個變數;發現類中有重複的程式碼片段,將其提取為一個方法;發現不同類中有相同的方法,將其提取為一個類"。在真實的系統中,往往擁有多個Action和多個Service類,這時一個比較好的設定思路是,提供一個擷取所有Service實現對象的工具類,這樣就可以將Spring 的Service配置資訊屏蔽在一個類中,否則Service的配置名字散落在程式各處,維護性是很差的。

  2.2 列出所有已經上傳的檔案

  listAllFile方法調用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標籤展示出儲存在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. <ol>
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>

  展現頁面的每條記錄掛接著一個連結地址,形如:fileAction.do?method=download&fileId=xxx,method參數指定了這個請求由FileAction的download方法來響應,fileId指定了記錄的主鍵。

  由於在FileActionForm中,我們定義了fileId的屬性,所以在download回應程式法中,我們將可以從FileActionForm中取得fileId的值。這裡涉及到一個處理多個請求Action所對應的ActionForm的設計問題,由於原來的Action只能對應一個請求,那麼原來的ActionForm非常簡單,它僅需要將這個請求的參數項作為其屬性就可以了,但現在一個Action對應多個請求,每個請求所對應的參數項是不一樣的,此時的ActionForm的屬性就必須是多請求參數項的並集了。所以,除了檔案上傳請求所對應的fileContent和remark屬性外還包括檔案下載的fileId屬性:


圖 7 FileActionForm

  當然這樣會造成屬性的冗餘,比如在檔案上傳的請求中,只會用到fileContent和remark屬性,而在檔案下載的請求時,只會使用到fileId屬性。但這種冗餘是會帶來好處的--它使得一個Action可以處理多個請求。

  2.3 下載檔案

  在列表頁面中點擊一個檔案下載,其請求由FileAction的download方法來響應,download方法調用業務層的FileService方法,擷取檔案資料並寫出到response的響應流中。通過合理設定HTTP回應標頭參數,將響應流在用戶端表現為一個下載檔案對話方塊,其代碼如下所示:

  代碼 10 業務介面實作類別之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行,設定HTTP回應標頭,將響應類型設定為application/x-msdownload MIME類型,則響應流在IE中將彈出一個檔案下載的對話方塊, 4所示。IE所支援的MIME類型多達26種,您可以通過這個網址查看其他的MIME類型:

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

  如果下載檔案的檔案名稱含有中文字元,如果不對其進行寫入程式碼,如第18行所示,客戶檔案下載對話方塊中出現的檔案名稱將會發生亂碼。
第19行代碼獲得response的輸出資料流,作為FileServie write(OutputStream os,String fileId)的入參,這樣檔案的內容將寫到response的輸出資料流中。

  3、web.xml檔案的配置

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

  ·通過org.springframework.web.context .ContextLoaderListener容器監聽器,在Web容器初始化時觸發初始化Spring容器,在web.xml中通過<listener></listener>對其進行配置。

  ·通過Servlet org.springframework.web.context.ContextLoaderServlet,將其配置為自動啟動的Servlet,在Web容器初始化時,通過這個Servlet啟動Spring容器。

  在初始化Spring容器之前,必須先初始化log4J的引擎,Spring也提供了容器監聽器和自動啟動Servlet兩種方式對log4J引擎進行初始化:

  ·org.springframework.web.util .Log4jConfigListener

  ·org.springframework.web.util.Log4jConfigServlet

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

  代碼 11 web.xml中對應Spring的配置內容

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>

  啟動Spring容器時,需要得到兩個資訊:Spring設定檔的地址和Log4J屬性檔案,這兩上資訊分別通過contextConfigLocationWeb和log4jConfigLocation容器參數指定,如果有多個Spring設定檔,則用逗號隔開,如:

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

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

  亂碼是開發Web應用程式一個比較老套又常見問題,由於不同Web應用伺服器的預設編碼是不一樣的,為了方便Web應用在不同的Web應用伺服器上移植,最好的做法是Web程式自身來處理編碼轉換的工作。經典的作法是在web.xml中配置一個編碼轉換過濾器,Spring就提供了一個編碼過濾器類CharacterEncodingFilter,下面,我們為應用配置上這個過濾器:

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參數指定編碼轉換類型為GBK,<filter-mapping>的配置使該過濾器截獲所有的請示。

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

  總結

  本文通過一個檔案上傳下載的Web應用,講解了如何構建基於SSH的Web應用,通過Struts和FormFile,Spring的LobHandler以及Spring為HibernateBlob處理所提供的使用者類BlobByteArrayType ,實現上傳和下載檔案的功能僅需要廖廖數行的代碼即告完成。讀者只需對程式作稍許的調整,即可處理Clob欄位:

  ·領域對象對應Clob欄位的屬性聲明為String類型;

  ·對應檔對應Clob欄位的屬性聲明為org.springframework.orm.hibernate3.support.ClobStringType類型。

  本文通過SSH對檔案上傳下載簡捷完美的實現得以管中窺豹瞭解SSH強強聯合構建Web應用的強大優勢。在行文中,還穿插了一些分層的設計經驗,配置技巧和Spring所提供的方便類,相信這些知識對您的開發都有所裨益。

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.