心的方向

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

          Struts+Spring+Hibernate實現上傳下載(三)

          轉自:http://lihaiyan.javaeye.com/blog/127796

          業務層

            1、業務層接口

            "面向接口而非面向類編程"是Spring不遺余力所推薦的編程原則,這條原則也已經為大部開發者所接受;此外,JDK的動態代理只對接口有效,否則必須使用CGLIB生成目標類的子類。我們依從于Spring的倡導為業務類定義一個接口:

            代碼 7 業務層操作接口

          1. public interface FileService
          2. {
          3. void save(FileActionForm fileForm);//將提交的上傳文件保存到數據表中
          4. List getAllFile();//得到T_FILE所示記錄
          5. void write(OutputStream os,String fileId);//將某個文件的文件數據寫出到輸出流中
          6. String getFileName(String fileId);//獲取文件名
          7. }

            其中save(FileActionForm fileForm)方法,將封裝在fileForm中的上傳文件保存到數據庫中,這里我們使用FileActionForm作為方法入參,FileActionForm是Web層的表單數據對象,它封裝了提交表單的數據。將FileActionForm直接作為業務層的接口入參,相當于將Web層傳播到業務層中去,即將業務層綁定在特定的Web層實現技術中,按照分層模型學院派的觀點,這是一種反模塊化的設計,但在"一般"的業務系統并無需提供多種UI界面,系統Web層將來切換到另一種實現技術的可能性也微乎其微,所以筆者覺得沒有必要為了這個業務層完全獨立于調用層的過高目標而去搞一個額外的隔離層,浪費了原材料不說,還將系統搞得過于復雜,相比于其它原則,"簡單"始終是最大的一條原則。

            getAllFile()負責獲取T_FILE表所有記錄,以便在網頁上顯示出來。

            而getFileName(String fileId)和write(OutputStream os,String fileId)則用于下載某個特定的文件。具體的調用是將Web層將response.getOutputStream()傳給write(OutputStream os,String fileId)接口,業務層直接將文件數據輸出到這個響應流中。具體實現請參見錯誤!未找到引用源。節下載文件部分。

            2、業務層接口實現類

            FileService的實現類為FileServiceImpl,其中save(FileActionForm fileForm)的實現如下所示:

            代碼 8 業務接口實現類之save()

          1. …
          2. public class FileServiceImpl
          3. implements FileService
          4. {
          5. private TfileDAO tfileDAO;
          6. public void save(FileActionForm fileForm)
          7. {
          8. Tfile tfile = new Tfile();
          9. try
          10. {
          11. tfile.setFileContent(fileForm.getFileContent().getFileData());
          12. }
          13. catch (FileNotFoundException ex)
          14. {
          15. throw new RuntimeException(ex);
          16. }
          17. catch (IOException ex)
          18. {
          19. throw new RuntimeException(ex);
          20. }
          21. tfile.setFileName(fileForm.getFileContent().getFileName());
          22. tfile.setRemark(fileForm.getRemark());
          23. tfileDAO.save(tfile);
          24. }
          25. …
          26. }

            在save(FileActionForm fileForm)方法里,完成兩個步驟:

            其一,象在水桶間倒水一樣,將FileActionForm對象中的數據倒入到Tfile對象中;

            其二,調用TfileDAO保存數據。

            需要特別注意的是代碼的第11行,FileActionForm的fileContent屬性為org.apache.struts.upload.FormFile類型,FormFile提供了一個方便的方法getFileData(),即可獲取文件的二進制數據。通過解讀FormFile接口實現類DiskFile的原碼,我們可能知道FormFile本身并不緩存文件的數據,只有實際調用getFileData()時,才從磁盤文件輸入流中獲取數據。由于FormFile使用流讀取方式獲取數據,本身沒有緩存文件的所有數據,所以對于上傳超大體積的文件,也是沒有問題的;但是,由于數據持久層的Tfile使用byte[]來緩存文件的數據,所以并不適合處理超大體積的文件(如100M),對于超大體積的文件,依然需要使用java.sql.Blob類型以常規流操作的方式來處理。

            此外,通過FileForm的getFileName()方法就可以獲得上傳文件的文件名,如第21行代碼所示。

            write(OutputStream os,String fileId)方法的實現,如代碼 9所示:

            代碼 9 業務接口實現類之write()

          1. …
          2. public class FileServiceImpl
          3. implements FileService
          4. {
          5.
          6. public void write(OutputStream os, String fileId)
          7. {
          8. Tfile tfile = tfileDAO.findByFildId(fileId);
          9. try
          10. {
          11. os.write(tfile.getFileContent());
          12. os.flush();
          13. }
          14. catch (IOException ex)
          15. {
          16. throw new RuntimeException(ex);
          17. }
          18. }
          19. …
          20. }

            write(OutputStream os,String fileId)也簡單地分為兩個操作步驟,首先,根據fileId加載表記錄,然后將fileContent寫入到輸出流中。

            3、Spring事務配置

            下面,我們來看如何在Spring配置文件中為FileService配置聲明性的事務

          1. <beans>
          2. …
          3. <bean id="transactionManager"
          4. class="org.springframework.orm.hibernate3.HibernateTransactionManager">
          5. <property name="sessionFactory" ref="sessionFactory"/>
          6. </bean>
          7. <!-- 事務處理的AOP配置 //-->
          8. <bean id="txProxyTemplate" abstract="true"
          9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
          10. <property name="transactionManager" ref="transactionManager"/>
          11. <property name="transactionAttributes">
          12. <props>
          13. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
          14. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
          15. <prop key="save">PROPAGATION_REQUIRED</prop>
          16. <prop key="write">PROPAGATION_REQUIRED,readOnly</prop>
          17. </props>
          18. </property>
          19. </bean>
          20. <bean id="fileService" parent="txProxyTemplate">
          21. <property name="target">
          22. <bean class="sshfile.service.FileServiceImpl">
          23. <property name="tfileDAO" ref="tfileDAO"/>
          24. </bean>
          25. </property>
          26. </bean>
          27. </beans>

            Spring的事務配置包括兩個部分:

            其一,定義事務管理器transactionManager,使用HibernateTransactionManager實現事務管理;

            其二,對各個業務接口進行定義,其實txProxyTemplate和fileService是父子節點的關系,本來可以將txProxyTemplate定義的內容合并到fileService中一起定義,由于我們的系統僅有一個業務接口需要定義,所以將其定義的一部分抽象到父節點txProxyTemplate中意義確實不大,但是對于真實的系統,往往擁有為數眾多的業務接口需要定義,將這些業務接口定義內容的共同部分抽取到一個父節點中,然后在子節點中通過parent進行關聯,就可以大大簡化業務接口的配置了。

            父節點txProxyTemplate注入了事務管理器,此外還定義了業務接口事務管理的方法(允許通過通配符的方式進行匹配聲明,如前兩個接口方法),有些接口方法僅對數據進行讀操作,而另一些接口方法需要涉及到數據的更改。對于前者,可以通過readOnly標識出來,這樣有利于操作性能的提高,需要注意的是由于父類節點定義的Bean僅是子節點配置信息的抽象,并不能具體實現化一個Bean對象,所以需要特別標注為abstract="true",如第8行所示。

            fileService作為一個目標類被注入到事務代理器中,而fileService實現類所需要的tfileDAO實例,通過引用3.2節中定義的tfileDAO Bean注入。


          posted on 2008-04-10 15:01 阿偉 閱讀(238) 評論(0)  編輯  收藏 所屬分類: 框架整合
          主站蜘蛛池模板: 湖州市| 裕民县| 格尔木市| 阳江市| 壤塘县| 海宁市| 镇巴县| 同江市| 新泰市| 肥西县| 香格里拉县| 临邑县| 吐鲁番市| 光山县| 新竹市| 泗水县| 汝城县| 南投市| 如东县| 陈巴尔虎旗| 吴川市| 武乡县| 梅州市| 庆元县| 东港市| 天津市| 伽师县| 阿瓦提县| 老河口市| 浠水县| 文安县| 武邑县| 双牌县| 灵台县| 资兴市| 大关县| 华容县| 古浪县| 宁安市| 南雄市| 巧家县|