版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
StrutsSpringHibernate实现上传下载2005年12月21日10:06天极yesky引言文件的上传和下载在J2EE编程已经是一个非常古老的话题了,也许您马上就能掰着指头数出好几个著名的大件:如SmartUpload、Apache的FileUpload。但如果您的项目是构建在Struts+Spring+Hibernate(以下称SSH框架上的,这些大件就显得笨重而沧桑了,SSH提供了一个简捷方便的文件上传下载的方案,我们只需要通过一些配置并辅以少量的代码就可以完好解决这个问题了。本文将围绕SSH文件上传下载的主题,向您详细讲述如何开发基于SSH的Web程序。SSH各框架的均为当前最新版本:•Struts1.2-Spring1.2.5-Hibernate3.0本文选用的数据库为Oracle9i,当然你可以在不改动代码的情况下,通过配置文件的调整将其移植到任何具有Blob字段类型的数据库上,如MySQLSQLServer等。总体实现上传文件保存到T_FILE表中,T_FILE表结构如下:T_FIL£FILEJDCHARC32?印注FILE.NAMEVARGrl內FILE_CjriTENT曰2目REh4AR^丿出总匚图1T_FILE表结构其中:综上所述,我们可以通过图综上所述,我们可以通过图2,描绘出SSH处理文件上传的方案:综上所述,我们可以通过图综上所述,我们可以通过图2,描绘出SSH处理文件上传的方案:•FILE_ID:文件ID,32个字符,用Hibernate的uuid.hex算法生成。FILE_NAME文件名。FILE_CONTENT文件内容,对应Oracle的Blob类型。REMARK文件备注。文件数据存储在Blob类型的FILE_CONTEN■表字段上,在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的属性来获取表单提交的文件数据。图2SSH处理文件上传技术方案文件上传的页面如图3所示:图3文件上传页面文件下载的页面如图4所示:图4文件下载页面该工程的资源结构如图5所示:^EEESSR园1+1jec+Soiirce^Q®sSh£ile_dio\.{-^TfileM.jiI:*11「-越TfilePAOMibjmaSIfilfi.hbm,xmlI轸霽訶鬲Ep-二二二二二二二二二:J严-越F订eService.jara.i—fij1i1eServiceimnlhart.S»檔曲高.;r'_S^.FileAction.javiXeActjoriFonn.j_ava_白EemModjilT^g4DeploymantdieEcriptorE百Midduladirectory51WEP-INF1由卑cl蛟心;d蚩i让applicationConteKt.Minihr^^Tnikmin]fetruts-config.j(i»L圍ztrut£-htil.tldstruts-lo^ic.tld""F^web.xml-二#fii^Ac*icn回」瑩■(g£i1e-uploal.jeja£•Nil持久层服务层声P门隔配置
文件Struts配置文
件图5工程资源结构工程的类按SSH的层次结构划分为数据持久层、业务层和Web层;WEB-INF下的applicationContext.xml为Spring的配置文件,struts-config.xml为Struts的配置文件,file-upload.jsp为文件上传页面,file-list.jsp为文件列表页面。本文后面的章节将从数据持久层->业务层->Web层的开发顺序,逐层讲解文件上传下载的开发过程。数据持久层1、领域对象及映射文件您可以使用HibernateMiddlegen、HibernateTools、HibernateSyhchronizer等工具或手工的方式,编写Hibernate的领域对象和映射文件。其中对应T_FILE表的领域对象Tfile.java为:代码1领域对象Tfile特别需要注意的是:数据库表为Blob类型的字段在Tfile中的fileContent类型为byte[]。Tfile的Hibernate映射文件Tfile.hbm.xml放在Tfile.java类文件的相同目录下:代码2领域对象映射文件<?xmlversion="1.0"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"TOC\o"1-5"\h\z"/hibernate-mapping-3.0.dtd"><hibernate-mapping><classname="sshfile.model.Tfile"table="T_FILE"><idname="fileld"type="java.lang.String"column="FILE」D"><generatorclass="uuid.hex"/></id><propertyname="fileContent"type="org.springframework.orm.hibernate3.support.BlobByteArrayType"column="FILE_CONTENT"lazy="true"/>…〃其它一般字段的映射</class></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接口中,这些接口方法分别是:•findByFildld(StringfileId)save(Tfiletfile)ListfindAll()TfileDAOHibernate提供了对TfileDAO接口基于Hibernate的实现,如代码3所示:代码3基于Hibernate的fileDAO实现类packagesshfile.dao;2.importsshfile.model.*;importorg.springframework.orm.hibernate3.support.HibernateDaoSupport;importjava.util.List;6.publicclassTfileDAOHibernateextendsHibernateDaoSupportimplementsTfileDAO{publicTfilefindByFildld(Stringfileld)TOC\o"1-5"\h\z{return(Tfile)getHibernateTemplate().get(Tfile.class,fileId);}publicvoidsave(Tfiletfile){getHibernateTemplate().save(tfile);getHibernateTemplate().flush();}publicListfindAll(){returngetHibernateTemplate().loadAII(Tfile.class);}}TfileDAOHibernate通过扩展Spring提供的Hibernate支持类HibernateDaoSupport而建立,HibernateDaoSupport封装了HibernateTemplate,而HibernateTemplate封装了Hibernate所提供几乎所有的的数据操作方法,如execute(HibernateCallbackaction),load(ClassentityClass,Serializableid),save(finalObjectentity)等等。所以我们的DAOR需要简单地调用父类的HibernateTemplate就可以完成几乎所有的数据库操作了。由于Spring通过代理Hibernate完成数据层的操作,所以原Hibernate的配置文件hibernate.cfg.xml的信息也转移到Spring的配置文件中:代码4Spring中有关Hibernate的配置信息<beans>TOC\o"1-5"\h\z<!--数据源的配置//--><beanid="dataSource"class="mons.dbcp.BasicDataSource"destroy-method="close"><propertyname="driverClassName"value="oracle.jdbc.driver.OracleDriver'7><propertyname="url"value="jdbc:oracle:thin:@localhost:1521:ora9i"/><propertyname="username"value="test"/><propertyname="password"value="test"/></bean><!--Hibernate会话工厂配置//--><beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"<propertyname="dataSource"ref="dataSource"/><propertyname="mappingDirectoryLocations"><list><value>classpath:/sshfile/model</value></list></property><propertyname="hibernateProperties"><props><propkey="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop><propkey="hibernate.cglib.use_reflection_optimizer">true</prop></props></property></bean><!--Hibernate模板//--><beanid="hibernateTemplate"TOC\o"1-5"\h\zclass="org.springframework.orm.hibernate3.HibernateTemplate"><propertyname="sessionFactory"ref="sessionFactory"/></bean><!--DAO配置//--><beanid="tfileDAO"class="sshfile.dao.TfileDAOHibernate"><propertyname="hibernateTemplate"ref="hibernateTemplate"/></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必须注入至UHibernate会话工厂sessionFactory中,因为sessionFactory负责产生与数据库交互的Session。LobHandler的配置如代码5所示:代码5Lob字段的处理句柄配置<beans>TOC\o"1-5"\h\z…<beanid="nativeJdbcExtractor"4.class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"lazy-init="true"/><beanid="lobHandler"class="org.springframework.jdbc.support.lob.OracleLobHandler"lazy-init="true"><propertyname="nativeJdbcExtractor"><reflocal="nativeJdbcExtractor"/></property></bean>…</beans>首先,必须定义一个能够从连接池中抽取出本地数据库JDBC对象首先,必须定义一个能够从连接池中抽取出本地数据库JDBC对象(如OracleConnection,OracleResultSet等)的抽取器:nativeJdbcExtractor,这样才可以执行一些特定数据库的操作。对于那些仅圭寸装了Connection而未包括Statement的简单数据连接池,SimpleNativeJdbcExtractor是效率最高的抽取器实现类,但具体到apache的BasicDataSource连接池,它封装了所有JDBC的对象,这时就需要使用CommonsDbcpNativeJdbcExtractor了。Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器:WebLogic:WebLogicNativeJdbcExtractorWebSphereWebSphereNativeJdbcExtractorJBoss:JBossNativeJdbcExtractor在定义了JDBC抽取器后,再定义lobHandler。Spring1.2.5提供了两个lobHandler:DefaultLobHandler:适用于大部分的数据库,如SqlServer,MySQL对Oracle10g也适用,但不适用于Oracle9i(看来Oracle9i确实是个怪胎,谁叫Oracle公司自己都说Oracle9i是一个过渡性的产品呢)。OracleLobHandler:适用于Oracle9i和Oracle10g。由于我们的数据库是Oracle9i,所以使用OracleLobHandler。在配置完LobHandler后,还需要将其注入到在配置完LobHandler后,还需要将其注入到sessionFactory的Bean中,下面是调用后的sessionFactoryBean的配置:中的配置代码6将lobHandler注入到sessionFactory中的配置<beans>TOC\o"1-5"\h\z…<beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><propertyname="dataSource"ref="dataSource"/><!--为处理Blob类型字段的句柄声明//--><propertyname="lobHandler"ref="lobHandler"/>…</bean>…</beans>如第7所示,通过sessionFactory的lobHandler属性进行注入。业务层1、业务层接口"面向接口而非面向类编程”是Spring不遗余力所推荐的编程原则,这条原则也已经为大部开发者所接受;此外,JDK的动态代理只对接口有效,否则必须使用CGLIB生成目标类的子类。我们依从于Spring的倡导为业务类定义一个接口:代码7业务层操作接口publicinterfaceFileService{voidsave(FileActionFormfileForm);//将提交的上传文件保存到数据表中ListgetAIIFile();〃得到T_FILE所示记录voidwrite(OutputStreamos,StringfileId);//将某个文件的文件数据写出到输出流中StringgetFileName(StringfileId);//获取文件名}其中save(FileActionFormfileForm)方法,将圭寸装在fileForm中的上传文件保存到数据库中,这里我们使用FileActionForm作为方法入参,FileActionForm是Web层的表单数据对象,它封装了提交表单的数据。将FileActionForm直接作为业务层的接口入参,相当于将Web层传播到业务层中去,即将业务层绑定在特定的Web层实现技术中,按照分层模型学院派的观点,这是一种反模块化的设计,但在"一般”的业务系统并无需提供多种UI界面,系统Web层将来切换到另一种实现技术的可能性也微乎其微,所以笔者觉得没有必要为了这个业务层完全独立于调用层的过高目标而去搞一个额外的隔离层,浪费了原材料不说,还将系统搞得过于复杂,相比于其它原则,”简单"始终是最大的一条原则。getAIIFile()负责获取T_FILE表所有记录,以便在网页上显示出来。
而getFileName(Stringfileld)和而getFileName(Stringfileld)和write(OutputStreamos,Stringfileld)载某个特定的文件。具体的调用是将Web层将response.getOutputStream()传给write(OutputStreamos,StringfileId)接口,业务层直接将文件数据输出到这个响应流中。具体实现请参见错误!未找到引用源。节下载文件部分。2、业务层接口实现类FileService的实现类为FileServicelmpI,其中save(FileActionFormfileForm)的实现如下所示:代码8业务接口实现类之save()…publicclassFileServiceImplimplementsFileServiceTOC\o"1-5"\h\z{privateTfileDAOtfileDAO;publicvoidsave(FileActionFormfileForm){Tfiletfile=newTfile();try{tfile.setFileContent(fileForm.getFileContent().getFileData());}catch(FileNotFoundExceptionex){thrownewRuntimeException(ex);}catch(IOExceptionex){thrownewRuntimeException(ex);}tfile.setFileName(fileForm.getFileContent().getFileName());tfile.setRemark(fileForm.getRemark());tfileDAO.save(tfile);}…}在在save(FileActionFormfileForm)方法里,完成两个步骤:在在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)方法的实现,如代码write(OutputStreamos,StringfileId)方法的实现,如代码9所示:代码9业务接口实现类之write()…publicclassFileServiceImplimplementsFileServiceTOC\o"1-5"\h\z{5.publicvoidwrite(OutputStreamos,StringfileId){Tfiletfile=tfileDAO.findByFildld(fileld);try{os.write(tfile.getFileContent());os.flush();}catch(IOExceptionex)27.<27.</beans>-file-upload.jsp-file-upload.jsp:上传文件的页面。{thrownewRuntimeException(ex);}}-}write(OutputStreamos,StringfileId)也简单地分为两个操作步骤,首先,根据write(OutputStreamos,StringfileId)也简单地分为两个操作步骤,首先,根据27.<27.</beans>-file-upload.jsp-file-upload.jsp:上传文件的页面。27.<27.</beans>-file-upload.jsp-file-upload.jsp:上传文件的页面。fileId加载表记录,然后将fileContent写入到输出流中。3、Spring事务配置F面,我们来看如何在Spring配置文件中为FileService配置声明性的事务<beans>-<beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"5.<propertyname="sessionFactory"ref="sessionFactory"/5.6.</bean>7.<!--事务处理的AOP配置//-->8.<beanid="txProxyTemplate"abstract="true"9.class="erceptor.TransactionProxyFactoryBean"10.<propertyname="transactionManager"ref="transactionManager'711.<propertyname="transactionAttributes"12.<props>13.<propkey="get*"14.<propkey="find*">PROPAGATION_REQUIRED,readO<yprop>>PROPAGATION_REQUIRED,readO<yprop>15.<propkey="save">PROPAGATION_REQUIREDrop>6.</bean>7.<!--事务处理的AOP配置//-->8.<beanid="txProxyTemplate"abstract="true"9.class="erceptor.TransactionProxyFactoryBean"10.<propertyname="transactionManager"ref="transactionManager'711.<propertyname="transactionAttributes"12.<props>13.<propkey="get*"14.<propkey="find*">PROPAGATION_REQUIRED,readO<yprop>>PROPAGATION_REQUIRED,readO<yprop>15.<propkey="save">PROPAGATION_REQUIREDrop>16.<propkey="write">PROPAGATION_REQUIRED,readO<yprop>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>Spring的事务配置包括两个部分:其一,定义事务管理器transactionManager,使用HibernateTransactionManager实现事务管理;其二,对各个业务接口进行定义,其实txProxyTemplate和fileService是父子节点的关系,本来可以将txProxyTemplate定义的内容合并到fileService中一起定义,由于我们的系统仅有一个业务接口需要定义,所以将其定义的一部分抽象到父节点txProxyTemplate中意义确实不大,但是对于真实的系统,往往拥有为数众多的业务接口需要定义,将这些业务接口定义内容的共同部分抽取到一个父节点中,然后在子节点中通过parent进行关联,就可以大大简化业务接口的配置了。父节点txProxyTemplate注入了事务管理器,此外还定义了业务接口事务管理的方法(允许通过通配符的方式进行匹配声明,如前两个接口方法),有些接口方法仅对数据进行读操作,而另一些接口方法需要涉及到数据的更改。对于前者,可以通过readOnly标识出来,这样有利于操作性能的提高,需要注意的是由于父类节点定义的Bean仅是子节点配置信息的抽象,并不能具体实现化一个Bean对象,所以需要特别标注为abstract="true",如第8行所示。fileService作为一个目标类被注入到事务代理器中,而fileService实现类所需要的tfileDAO实例,通过引用3.2节中定义的tfileDAOBean注入。Web层实现1、Web层的构件和交互流程Web层包括主要3个功能:•上传文件。•列出所有已经上传的文件列表,以供点击下载。•下载文件。Web层实现构件包括与2个JSP页面,1个ActionForm及一个Action
-file-list.jsp:已经上传文件的列表页面。-FileActionForm:file-upload.jsp页面表单对应的ActionForm。•FileAction:继承org.apache.struts.actions.DispatchAction的Action,这样这个Action就可以通过一个URL参数区分中响应不同的请求。Web层的这些构件的交互流程如图6所示:hLt-wLo-ad.sf[llenctloidom#/tileftctio*hLt-wLo-ad.sf[llenctloidom#/tileftctio*芳CllcLLstFaveloadALLHle27.<27.</beans>-file-upload.jsp-file-upload.jsp:上传文件的页面。27.<27.</beans>-file-upload.jsp-file-upload.jsp:上传文件的页面。图6Web层Struts流程图其中,在执行文件上传的请求时,FileAction在执行文件上传后,forward到loadAllFile出口中,loadAllFile加载数据库中所有已经上传的记录,然后forward至U名为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某个请求操作编写一个Action类。但是参数名是要在struts-config.xml中配置的:<form-beans>TOC\o"1-5"\h\z<form-beanname="fileActionForm"type="sshfile.web.FileActionForm"/></form-beans><action-mappings><actionname="fileActionForm"parameter="method"path="/fileAction"type="sshfile.web.FileAction"><forwardname="fileListPage"path="/file-list.jsp"/><forwardname="loadAllFile"path="/fileAction.do?method=listAIIFile"/></action></action-mappings></struts-config>第6行的parameter="method"指定了承载方法名的参数,第9行中,我们还配置了一个调用FileAction不同方法的Action出口。FileAction共有3个请求响应的方法,它们分别是:upload(…):处理上传文件的请求。listAllFile(…):处理加载数据库表中所有记录的请求。download(…):处理下载文件的请求。下面我们分别对这3个请求处理方法进行讲解。2.1上传文件上传文件的请求处理方法非常简单,简之言之,就是从Spring容器中获取业务层处理类FileService,调用其save(FileActionFormform)方法上传文件,如下所示:publicclassFileActionextendsDispatchAction{//将上传文件保存到数据库中publicActionForwardupload(ActionMappingmapping,ActionFormform,HttpServletRequestrequest,HttpServletResponseresponse){FileActionFormfileForm=(FileActionForm)form;FileServicefileService=getFileService();fileService.save(fileForm);returnmapping.findForward("loadAIIFile");TOC\o"1-5"\h\z}//从Spring容器中获取FileService对象privateFileServicegetFileService(){ApplicationContextappContext=WebApplicationContextUtils.getWebApplicationContext(this.getServlet().getServletContext());return(FileService)appContext.getBean("fileService");}…}由于FileAction其它两个请求处理方法也需要从Spring容器中获取FileService实例,所以我们特别提供了一个getFileService()方法(第15~21行)。重构的一条原则就是:"发现代码中有重复的表达式,将其提取为一个变量;发现类中有重复的代码段,将其提取为一个方法;发现不同类中有相同的方法,将其提取为一个类”。在真实的系统中,往往拥有多个Action和多个Service类,这时一个比较好的设置思路是,提供一个获取所有Service实现对象的工具类,这样就可以将Spring的Service配置信息屏蔽在一个类中,否则Service的配置名字散落在程序各处,维护性是很差的。2.2列出所有已经上传的文件listAllFile方法调用Servie层方法加载T_FILE表中所有记录,并将其保存在Request域中,然后forward到列表页面中:publicclassFileActionextendsDispatchAction{…publicActionForwardlistAllFile(ActionMappingmapping,ActionFormform,HttpServletRequestrequest,HttpServletResponseresponse)throwsModuleException{FileServicefileService=getFileService();ListfileList=fileService.getAIIFile();request.setAttribute("fileList",fileList);returnmapping.findForward("fileListPage");TOC\o"1-5"\h\z}}file-list.jsp页面使用Struts标签展示出保存在Request域中的记录:<%@pagecontentType="text/html;charset=GBK"%><%@tagliburi="/WEB-INF/struts-logic.tld"prefix="logic"%><%@tagliburi="/WEB-INF/struts-bean.tld"prefix="bean"%><html><head><title>file-download</title></head><bodybgcolor="#ffffff"><ol>TOC\o"1-5"\h\z<logic:iterateid="item"name="fileList"scope="request"><li><ahref='fileAction.do?method=download&fileld=<bean:writename="item"property="fileld"/>'><bean:writename="item"property="fileName"/></a></li></logic:iterate></ol></body></html>展现页面的每条记录挂接着一个链接地址,形如:fileAction.do?method=download&fileld=xxx,method参数指定了这个请求由FileAction的download方法来响应,fileld指定了记录的主键。由于在FileActionForm中,我们定义了fileld的属性,所以在download响应方法中,我们将可以从FileActionForm中取得fileld的值。这里涉及到一个处理多个请求Action所对应的ActionForm的设计问题,由于原来的Action只能对应一个请求,那么原来的ActionForm非常简单,它仅需要将这个请求的参数项作为其属性就可以了,但现在一个Action对应多个请求,每个请求所对应的参数项是不一样的,此时的ActionForm的属性就fileContent禾口remark必须是多请求参数项的并集了。所以,除了文件上传请求所对应的属性外还包括文件下载的fileContent禾口remarksshfilev+bFiltActionForm少_'fileC节门fi]*!ld:亏ring'*押rtfitrk:in百…|图7FileActionForm当然这样会造成属性的冗余,比如在文件上传的请求中,只会用到fileContent和remark属性,而在文件下载的请求时,只会使用到fileld属性。但这种冗余是会带来好处的--它使得一个Action可以处理多个请求。2.3下载文件在列表页面中点击一个文件下载,其请求由FileAction的download方法来响应,download方法调用业务层的FileService方法,获取文件数据并写出到response的响应流中。通过合理设置HTTP响应头参数,将响应流在客户端表现为一个下载文件对话框,其代码如下所示:代码10业务接口实现类之downloadpublicclassFileActionextendsDispatchAction{…publicActionForwarddownload(ActionMappingmapping,ActionFormform,HttpServletRequestrequest,HttpServletResponseresponse)throwsModuleException{FileActionFormfileForm=(FileActionForm)form;FileServicefileService=getFileService();StringfileName=fileService.getFileName(fileForm.getFileld());try{response.setContentType("application/x-msdownload");response.setHeader("Content-Disposition","attachment;"+"filename="+newString(fileName.getBytes(),"ISO-8859-1"));fileService.write(response.getOutputStream(),fileForm.getFileld());TOC\o"1-5"\h\z}catch(Exceptione){thrownewModuleException(e.getMessage());}returnnull;}}第15~18行,设置HTTP响应头,将响应类型设置为即plication/x-msdownloadMIME类型,则响应流在IE中将弹出一个文件下载的对话框,如图4所示。IE所支持的MIME类型多达26种,您可以通过这个网址查看其他的MIME类型:/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中通过vlistener>vWeb容器初始化时触发初始化对其进行配置。,将其配-通过Servletorg.springframework.web.context.ContextLoaderServlet,将其配置为自动启动的Servlet,在Web容器初始化时,通过这个Servlet启动Spring容器。在初始化Spring容器之前,必须先初始化log4J的引擎,Spring也提供了容器监听器和自动启动Servlet两种方式对log4J引擎进行初始化:-org.springframework.web.util.Log4jConfigListener-org.springframework.web.util.Log4jConfigServletF面我们来说明如何配置web.xml启动Spring容器:代码11web.xml中对应Spring的配置内容<
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 隧道环境影响评估方案
- 2026北新路桥集团第三批次社会招聘1人备考题库及1套参考答案详解
- 水库运行调度优化方案
- 2026安徽皖信招聘铁塔阜阳市分公司技术人员2人备考题库附答案详解(巩固)
- 2026青海省第五人民医院青海省肿瘤医院校园招聘14人备考题库及答案详解(历年真题)
- 2026陕西西安市西北工业大学生命科学与技术学院理论生态学团队招聘1人备考题库及答案详解(夺冠)
- 施工现场环境保护措施方案
- 2026火车站邮政快递处理中心招聘30人备考题库带答案详解(完整版)
- 2026年白城市市直事业单位公开招聘硕士以上人才备考题库(1号)(100人)及答案详解(各地真题)
- 2026永安财产保险股份有限公司招聘备考题库含答案详解(典型题)
- 地质科普知识讲座
- 地理科学的发展及其对人类社会的贡献
- GB/T 43683.1-2024水轮发电机组安装程序与公差导则第1部分:总则
- 2024年江苏南京紫金投资集团有限责任公司招聘笔试参考题库含答案解析
- 物料降本规划方案
- Python经济大数据分析 课件 第7章 Python应用航空公司客户价值分析
- 云南德福环保有限公司2000t-a含油硅藻土处理和综合利用工程 环评报告
- 【实用资料】马克思主义基本原理绪论PPT
- 安全检查流程图
- GB/T 1921-2004工业蒸汽锅炉参数系列
- 基于web计算机应用竞赛管理系统论文
评论
0/150
提交评论