马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
在ruby里才是一切皆对象。当然我不并不是很了解ruby,但是ruby确实是将语法简化得很好。上传|下载 弁言
文件的上传和下载在J2EE编程已是一个十分陈旧的话题了,大概您即刻就可以掰着指头数出好几个出名的年夜件:如SmartUpload、Apache的FileUpload。但假如您的项目是构建在Struts+Spring+Hibernate(以下称SSH)框架上的,这些年夜件就显得粗笨而沧桑了,SSH供应了一个简便便利的文件上传下载的计划,我们只必要经由过程一些设置并辅以大批的代码就能够无缺办理这个成绩了。
本文将环绕SSH文件上传下载的主题,向您具体报告怎样开辟基于SSH的Web程序。SSH各框架的均为以后最新版本:
・Struts1.2
・Spring1.2.5
・Hibernate3.0
本文选用的数据库为Oracle9i,固然你能够在不修改代码的情形下,经由过程设置文件的调剂将其移植就任何具有Blob字段范例的数据库上,如MySQL,SQLServer等。
整体完成
上传文件保留到T_FILE表中,T_FILE表布局以下:
T_FILE表布局
个中:
・FILE_ID:文件ID,32个字符,用Hibernate的uuid.hex算法天生。
・FILE_NAME:文件名。
・FILE_CONTENT:文件内容,对应Oracle的Blob范例。
・REMARK:文件备注。
文件数据存储在Blob范例的FILE_CONTENT表字段上,在Spring中接纳OracleLobHandler来处置Lob字段(包含Clob和Blob),因为在程序中不必要援用到oracle数据驱动程序的详细类且屏障了分歧数据库处置Lob字段办法上的不同,从而撤消程序在多半据库移植上的樊篱。
1.起首数据表中的Blob字段在Java范畴对象中声明为byte[]范例,而非java.sql.Blob范例。
2.数据表Blob字段在Hibernate耐久化映照文件中的type为org.springframework.orm.hibernate3.support.BlobByteArrayType,即Spring所供应的用户自界说的范例,而非java.sql.Blob。
3.在Spring中利用org.springframework.jdbc.support.lob.OracleLobHandler处置Oracle数据库的Blob范例字段。
经由过程如许的设置和设置,我们就能够象耐久化表的一样平常字段范例一样处置Blob字段了。
以上是Spring+Hibernate将文件二进制数据耐久化到数据库的办理计划,而Struts经由过程将表单中file范例的组件映照为ActionForm中范例为org.apache.struts.upload.FormFile的属性来猎取表单提交的文件数据。
综上所述,我们能够经由过程,刻画出SSH处置文件上传的计划:
SSH处置文件上传手艺计划
文件上传的页面如所示:
文件上传页面
文件下载的页面如所示:
文件下载页面
该工程的资本布局如所示:
工程资本布局
工程的类按SSH的条理布局分别为数据耐久层、营业层和Web层;WEB-INF下的applicationContext.xml为Spring的设置文件,struts-config.xml为Struts的设置文件,file-upload.jsp为文件上传页面,file-list.jsp为文件列表页面。
本文前面的章节将从数据耐久层->营业层->Web层的开辟按次,逐层解说文件上传下载的开辟历程。
<P> 数据耐久层
1、范畴对象及映照文件
您可使用HibernateMiddlegen、HIbernateTools、HibernateSyhchronizer等工具或手工的体例,编写Hibernate的范畴对象和映照文件。个中对应T_FILE表的范畴对象Tfile.java为:
代码1范畴对象Tfile
1.packagesshfile.model;
2.publicclassTfile
3.{
4.privateStringfileId;
5.privateStringfileName;
6.privatebyte[]fileContent;
7.privateStringremark;
8.…//getterandsetter
9.}
出格必要注重的是:数据库表为Blob范例的字段在Tfile中的fileContent范例为byte[]。Tfile的Hibernate映照文件Tfile.hbm.xml放在Tfile.java类文件的不异目次下:
代码2范畴对象映照文件
1.<?xmlversion="1.0"?>
2.<!DOCTYPEhibernate-mappingPUBLIC
3."-//Hibernate/HibernateMappingDTD3.0//EN"
4."http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
5.<hibernate-mapping>
6.<classname="sshfile.model.Tfile"table="T_FILE">
7.<idname="fileId"type="java.lang.String"column="FILE_ID">
8.<generatorclass="uuid.hex"/>
9.</id>
10.<propertyname="fileContent"
11.type="org.springframework.orm.hibernate3.support.BlobByteArrayType"
12.column="FILE_CONTENT"lazy="true"/>
13.…//别的一样平常字段的映照
14.</class>
15.</hibernate-mapping>
fileContent字段映照为Spring所供应的BlobByteArrayType范例,BlobByteArrayType是用户自界说的数据范例,它完成了Hibernate的org.hibernate.usertype.UserType接口。BlobByteArrayType利用从sessionFactory猎取的Lob操纵句柄lobHandler将byte[]的数据保留到Blob数据库字段中。如许,我们就再没有需要经由过程硬编码的体例,先insert然后再update来完成Blob范例数据的耐久化,这个本来难奉养的老爷终究被布衣化了。关于lobHandler的设置请见本文前面的内容。
别的lazy="true"申明地前往全部Tfile对象时,其实不前往fileContent这个字段的数据,只要在显式挪用tfile.getFileContent()办法时才真正从数据库中猎取fileContent的数据。这是Hibernate3引进的新特征,关于包括分量级年夜数据的表字段,这类抽取体例进步了对年夜字段操纵的天真性,不然加载Tfile对象的了局集时假如老是前往fileContent,这类批量的数据抽取将能够引发数据库的"洪泛效应"。
2、DAO编写和设置
Spring夸大面向接口编程,以是我们将一切对Tfile的数据操纵的办法界说在TfileDAO接口中,这些接口办法分离是:
・findByFildId(StringfileId)
・save(Tfiletfile)
・ListfindAll()
TfileDAOHibernate供应了对TfileDAO接口基于Hibernate的完成,如代码3所示:
代码3基于Hibernate的fileDAO完成类
1.packagesshfile.dao;
2.
3.importsshfile.model.*;
4.importorg.springframework.orm.hibernate3.support.HibernateDaoSupport;
5.importjava.util.List;
6.
7.publicclassTfileDAOHibernate
8.extendsHibernateDaoSupportimplementsTfileDAO
9.{
10.publicTfilefindByFildId(StringfileId)
11.{
12.return(Tfile)getHibernateTemplate().get(Tfile.class,fileId);
13.}
14.publicvoidsave(Tfiletfile)
15.{
16.getHibernateTemplate().save(tfile);
17.getHibernateTemplate().flush();
18.}
19.publicListfindAll()
20.{
21.returngetHibernateTemplate().loadAll(Tfile.class);
22.}
23.}
TfileDAOHibernate经由过程扩大Spring供应的Hibernate撑持类HibernateDaoSupport而创建,HibernateDaoSupport封装了HibernateTemplate,而HibernateTemplate封装了Hibernate所供应几近一切的的数据操纵办法,如execute(HibernateCallbackaction),load(ClassentityClass,Serializableid),save(finalObjectentity)等等。
以是我们的DAO只必要复杂地挪用父类的HibernateTemplate就能够完成几近一切的数据库操纵了。
因为Spring经由过程代办署理Hibernate完成数据层的操纵,以是原Hibernate的设置文件hibernate.cfg.xml的信息也转移到Spring的设置文件中:
代码4Spring中有关Hibernate的设置信息
1.<beans>
2.<!--数据源的设置//-->
3.<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"
4.destroy-method="close">
5.<propertyname="driverClassName"value="oracle.jdbc.driver.OracleDriver"/>
6.<propertyname="url"value="jdbc:oracle:thin:@localhost:1521:ora9i"/>
7.<propertyname="username"value="test"/>
8.<propertyname="password"value="test"/>
9.</bean>
10.<!--Hibernate会话工场设置//-->
11.<beanid="sessionFactory"
12.class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
13.<propertyname="dataSource"ref="dataSource"/>
14.<propertyname="mappingDirectoryLocations">
15.<list>
16.<value>classpath:/sshfile/model</value>
17.</list>
18.</property>
19.<propertyname="hibernateProperties">
20.<props>
21.<propkey="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
22.<propkey="hibernate.cglib.use_reflection_optimizer">true</prop>
23.</props>
24.</property>
25.</bean>
26.<!--Hibernate模板//-->
27.<beanid="hibernateTemplate"
28.class="org.springframework.orm.hibernate3.HibernateTemplate">
29.<propertyname="sessionFactory"ref="sessionFactory"/>
30.</bean>
31.<!--DAO设置//-->
32.<beanid="tfileDAO"class="sshfile.dao.TfileDAOHibernate">
33.<propertyname="hibernateTemplate"ref="hibernateTemplate"/>
34.</bean>
35.…
36.</beans>
第3~9行界说了一个数据源,实在现类是apache的BasicDataSource,第11~25行界说了Hibernate的会话工场,会话工场类用Spring供应的LocalSessionFactoryBean保护,它注进了数据源和资本映照文件,别的还经由过程一些键值对设置了Hibernate所需的属性。
个中第16行经由过程类路径的映照体例,将sshfile.model类包目次下的一切范畴对象的映照文件装载出去,在本文的例子里,它将装载进Tfile.hbm.xml映照文件。假如有多个映照文件必要声明,利用类路径映照体例明显比间接独自指定映照文件名的体例要烦琐。
第27~30行界说了Spring代办署理Hibernate数据操纵的HibernateTemplate模板,而第32~34即将该模板注进到tfileDAO中。
必要指定的是Spring1.2.5供应了两套Hibernate的撑持包,个中Hibernate2相干的封装类位于org.springframework.orm.hibernate2.*包中,而Hibernate3.0的封装类位于org.springframework.orm.hibernate3.*包中,必要依据您所选用Hibernate版本举行准确选择。
3、Lob字段处置的设置
我们后面已指出Oracle的Lob字段和一样平常范例的字段在操纵上有一个分明的区分--那就是你必需起首经由过程Oracle的empty_blob()/empty_clob()初始化Lob字段,然后猎取该字段的援用,经由过程这个援用变动其值。以是要完成对Lob字段的操纵,Hibernate必需实行两步数据库会见操纵,先Insert再Update。
利用BlobByteArrayType字段范例后,为何我们就能够象一样平常的字段范例一样操纵Blob字段呢?能够断定的一点是:BlobByteArrayType不成能超越Blob生成的操纵体例,本来是BlobByteArrayType数据范例自己详细数据会见的功效,它经由过程LobHandler将两次数据会见的举措埋没起来,使Blob字段的操纵在体现上和其他一样平常字段业范例无异,以是LobHandler便是谁人"苦了我一个,幸运十亿人"的那位幕后好汉。
LobHandler必需注进到Hibernate会话工场sessionFactory中,由于sessionFactory卖力发生与数据库交互的Session。LobHandler的设置如代码5所示:
代码5Lob字段的处置句柄设置
1.<beans>
2.…
3.<beanid="nativeJdbcExtractor"
4.class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
5.lazy-init="true"/>
6.<beanid="lobHandler"
7.class="org.springframework.jdbc.support.lob.OracleLobHandler"lazy-init="true">
8.<propertyname="nativeJdbcExtractor">
9.<reflocal="nativeJdbcExtractor"/>
10.</property>
11.</bean>
12.…
13.</beans>
起首,必需界说一个可以从毗连池中抽掏出当地数据库JDBC对象(如OracleConnection,OracleResultSet等)的抽取器:nativeJdbcExtractor,如许才能够实行一些特定命据库的操纵。关于那些仅封装了Connection而未包含Statement的复杂数据毗连池,SimpleNativeJdbcExtractor是效力最高的抽取器完成类,但详细到apache的BasicDataSource毗连池,它封装了一切JDBC的对象,这时候就必要利用CommonsDbcpNativeJdbcExtractor了。Spring针对几个出名的Web服务器的数据源供应了响应的JDBC抽取器:
・WebLogic:WebLogicNativeJdbcExtractor
・WebSphere:WebSphereNativeJdbcExtractor
・JBoss:JBossNativeJdbcExtractor
在界说了JDBC抽取器后,再界说lobHandler。Spring1.2.5供应了两个lobHandler:
・DefaultLobHandler:合用于年夜部分的数据库,如SqlServer,MySQL,对Oracle10g也合用,但不合用于Oracle9i(看来Oracle9i的确是个怪胎,谁叫Oracle公司本人都说Oracle9i是一个过渡性的产物呢)。
・OracleLobHandler:合用于Oracle9i和Oracle10g。
因为我们的数据库是Oracle9i,以是利用OracleLobHandler。
在设置完LobHandler后,还必要将其注进到sessionFactory的Bean中,上面是挪用后的sessionFactoryBean的设置:
代码6将lobHandler注进到sessionFactory中的设置
1.<beans>
2.…
3.<beanid="sessionFactory"
4.class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
5.<propertyname="dataSource"ref="dataSource"/>
6.<!--为处置Blob范例字段的句柄声明//-->
7.<propertyname="lobHandler"ref="lobHandler"/>
8.…
9.</bean>
10.…
11.</beans>
如第7所示,经由过程sessionFactory的lobHandler属性举行注进。
<P> 营业层
1、营业层接口
"面向接口而非面向类编程"是Spring尽心尽力所保举的编程准绳,这条准绳也已为年夜部开辟者所承受;别的,JDK的静态代办署理只对接口无效,不然必需利用CGLIB天生方针类的子类。我们允从于Spring的倡议为营业类界说一个接口:
代码7营业层操纵接口
1.publicinterfaceFileService
2.{
3.voidsave(FileActionFormfileForm);//将提交的上传文件保留到数据表中
4.ListgetAllFile();//失掉T_FILE所示纪录
5.voidwrite(OutputStreamos,StringfileId);//将某个文件的文件数据写出到输入流中
6.StringgetFileName(StringfileId);//猎取文件名
7.}
个中save(FileActionFormfileForm)办法,将封装在fileForm中的上传文件保留到数据库中,这里我们利用FileActionForm作为办法进参,FileActionForm是Web层的表双数据对象,它封装了提交表单的数据。将FileActionForm间接作为营业层的接口进参,相称于将Web层传布到营业层中往,行将营业层绑定在特定的Web层完成手艺中,依照分层模子学院派的概念,这是一种反模块化的计划,但在"一样平常"的营业体系并没有需供应多种UI界面,体系Web层未来切换到另外一种完成手艺的大概性也微不足道,以是笔者以为没有需要为了这个营业层完整自力于挪用层的太高方针而往弄一个分外的断绝层,华侈了原质料不说,还将体系弄得过于庞大,比拟于别的准绳,"复杂"一直是最年夜的一条准绳。
getAllFile()卖力猎取T_FILE表一切纪录,以便在网页上显现出来。
而getFileName(StringfileId)和write(OutputStreamos,StringfileId)则用于下载某个特定的文件。详细的挪用是将Web层将response.getOutputStream()传给write(OutputStreamos,StringfileId)接口,营业层间接将文件数据输入到这个呼应流中。详细完成请拜见毛病!未找到援用源。节下载文件部分。
2、营业层接话柄现类
FileService的完成类为FileServiceImpl,个中save(FileActionFormfileForm)的完成以下所示:
代码8营业接话柄现类之save()
1.…
2.publicclassFileServiceImpl
3.implementsFileService
4.{
5.privateTfileDAOtfileDAO;
6.publicvoidsave(FileActionFormfileForm)
7.{
8.Tfiletfile=newTfile();
9.try
10.{
11.tfile.setFileContent(fileForm.getFileContent().getFileData());
12.}
13.catch(FileNotFoundExceptionex)
14.{
15.thrownewRuntimeException(ex);
16.}
17.catch(IOExceptionex)
18.{
19.thrownewRuntimeException(ex);
20.}
21.tfile.setFileName(fileForm.getFileContent().getFileName());
22.tfile.setRemark(fileForm.getRemark());
23.tfileDAO.save(tfile);
24.}
25.…
26.}
在save(FileActionFormfileForm)办法里,完成两个步骤:
其一,象在水桶间倒水一样,将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(OutputStreamos,StringfileId)办法的完成,如代码9所示:
代码9营业接话柄现类之write()
1.…
2.publicclassFileServiceImpl
3.implementsFileService
4.{
5.
6.publicvoidwrite(OutputStreamos,StringfileId)
7.{
8.Tfiletfile=tfileDAO.findByFildId(fileId);
9.try
10.{
11.os.write(tfile.getFileContent());
12.os.flush();
13.}
14.catch(IOExceptionex)
15.{
16.thrownewRuntimeException(ex);
17.}
18.}
19.…
20.}
write(OutputStreamos,StringfileId)也复杂地分为两个操纵步骤,起首,依据fileId加载表纪录,然后将fileContent写进到输入流中。
3、Spring事件设置
上面,我们来看怎样在Spring设置文件中为FileService设置声明性的事件
1.<beans>
2.…
3.<beanid="transactionManager"
4.class="org.springframework.orm.hibernate3.HibernateTransactionManager">
5.<propertyname="sessionFactory"ref="sessionFactory"/>
6.</bean>
7.<!--事件处置的AOP设置//-->
8.<beanid="txProxyTemplate"abstract="true"
9.class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
10.<propertyname="transactionManager"ref="transactionManager"/>
11.<propertyname="transactionAttributes">
12.<props>
13.<propkey="get*">PROPAGATION_REQUIRED,readOnly</prop>
14.<propkey="find*">PROPAGATION_REQUIRED,readOnly</prop>
15.<propkey="save">PROPAGATION_REQUIRED</prop>
16.<propkey="write">PROPAGATION_REQUIRED,readOnly</prop>
17.</props>
18.</property>
19.</bean>
20.<beanid="fileService"parent="txProxyTemplate">
21.<propertyname="target">
22.<beanclass="sshfile.service.FileServiceImpl">
23.<propertyname="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节中界说的tfileDAOBean注进。
<P> 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层的这些构件的交互流程如所示:
Web层Struts流程图
个中,在实行文件上传的哀求时,FileAction在实行文件上传后,forward到loadAllFile出口中,loadAllFile加载数据库中一切已上传的纪录,然后forward到名为fileListPage的出口中,挪用file-list.jsp页面显现已上传的纪录。
2、FileAction功效
Struts1.0的Action有一个弱项:一个Action只能处置一种哀求,Struts1.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-beanname="fileActionForm"type="sshfile.web.FileActionForm"/>
4.</form-beans>
5.<action-mappings>
6.<actionname="fileActionForm"parameter="method"path="/fileAction"
7.type="sshfile.web.FileAction">
8.<forwardname="fileListPage"path="/file-list.jsp"/>
9.<forwardname="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(FileActionFormform)办法上传文件,以下所示:
1.publicclassFileAction
2.extendsDispatchAction
3.{
4.//将上传文件保留到数据库中
5.publicActionForwardupload(ActionMappingmapping,ActionFormform,
6.HttpServletRequestrequest,
7.HttpServletResponseresponse)
8.{
9.FileActionFormfileForm=(FileActionForm)form;
10.FileServicefileService=getFileService();
11.fileService.save(fileForm);
12.returnmapping.findForward("loadAllFile");
13.}
14.//从Spring容器中猎取FileService对象
15.privateFileServicegetFileService()
16.{
17.ApplicationContextappContext=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.publicclassFileAction
2.extendsDispatchAction
3.{
4.…
5.publicActionForwardlistAllFile(ActionMappingmapping,ActionFormform,
6.HttpServletRequestrequest,
7.HttpServletResponseresponse)
8.throwsModuleException
9.{
10.FileServicefileService=getFileService();
11.ListfileList=fileService.getAllFile();
12.request.setAttribute("fileList",fileList);
13.returnmapping.findForward("fileListPage");
14.}
15.}
file-list.jsp页面利用Struts标签展现出保留在Request域中的纪录:
1.<%@pagecontentType="text/html;charset=GBK"%>
2.<%@tagliburi="/WEB-INF/struts-logic.tld"prefix="logic"%>
3.<%@tagliburi="/WEB-INF/struts-bean.tld"prefix="bean"%>
4.<html>
5.<head>
6.<title>file-download</title>
7.</head>
8.<bodybgcolor="#ffffff">
9.<ol>
10.<logic:iterateid="item"name="fileList"scope="request">
11.<li>
12.<ahref=fileAction.do?method=download&fileId=
13.<bean:writename="item"property="fileId"/>>
14.<bean:writename="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属性:
FileActionForm
固然如许会形成属性的冗余,好比在文件上传的哀求中,只会用到fileContent和remark属性,而在文件下载的哀求时,只会利用到fileId属性。但这类冗余是会带来优点的--它使得一个Action能够处置多个哀求。
2.3下载文件
在列表页面中点击一个文件下载,其哀求由FileAction的download办法来呼应,download办法挪用营业层的FileService办法,猎取文件数据并写出到response的呼应流中。经由过程公道设置HTTP呼应头参数,将呼应流在客户端体现为一个下载文件对话框,其代码以下所示:
代码10营业接话柄现类之download
1.publicclassFileAction
2.extendsDispatchAction
3.{
4.…
5.publicActionForwarddownload(ActionMappingmapping,ActionFormform,
6.HttpServletRequestrequest,
7.HttpServletResponseresponse)
8.throwsModuleException
9.{
10.FileActionFormfileForm=(FileActionForm)form;
11.FileServicefileService=getFileService();
12.StringfileName=fileService.getFileName(fileForm.getFileId());
13.try
14.{
15.response.setContentType("application/x-msdownload");
16.response.setHeader("Content-Disposition",
17."attachment;"+"filename="+
18.newString(fileName.getBytes(),"ISO-8859-1"));
19.fileService.write(response.getOutputStream(),fileForm.getFileId());
20.}
21.catch(Exceptione)
22.{
23.thrownewModuleException(e.getMessage());
24.}
25.returnnull;
26.}
27.}
第15~18行,设置HTTP呼应头,将呼应范例设置为application/x-msdownloadMIME范例,则呼应流在IE中将弹出一个文件下载的对话框,如所示。IE所撑持的MIME范例多达26种,您能够经由过程这个网址检察其他的MIME范例:
http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp。
假如下载文件的文件名含有中笔墨符,假如不合错误其举行硬编码,如第18行所示,客户文件下载对话框中呈现的文件名将会产生乱码。
第19行代码取得response的输入流,作为FileServiewrite(OutputStreamos,StringfileId)的进参,如许文件的内容将写到response的输入流中。
3、web.xml文件的设置
Spring容器在什么时候启动呢?我能够在Web容器初始化来实行启动Spring容器的操纵,Spring供应了两种体例启动的办法:
・经由过程org.springframework.web.context.ContextLoaderListener容器监听器,在Web容器初始化时触发初始化Spring容器,在web.xml中经由过程<listener></listener>对其举行设置。
・经由过程Servletorg.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容器:
代码11web.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所供应的便利类,信任这些常识对您的开辟都有所裨益。
主要缺点就是:速度比较慢,没有C和C++快 |