Z?struts-config.xml 文g中配|?DelegatingRequestProcessor
Q你需要重?<controller> 元素?“processorClass” 属性?下面的几行应该放?<action-mapping> 元素的后面?<controller>
<set-property property="processorClass"
value="http://www.zhmy.com/org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>
增加q些讄之后Q不你查询Mcd?ActionQSping都自动在它的context配置文g中寻找?实际上,你甚至不需要指定类型。下面两个代码片断都可以工作Q?
<action path="/user" type="com.whatever.struts.UserAction"/>
<action path="/user"/>
如果你?Struts ?modules Ҏ,你的 bean 命名必须含有 module 的前~?举个例子Q如果一?Action 的定义ؓ Q而且它的 module 前缀?#8220;admin”Q?那么它应该对应名? ?bean
来源:http://deathmask1980.spaces.live.com/blog/cns!8633c46371110374!118.entry
Web层实?br />
1、Web层的构g和交互流E?br />
Web层包括主?个功能:
·上传文g?br />
·列出所有已l上传的文g列表Q以供点M载?br />
·下蝲文g?br />
Web层实现构件包括与2个JSP面Q?个ActionForm及一个ActionQ?br />
·file-upload.jspQ上传文件的面?br />
·file-list.jspQ已l上传文件的列表面?br />
·FileActionFormQfile-upload.jsp面表单对应的ActionForm?br />
·FileActionQ承org.apache.struts.actions.DispatchAction的ActionQ这栯个Action可以通过一个URL参数区分中响应不同的h?br />
Web层的q些构g的交互流E如?6所C:
![]() ?6 Web层Struts程?/span> |
其中Q在执行文g上传的请求时QFileAction在执行文件上传后Qforward到loadAllFile出口中,loadAllFile加蝲数据库中所有已l上传的记录Q然后forward到名为fileListPage的出口中Q调用file-list.jsp面昄已经上传的记录?br />
2、FileAction功能
Struts 1.0的Action有一个弱:一个Action只能处理一U请求,Struts 1.1中引入了一个DispatchActionQ允讔R过URL参数指定调用Action中的某个ҎQ如http://yourwebsite/fileAction.do?method=upload卌用FileAction中的uploadҎ。通过q种方式Q我们就可以一些相关的h集中C个Action当中~写Q而没有必要ؓ某个h操作~写一个ActioncR但是参数名是要在struts-config.xml中配|的Q?br />
1. Qstruts-configQ?br />
2. Qform-beansQ?br />
3. Qform-bean name="fileActionForm" type="sshfile.web.FileActionForm" /Q?br />
4. Q?form-beansQ?br />
5. Qaction-mappingsQ?br />
6. Qaction name="fileActionForm" parameter="method" path="/fileAction" 7. type="sshfile.web.FileAction"Q?br /> 8. Qforward name="fileListPage" path="/file-list.jsp" /Q?br /> 9. Qforward name="loadAllFile" path="/fileAction.do?method=listAllFile" /Q?br /> 10. Q?actionQ?br /> 11. Q?action-mappingsQ?br /> 12. Q?struts-configQ?/span> |
W?行的parameter="method"指定了承载方法名的参敎ͼW?行中Q我们还配置了一个调用FileAction不同Ҏ的Action出口?br />
FileAction共有3个请求响应的ҎQ它们分别是Q?br />
·upload(…)Q处理上传文件的h?br />
·listAllFile(…)Q处理加载数据库表中所有记录的h?br />
·downloadQ?#8230;Q:处理下蝲文g的请求?br />
下面我们分别对这3个请求处理方法进行讲解?br />
2.1 上传文g
上传文g的请求处理方法非常简单,之言之,是从Spring容器中获取业务层处理cFileServiceQ调用其save(FileActionForm form)Ҏ上传文gQ如下所C:
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其它两个h处理Ҏ也需要从Spring容器中获取FileService实例Q所以我们特别提供了一个getFileService()ҎQ第15~21行)。重构的一条原则就是:"发现代码中有重复的表辑ּQ将其提取ؓ一个变量;发现cM有重复的代码D,其提取Z个方法;发现不同cM有相同的ҎQ将其提取ؓ一个类"。在真实的系l中Q往往拥有多个Action和多个Servicec,q时一个比较好的设|思\是,提供一个获取所有Service实现对象的工LQ这样就可以Spring 的Service配置信息屏蔽在一个类中,否则Service的配|名字散落在E序各处Q维护性是很差的?br />
2.2 列出所有已l上传的文g
listAllFileҎ调用Servie层方法加载T_FILE表中所有记录,q将其保存在Request域中Q然后forward到列表页面中Q?br />
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标签展示Z存在Request域中的记录:
1. Q?@page contentType="text/html; charset=GBK"%Q?br />
2. Q?@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%Q?br />
3. Q?@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%Q?br />
4. QhtmlQ?br />
5. QheadQ?br />
6. QtitleQfile-downloadQ?titleQ?br />
7. Q?headQ?br />
8. Qbody bgcolor="#ffffff"Q?br />
9. QolQ?br />
10. Qlogic:iterate id="item" name="fileList" scope="request"Q?br />
11. QliQ?br />
12. Qa href='fileAction.do?method=download&fileId= 13. Qbean:write name="item"property="fileId"/Q?Q?br /> 14. Qbean:write name="item" property="fileName"/Q?br /> 15. Q?aQ?br /> 16. Q?liQ?br /> 17. Q?logic:iterateQ?br /> 18. Q?olQ?br /> 19. Q?bodyQ?br /> 20. Q?htmlQ?/span> |
展现面的每条记录挂接着一个链接地址QŞ如:fileAction.do?method=download&fileId=xxxQmethod参数指定了这个请求由FileAction的downloadҎ来响应,fileId指定了记录的主键?br />
׃在FileActionForm中,我们定义了fileId的属性,所以在download响应Ҏ中,我们可以从FileActionForm中取得fileId的倹{这里涉及到一个处理多个请求Action所对应的ActionForm的设计问题,׃原来的Action只能对应一个请求,那么原来的ActionForm非常单,它仅需要将q个h的参数项作ؓ其属性就可以了,但现在一个Action对应多个hQ每个请求所对应的参数项是不一LQ此时的ActionForm的属性就必须是多h参数的q了。所以,除了文g上传h所对应的fileContent和remark属性外q包括文件下载的fileId属性:
![]() ?7 FileActionForm |
当然q样会造成属性的冗余Q比如在文g上传的请求中Q只会用到fileContent和remark属性,而在文g下蝲的请求时Q只会用到fileId属性。但q种冗余是会带来好处?-它得一个Action可以处理多个h?br />
2.3 下蝲文g
在列表页面中点击一个文件下载,其请求由FileAction的downloadҎ来响应,downloadҎ调用业务层的FileServiceҎQ获取文件数据ƈ写出到response的响应流中。通过合理讄HTTP响应头参敎ͼ响应流在客L表现Z个下载文件对话框Q其代码如下所C:
代码 10 业务接口实现cMdownload
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. } |
W?5~18行,讄HTTP响应_响应类型设|ؓapplication/x-msdownload MIMEcdQ则响应在IE中将弹出一个文件下载的对话框,如图 4所C。IE所支持的MIMEcd多达26U,您可以通过q个|址查看其他的MIMEcdQ?br />
http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp?br />
如果下蝲文g的文件名含有中文字符Q如果不对其q行编码,如第18行所C,客户文g下蝲对话框中出现的文件名会发生q?br />
W?9行代码获得response的输出流Q作为FileServie write(OutputStream os,String fileId)的入参,q样文g的内容将写到response的输出流中?br />
3、web.xml文g的配|?br />
Spring容器在何时启动呢Q我可以在Web容器初始化来执行启动Spring容器的操作,Spring提供了两U方式启动的ҎQ?br />
·通过org.springframework.web.context .ContextLoaderListener容器监听器,在Web容器初始化时触发初始化Spring容器Q在web.xml中通过QlistenerQ</listenerQ对其进行配|?br />
·通过Servlet org.springframework.web.context.ContextLoaderServletQ将光|ؓ自动启动的ServletQ在Web容器初始化时Q通过q个Servlet启动Spring容器?br />
在初始化Spring容器之前Q必d初始化log4J的引擎,Spring也提供了容器监听器和自动启动Servlet两种方式对log4J引擎q行初始化:
·org.springframework.web.util .Log4jConfigListener
·org.springframework.web.util.Log4jConfigServlet
下面我们来说明如何配|web.xml启动Spring容器Q?br />
代码 11 web.xml中对应Spring的配|内?br />
1. Qweb-appQ?br />
2. Qcontext-paramQ?br />
3. Qparam-nameQcontextConfigLocationQ?param-nameQ?br />
4. Qparam-valueQ?WEB-INF/applicationContext.xmlQ?param-valueQ?br />
5. Q?context-paramQ?br />
6. Qcontext-paramQ?br />
7. Qparam-nameQlog4jConfigLocationQ?param-nameQ?br />
8. Qparam-valueQ?WEB-INF/log4j.propertiesQ?param-valueQ?br />
9. Q?context-paramQ?br />
10. QservletQ?br />
11. Qservlet-nameQlog4jInitServletQ?servlet-nameQ?br />
12. Qservlet-classQorg.springframework.web.util.Log4jConfigServletQ?servlet-classQ?br />
13. Qload-on-startupQ?Q?load-on-startupQ?br />
14. Q?servletQ?br />
15. QservletQ?br />
16. Qservlet-nameQspringInitServletQ?servlet-nameQ?br />
17. Qservlet-classQorg.springframework.web.context.ContextLoaderServletQ?servlet-classQ?br />
18. Qload-on-startupQ?Q?load-on-startupQ?br />
19. Q?servletQ?br />
20. … 21. Q?web-appQ?/span> |
启动Spring容器Ӟ需要得C个信息:Spring配置文g的地址和Log4J属性文Ӟq两上信息分别通过contextConfigLocationWeb和log4jConfigLocation容器参数指定Q如果有多个Spring配置文gQ则用逗号隔开Q如Q?br />
/WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2
׃在启动ContextLoaderServlet之前Q必M先初始化Log4J的引擎,所以Log4jConfigServlet必须在ContextLoaderServlet之前启动Q这通过Qload-on-startupQ来指定它们启动的先后顺序?br />
q是开发Web应用E序一个比较老套又常见问题,׃不同Web应用服务器的默认~码是不一LQؓ了方便Web应用在不同的Web应用服务器上ULQ最好的做法是WebE序自n来处理编码{换的工作。经典的作法是在web.xml中配|一个编码{换过滤器QSpring提供了一个编码过滤器cCharacterEncodingFilterQ下面,我们为应用配|上q个qo器:
1. Qweb-appQ?br />
2. … 3. QfilterQ?br /> 4. Qfilter-nameQencodingFilterQ?filter-nameQ?br /> 5. Qfilter-classQorg.springframework.web.filter.CharacterEncodingFilterQ?filter-classQ?br /> 6. Qinit-paramQ?br /> 7. Qparam-nameQencodingQ?param-nameQ?br /> 8. Qparam-valueQGBKQ?param-valueQ?br /> 9. Q?init-paramQ?br /> 10. Q?filterQ?br /> 11. Qfilter-mappingQ?br /> 12. Qfilter-nameQencodingFilterQ?filter-nameQ?br /> 13. Qurl-patternQ?*Q?url-patternQ?br /> 14. Q?filter-mappingQ?br /> 15. … 16. Q?web-appQ?/span> |
Spring的过滤器cLorg.springframework.web.filter.CharacterEncodingFilterQ通过encoding参数指定~码转换cd为GBKQ<filter-mappingQ的配置使该qo器截h有的L?br />
Struts的框架也需要在web.xml中配|,惛_读者朋友对Struts的配|都很熟悉,故在此不再提及,请参见本文所提供的源码?br />
ȝ
本文通过一个文件上传下载的Web应用Q讲解了如何构徏ZSSH的Web应用Q通过Struts和FormFileQSpring的LobHandler以及Spring为HibernateBlob处理所提供的用LBlobByteArrayType Q实C传和下蝲文g的功能仅需要廖廖数行的代码卛_完成。读者只需对程序作E许的调_卛_处理Clob字段Q?br />
·领域对象对应Clob字段的属性声明ؓStringcdQ?br />
·映射文g对应Clob字段的属性声明ؓorg.springframework.orm.hibernate3.support.ClobStringTypecd?br />
本文通过SSHҎ件上传下载简捷完的实现得以中Hv了解SSH强强联合构徏Web应用的强大优ѝ在行文中,q穿插了一些分层的设计l验Q配|技巧和Spring所提供的方便类Q相信这些知识对您的开发都有所裨益?/span>
作者:陈雄?/span>出处Q天极开?/span>
业务?br />
1、业务层接口
"面向接口而非面向cȝE?是Spring不遗余力所推荐的编E原则,q条原则也已lؓ大部开发者所接受Q此外,JDK的动态代理只Ҏ口有效,否则必须使用CGLIB生成目标cȝ子类。我们依从于Spring的倡导Z务类定义一个接口:
代码 7 业务层操作接?br />
1. public interface FileService
2. {
3. void save(FileActionForm fileForm);//提交的上传文g保存到数据表?br />
4. List getAllFile();//得到T_FILE所C?br />
5. void write(OutputStream os,String fileId);//某个文件的文g数据写出到输出流?br />
6. String getFileName(String fileId);//获取文g?br />
7. }
其中save(FileActionForm fileForm)ҎQ将装在fileForm中的上传文g保存到数据库中,q里我们使用FileActionForm作ؓҎ入参QFileActionForm是Web层的表单数据对象Q它装了提交表单的数据。将FileActionForm直接作ؓ业务层的接口入参Q相当于Web层传播到业务层中去,卛_业务层绑定在特定的Web层实现技术中Q按照分层模型学院派的观点,q是一U反模块化的设计Q但?一?的业务系lƈ无需提供多种UI界面Q系lWeb层将来切换到另一U实现技术的可能性也微乎其微Q所以笔者觉得没有必要ؓ了这个业务层完全独立于调用层的过高目标而去搞一个额外的隔离层,费了原材料不说Q还系l搞得过于复杂,相比于其它原则,"?始终是最大的一条原则?br />
getAllFile()负责获取T_FILE表所有记录,以便在网上昄出来?br />
而getFileName(String fileId)和write(OutputStream os,String fileId)则用于下载某个特定的文g。具体的调用是将Web层将response.getOutputStream()传给write(OutputStream os,String fileId)接口Q业务层直接文件数据输出到q个响应中。具体实现请参见错误Q未扑ֈ引用源。节下蝲文g部分?br />
2、业务层接口实现c?br />
FileService的实现类为FileServiceImplQ其中save(FileActionForm fileForm)的实现如下所C:
代码 8 业务接口实现cMsave()
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)Ҏ里,完成两个步骤Q?br />
其一Q象在水桉倒水一PFileActionForm对象中的数据倒入到Tfile对象中;
其二Q调用TfileDAO保存数据?br />
需要特别注意的是代码的W?1行,FileActionForm的fileContent属性ؓorg.apache.struts.upload.FormFilecdQFormFile提供了一个方便的ҎgetFileData()Q即可获取文件的二进制数据。通过解读FormFile接口实现cDiskFile的原码,我们可能知道FormFile本nq不~存文g的数据,只有实际调用getFileData()Ӟ才从盘文g输入中获取数据。由于FormFile使用读取方式获取数据,本n没有~存文g的所有数据,所以对于上传超大体U的文gQ也是没有问题的Q但是,׃数据持久层的Tfile使用byte[]来缓存文件的数据Q所以ƈ不适合处理大体积的文Ӟ?00MQ,对于大体积的文Ӟ依然需要用java.sql.Blobcd以常规流操作的方式来处理?br />
此外Q通过FileForm的getFileName()Ҏ可以获得上传文件的文g名,如第21行代码所C?br />
write(OutputStream os,String fileId)Ҏ的实玎ͼ如代?9所C:
代码 9 业务接口实现cMwrite()
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)也简单地分ؓ两个操作步骤Q首先,ҎfileId加蝲表记录,然后fileContent写入到输出流中?br />
3、Spring事务配置
下面Q我们来看如何在Spring配置文g中ؓFileService配置声明性的事务
1. QbeansQ?br />
2. …
3. Qbean id="transactionManager"
4. class="org.springframework.orm.hibernate3.HibernateTransactionManager"Q?br />
5. Qproperty name="sessionFactory" ref="sessionFactory"/Q?br />
6. Q?beanQ?br />
7. Q?-- 事务处理的AOP配置 //--Q?br />
8. Qbean id="txProxyTemplate" abstract="true"
9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"Q?br />
10. Qproperty name="transactionManager" ref="transactionManager"/Q?br />
11. Qproperty name="transactionAttributes"Q?br />
12. QpropsQ?br />
13. Qprop key="get*"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />
14. Qprop key="find*"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />
15. Qprop key="save"QPROPAGATION_REQUIREDQ?propQ?br />
16. Qprop key="write"QPROPAGATION_REQUIRED,readOnlyQ?propQ?br />
17. Q?propsQ?br />
18. Q?propertyQ?br />
19. Q?beanQ?br />
20. Qbean id="fileService" parent="txProxyTemplate"Q?br />
21. Qproperty name="target"Q?br />
22. Qbean class="sshfile.service.FileServiceImpl"Q?br />
23. Qproperty name="tfileDAO" ref="tfileDAO"/Q?br />
24. Q?beanQ?br />
25. Q?propertyQ?br />
26. Q?beanQ?br />
27. Q?beansQ?/span>
Spring的事务配|包括两个部分:
其一Q定义事务管理器transactionManagerQ用HibernateTransactionManager实现事务理Q?br />
其二Q对各个业务接口q行定义Q其实txProxyTemplate和fileService是父子节点的关系Q本来可以将txProxyTemplate定义的内容合q到fileService中一起定义,׃我们的系l仅有一个业务接口需要定义,所以将其定义的一部分抽象到父节点txProxyTemplate中意义确实不大,但是对于真实的系l,往往拥有为数众多的业务接口需要定义,这些业务接口定义内容的共同部分抽取C个父节点中,然后在子节点中通过parentq行兌Q就可以大大化业务接口的配置了?br />
父节点txProxyTemplate注入了事务管理器Q此外还定义了业务接口事务管理的ҎQ允讔R过通配W的方式q行匚w声明Q如前两个接口方法)Q有些接口方法仅Ҏ据进行读操作Q而另一些接口方法需要涉及到数据的更攏V对于前者,可以通过readOnly标识出来Q这h利于操作性能的提高,需要注意的是由于父c节点定义的Bean仅是子节炚w|信息的抽象Qƈ不能具体实现化一个Bean对象Q所以需要特别标注ؓabstract="true"Q如W?行所C?br />
fileService作ؓ一个目标类被注入到事务代理器中Q而fileService实现cL需要的tfileDAO实例Q通过引用3.2节中定义的tfileDAO Bean注入?/span>
数据持久?br />
1、领域对象及映射文g
您可以用Hibernate Middlegen、HIbernate Tools、Hibernate Syhchronizer{工h手工的方式,~写Hibernate的领域对象和映射文g。其中对应T_FILE表的领域对象Tfile.java为:
代码 1 领域对象Tfile
1. package sshfile.model;
2. public class Tfile
3.{
4. private String fileId;
5. private String fileName;
6. private byte[] fileContent;
7. private String remark;
8. …//getter and setter
9. }
特别需要注意的是:数据库表为Blobcd的字D在Tfile中的fileContentcd为byte[]。Tfile的Hibernate映射文gTfile.hbm.xml攑֜Tfile .javacL件的相同目录下:
代码 2 领域对象映射文g
1. Q?xml version="1.0"?Q?br />
2. Q?DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" Q?br />
5. Qhibernate-mappingQ?br />
6. Qclass name="sshfile.model.Tfile" table="T_FILE"Q?br />
7. Qid name="fileId" type="java.lang.String" column="FILE_ID"Q?br />
8. Qgenerator class="uuid.hex"/Q?br />
9. Q?idQ?br />
10. Qproperty name="fileContent"
11. type="org.springframework.orm.hibernate3.support.BlobByteArrayType"
12. column="FILE_CONTENT" lazy="true"/Q?br />
13. …//其它一般字D늚映射
14. Q?classQ?br />
15. Q?hibernate-mappingQ?/span>
fileContent字段映射为Spring所提供的BlobByteArrayTypecdQBlobByteArrayType是用戯定义的数据类型,它实CHibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取的Lob操作句柄lobHandlerbyte[]的数据保存到Blob数据库字D中。这P我们再没有必要通过编码的方式Q先insert然后再update来完成Blobcd数据的持久化Q这个原来难伺候的老爷l于被^民化了。关于lobHandler的配|请见本文后面的内容?br />
此外lazy="true"说明地返回整个Tfile对象Ӟq不q回fileContentq个字段的数据,只有在显式调用tfile.getFileContent()Ҏ时才真正从数据库中获取fileContent的数据。这是Hibernate3引入的新Ҏ,对于包含重量U大数据的表字段Q这U抽取方式提高了对大字段操作的灵zL,否则加蝲Tfile对象的结果集时如果Lq回fileContentQ这U批量的数据抽取可以引h据库?z泛效应"?br />
2、DAO~写和配|?br />
Spring面向接口~程Q所以我们将所有对Tfile的数据操作的Ҏ定义在TfileDAO接口中,q些接口Ҏ分别是:
·findByFildId(String fileId)
·save(Tfile tfile)
·List findAll()
TfileDAOHibernate提供了对TfileDAO接口ZHibernate的实玎ͼ如代?3所C:
代码 3 ZHibernate 的fileDAO实现c?br />
1. package sshfile.dao;
2.
3. import sshfile.model.*;
4. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
5. import java.util.List;
6.
7. public class TfileDAOHibernate
8. extends HibernateDaoSupport implements TfileDAO
9. {
10. public Tfile findByFildId(String fileId)
11. {
12. return (Tfile) getHibernateTemplate().get(Tfile.class, fileId);
13. }
14. public void save(Tfile tfile)
15. {
16. getHibernateTemplate().save(tfile);
17. getHibernateTemplate().flush();
18. }
19. public List findAll()
20. {
21. return getHibernateTemplate().loadAll(Tfile.class);
22. }
23. }
TfileDAOHibernate通过扩展Spring提供的Hibernate支持cHibernateDaoSupport而徏立,HibernateDaoSupport装了HibernateTemplateQ而HibernateTemplate装了Hibernate所提供几乎所有的的数据操作方法,如execute(HibernateCallback action)Qload(Class entityClass, Serializable id)Qsave(final Object entity){等?br />
所以我们的DAO只需要简单地调用父类的HibernateTemplate可以完成几乎所有的数据库操作了?br />
׃Spring通过代理Hibernate完成数据层的操作Q所以原Hibernate的配|文件hibernate.cfg.xml的信息也转移到Spring的配|文件中Q?br />
代码 4 Spring中有关Hibernate的配|信?br />
1. QbeansQ?br />
2. Q?-- 数据源的配置 //--Q?br />
3. Qbean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
4. destroy-method="close"Q?br />
5. Qproperty name="driverClassName" value="http://www.zhmy.com/oracle.jdbc.driver.OracleDriver"/Q?br />
6. Qproperty name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/Q?br />
7. Qproperty name="username" value="test"/Q?br />
8. Qproperty name="password" value="test"/Q?br />
9. Q?beanQ?br />
10. Q?-- Hibernate会话工厂配置 //--Q?br />
11. Qbean id="sessionFactory"
12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"Q?br />
13. Qproperty name="dataSource" ref="dataSource"/Q?br />
14. Qproperty name="mappingDirectoryLocations"Q?br />
15. QlistQ?br />
16. QvalueQclasspath:/sshfile/modelQ?valueQ?br />
17. Q?listQ?br />
18. Q?propertyQ?br />
19. Qproperty name="hibernateProperties"Q?br />
20. QpropsQ?br />
21. Qprop key="hibernate.dialect"Qorg.hibernate.dialect.OracleDialectQ?propQ?br />
22. Qprop key="hibernate.cglib.use_reflection_optimizer"QtrueQ?propQ?br />
23. Q?propsQ?br />
24. Q?propertyQ?br />
25. Q?beanQ?br />
26. Q?-- Hibernate 模板//--Q?br />
27. Qbean id="hibernateTemplate"
28. class="org.springframework.orm.hibernate3.HibernateTemplate"Q?br />
29. Qproperty name="sessionFactory" ref="sessionFactory"/Q?br />
30. Q?beanQ?br />
31. Q?--DAO配置 //--Q?br />
32. Qbean id="tfileDAO" class="sshfile.dao.TfileDAOHibernate"Q?br />
33. Qproperty name="hibernateTemplate" ref="hibernateTemplate" /Q?br />
34. Q?beanQ?br />
35. …
36. Q?beansQ?/span>
W?~9行定义了一个数据源Q其实现cLapache的BasicDataSourceQ第11~25行定义了Hibernate的会话工厂,会话工厂cȝSpring提供的LocalSessionFactoryBeanl护Q它注入了数据源和资源映文Ӟ此外q通过一些键值对讄了Hibernate所需的属性?br />
其中W?6行通过c\径的映射方式Q将sshfile.modelcd目录下的所有领域对象的映射文g装蝲q来Q在本文的例子里Q它装载进Tfile.hbm.xml映射文g。如果有多个映射文g需要声明,使用c\径映方式显然比直接单独指定映射文g名的方式要简ѝ?
W?7~30行定义了Spring代理Hibernate数据操作的HibernateTemplate模板Q而第32~34行将该模板注入到tfileDAO中?br />
需要指定的是Spring 1.2.5提供了两套Hibernate的支持包Q其中Hibernate 2相关的封装类位于org.springframework.orm.hibernate2.*包中Q而Hibernate 3.0的封装类位于org.springframework.orm.hibernate3.*包中Q需要根据您所选用Hibernate版本q行正确选择?br />
3、Lob字段处理的配|?br />
我们前面已经指出Oracle的Lob字段和一般类型的字段在操作上有一个明昄区别--那就是你必须首先通过Oracle的empty_blob()/empty_clob()初始化Lob字段Q然后获取该字段的引用,通过q个引用更改其倹{所以要完成对Lob字段的操作,Hibernate必须执行两步数据库访问操作,先Insert再Update?br />
使用BlobByteArrayType字段cd后,Z么我们就可以象一般的字段cd一h作Blob字段呢?可以定的一ҎQBlobByteArrayType不可能逾越Blob天生的操作方式,原来是BlobByteArrayType数据cd本n具体数据讉K的功能,它通过LobHandler两ơ数据访问的动作隐藏hQBlob字段的操作在表现上和其他一般字D业cd无异Q所以LobHandlerx那个"苦了我一个,q福十亿?的那位幕后英雄?br />
LobHandler必须注入到Hibernate会话工厂sessionFactory中,因ؓsessionFactory负责产生与数据库交互的Session。LobHandler的配|如代码 5所C:
代码 5 Lob字段的处理句柄配|?br />
1. QbeansQ?br />
2. …
3. Qbean id="nativeJdbcExtractor"
4. class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
5. lazy-init="true"/Q?br />
6. Qbean id="lobHandler"
7. class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true"Q?br />
8. Qproperty name="nativeJdbcExtractor"Q?br />
9. Qref local="nativeJdbcExtractor"/Q?br />
10. Q?propertyQ?br />
11. Q?beanQ?br />
12. …
13. Q?beansQ?/span>
首先Q必d义一个能够从q接池中抽取出本地数据库JDBC对象Q如OracleConnectionQOracleResultSet{)的抽取器QnativeJdbcExtractorQ这h可以执行一些特定数据库的操作。对于那些仅装了Connection而未包括Statement的简单数据连接池QSimpleNativeJdbcExtractor是效率最高的抽取器实现类Q但具体到apache的BasicDataSourceq接池,它封装了所有JDBC的对象,q时需要用CommonsDbcpNativeJdbcExtractor了。Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器:
·WebLogicQWebLogicNativeJdbcExtractor
·WebSphereQWebSphereNativeJdbcExtractor
·JBossQJBossNativeJdbcExtractor
在定义了JDBC抽取器后Q再定义lobHandler。Spring 1.2.5提供了两个lobHandlerQ?br />
·DefaultLobHandlerQ适用于大部分的数据库Q如SqlServerQMySQLQ对Oracle 10g也适用Q但不适用于Oracle 9iQ看来Oracle 9i实是个怪胎Q谁叫Oracle 公司自己都说Oracle 9i是一个过渡性的产品呢)?br />
·OracleLobHandlerQ适用于Oracle 9i和Oracle 10g?br />
׃我们的数据库是Oracle9iQ所以用OracleLobHandler?br />
在配|完LobHandler后, q需要将其注入到sessionFactory的Bean中,下面是调用后的sessionFactory Bean的配|:
代码 6 lobHandler注入到sessionFactory中的配置
1. QbeansQ?br />
2. …
3. Qbean id="sessionFactory"
4. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"Q?br />
5. Qproperty name="dataSource" ref="dataSource"/Q?br />
6. Q?-- 为处理Blobcd字段的句柄声?//--Q?br />
7. Qproperty name="lobHandler" ref="lobHandler"/Q?br />
8. …
9. Q?beanQ?br />
10. …
11. Q?beansQ?/span>
如第7所C,通过sessionFactory的lobHandler属性进行注入?/span>
![]() ?1 T_FILE表结?/span> |
![]() ?2 SSH处理文g上传技术方?/span> |
![]() ?3 文g上传面 |
![]() ?4 文g下蝲面 |
![]() ?5 工程资源l构 |