??xml version="1.0" encoding="utf-8" standalone="yes"?> IteratorQ还是ListQ这是一个设计错误? 我来谈谈在J2EE架构中各层的数据表示ҎQ? Web层的数据表示是FormBeanQ数据来源于HTML Form POST 在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内Q而不应该扩散到其它层Q这样可以降 低层间的耦合性,提高J2EE架构整体的可l护性和可扩展性。比如说Web层的逻辑q行了修改,那么只需 要修改FormBean的结构,而不需要触动业务层和持久层的代码修攏V同hQ当数据库表q行了小的调 _那么也只需要修Ҏ久层数据表示Q而不需要触动业务层代码和Web层代码? 不过׃Hibernate的强大功能,例如动态生成POQPO的状态管理可以脱SessionQ得在应用?/p> Hibernate的J2EE框架中,PO完全可以充当VOQ因此我们下面把PO和VO合ƈQ统UCؓPO? 先来谈谈ActionFormBean和持久层的PO之间的重大区别? 在简单的应用中,ActionFormBean和PO几乎是没有区别,所以很多hq脆是用ActionFormBean来充?/p> POQ于是ActionFormBean从JSP面到Servlet控制层再C务层Q然后穿q持久层Q最后一直映到?/p> 据库表。真是一竿子捅到了底Q? 但是在复杂的应用中,ActionFormBean和PO是分ȝQ他们也不可能一栗ActionFormBean是和|页?/p> 面的Form表单一一对应的,Form里面有什么元素,Bean里面有什么属性。而PO和数据库表对应,因此 如果数据库表不修改,那么PO也不会修改,如果面的流E和数据库表字段对应关系不一_那么你又 如何能够使用ActionFormBean来取代PO呢? 比如说吧Q用h册页面要求注册用L基本信息Q因此HTML Form里面包含了基本信息属性,于是你需 要一个ActionFormBean来一一对应(注意Q是一一对应)Q每个Bean属性对应一个文本框或者选择框什?/p> 的? 而用戯个持久对象呢Q他的属性和ActionFormBean有什么明显不同呢Q他会有一些ActionFormBean所 没有的集合属性,比如说用L权限属性,用户的组属性,用户的帖子等{。另外还有可能的是在 ActionFormBean里面?个属性,分别是用LFirst Name, Middle Name, Last NameQ而在我的Userq?/p> 个持久对象中是一?Name 对象属性? 假设我的注册面原来只要你提供First NameQ那么ActionFormBeanp一个属性,后来我要你提供全 名,你要改ActionFormBeanQ加两个属性。但是这个时候PO是不应该修改_因ؓ数据库没有改? 那么在一个完整的J2EEpȝ中应该如何进行合理的设计呢? JSP(View) ---> ActionFormBean(Module) ---> Action(Control) ActionFormBean是Web层的数据表示Q它和HTML面Form对应Q只要Web面的操作流E发生改变,它就 要相应的q行修改Q它不应该也不能被传递到业务层和持久层,否则一旦页面修改,会一直牵q到业务 层和持久层的大面U的代码q行修改Q对于Y件的可维护性和可扩展性而言Q是一个灾难,Actiont是 他的边界Q到此ؓ止! Action(Web Control) ---> Business Bean ---> DAO ---> ORM --->DB 而PO则是业务层和持久层的数据表示Q它在业务层和持久层之间q行动Q他不应该也不能被传递到Web 层的View中去Q而ActionServlet是他的边界Q到此ؓ止! 然后来看一看整个架构的程Q? 当用户通过览器访问网,提交了一个页面。于是Action拿到了这个FormBeanQ他会把FormBean属?/p> d来,然后构造一个PO对象Q再调用业务层的Beanc,完成了注册操作,重定向到成功面。而业?/p> 层Bean收到q个PO对象之后Q调用DAO接口ҎQ进行持久对象的持久化操作? 当用h询某个会员的信息的时候,他用全名q行查询Q于是Action得到一个UserNameFormBean包括? 个属性,分别是first name, middle name, last nameQ然后Action把UserNameFormBean?个属性读?/p> 来,构造Name对象Q再调用业务BeanQ把Name对象传递给业务BeanQ进行查询? 业务Bean取得Name(注意: Name对象只是User的一个属?对象之后调用DAO接口Q返回一个User的PO对象 Q注意这个User不同于在Web层用的UserFormBeanQ他有很多集合属性滴。然后业务Bean把User对象q?/p> 回给Action? Action拿到User之后Q把User的基本属性取?集合属性如果不需要就免了)Q构造UserFormBeanQ然?/p> 把UserFormBean request.setAttribute(...)Q然后重定向到查询结果页面? 查询面拿到request对象里面的ActionFormBeanQ自动调用tag昄之? ȝQ? FormBean是Web层的数据表示Q他不能被传递到业务层;PO是持久层的数据表C,在特定情况下Q例?/p> Hibernate中,他可以取代VO出现在业务层Q但是不POq是VO都必限制在业务层内使用Q最多到?/p> Web层的ControlQ绝不能被扩散到View厅R? FormBean和PO之间的数据{化是在Action中进行滴? BTW: JDO1.xq不能像Hibernate功能q样强大QPO不能q持久层,所以必d业务层用VOQ因此必d?/p> 务层q行大量的VO和PO的{化操作,相对于Hibernate来说Q编E比较烦琐? 当然咯,理论是一回事Q实际操作也不一定非要这样干Q你可以自行取舍Q在实际目中灵zM点,?/p> 加一点bad smellQ提高开发效率。只不过在大型项目中最好还是严丝合~,不然的话Q改版的时候会?/p> 苦的很滴?br />Q{载:http://forum.hibernate.org.cn/viewtopic.php?t=627Q?/p>
O/R Mapping ?Object Relational MappingQ对象关pL)的羃写。通俗点讲Q就是将对象与关pL据库l定Q用对象来表C关pL据。在O/R Mapping的世界里Q有两个基本的也是重要的东东需要了解,即VOQPO?br /> VOQ值对?Value Object)QPOQ持久对?Persisent Object)Q它们是׃l属性和属性的get和setҎl成。从l构上看Q它们ƈ没有什么不同的地方。但从其意义和本质上来看是完全不同的?br />
Q.VO是用new关键字创建,由GC回收的?
PO则是向数据库中添加新数据时创建,删除数据库中数据时削除的。ƈ且它只能存活在一个数据库q接中,断开q接卌销毁?
Q.VO是值对象,_点讲它是业务对象Q是存活在业务层的,是业务逻辑使用的,它存zȝ目的是为数据提供一个生存的地方?
PO则是有状态的Q每个属性代表其当前的状态。它是物理数据的对象表示。用它Q可以我们的程序与物理数据解耦,q且可以化对象数据与物理数据之间的{换?br />
Q.VO的属性是Ҏ当前业务的不同而不同的Q也是_它的每一个属性都一一对应当前业务逻辑所需要的数据的名U?
PO的属性是跟数据库表的字段一一对应的?br />
PO对象需要实现序列化接口?br />
Q{载:http://www.matrix.org.cn/resource/article/43/43869.htmlQ?br />Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-
?struts+ hibernate q种l构中,是不应该把Hibernate产生的PO直接传递给JSP的,不管他是
业务层的数据表示是VO
持久层的数据表示是POQ其数据来源于数据库Q持久层的数据表CZ如CMP
]]>
应用的启动和停止
Session的创建和失效如它们的名字那样Q应用启动事件发生在你的应用W一ơ被servlet容器装蝲和启动的时候;停止事g发生在Web应用停止的时候?br />
Session创徏事g发生在每ơ一个新的session创徏的时候,cM地Session失效事g发生在每ơ一个Session失效的时候。ؓ了用这些Web应用事gZ做些有用的事情,我们必须创徏和用一些特D的“监听”类。下面,我们研I这些监听类到地是什么以及我们如何去使用它们?br />
监听c:
它们是实C下边两个接口中Q何一个接口的单的javac:
如果你想让你的类监听应用的启动和停止事gQ你得实现ServletContextListener接口;如果你想让你的类ȝ听Session的创建和失效事gQ那你就得实现HttpSessionListener接口?让我们看看在q些接口中你必须要实现的Ҏ?
1.ServletContextListener :
接口包括如下两个ҎQ?
如果你实C一个接口,那你必d现它所有的Ҏ。因此,如果你想利用应用的启动和停止事gQ你需要创Z个Javacdƈ实现ServletContextListener接口。下Ҏq样的一个类的例子:
在上边的代码中,ApplicationWatchcdCServletContextListener接口。它实现了接口中的两个方法,但只用了其中的一个方法,另一个方法中没有写Q何代码。这个类把应用启动的旉记录在一个可以从其它应用cM存取应用启动旉的public static变量中?
我将很快解释如何告诉服务器我们有q个监听c,但首先让我们看看HttpSessionListener接口有什么不同的Ҏ?
2.HttpSessionListener :
q个接口也只包含两个ҎQ分别对应于Session的创建和失效Q?
如上边的ApplicationWatch例子那样Q我们也创徏了一个实现HttpSessionListener接口的类。如下:
在上边的代码中,SessionCountercdCHttpSessionListener接口Q其目的是计活动会话的数量?
好了Q我们已l学习了什么是Web应用事gQ有什么接口可以用以及看到了一些实现这些接口的例子。让我们看看如何告诉应用服务器我们有q些监听cR?
Web.xml :
我们通过把类路径加入/WEB-INF/web.xml文g的标{?listener>中来告诉服务器我们的监听cR下Ҏ一个web.xml文g的例子:
如上所C,在web.xml文g中声明监听类是非常简单的。现在,每次的服务器的启动和停止Q会话的创徏和失效,配置好的监听cȝ相应的方法就会被调用?img src ="http://www.tkk7.com/ltc603/aggbug/29174.html" width = "1" height = "1" />
]]>
文g的上传和下蝲在J2EE~程已经是一个非常古老的话题了,也许您马上就能掰着指头数出好几个著名的大gQ如SmartUpload、Apache的FileUpload。但如果您的目是构建在Struts+Spring+HibernateQ以下称SSHQ框架上的,q些大g显得笨重而桑了QSSH提供了一个简h便的文g上传下蝲的方案,我们只需要通过一些配|ƈ辅以量的代码就可以完好解决q个问题了?br />
本文围lSSH文g上传下蝲的主题,向您详细讲述如何开发基于SSH的WebE序。SSH各框架的均ؓ当前最新版本:
·Struts 1.2
·Spring 1.2.5
·Hibernate 3.0
本文选用的数据库为Oracle 9iQ当然你可以在不改动代码的情况下Q通过配置文g的调整将其移植到MhBlob字段cd的数据库上,如MySQLQSQLServer{?br />
M实现
上传文g保存到T_FILE表中QT_FILE表结构如下:
![]() ?1 T_FILE表结?/div> |
![]() ?2 SSH处理文g上传技术方?/div> |
![]() ?3 文g上传面 |
![]() ?4 文g下蝲面 |
![]() ?5 工程资源l构 |
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. } |
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?/td> |
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. } |
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="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. ?br />36. Q?beansQ?/td> |
1. QbeansQ?br />2. ?br />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. ?br />13. Q?beansQ?/td> |
1. QbeansQ?br />2. ?br />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. ?br />9. Q?beanQ?br />10. ?br />11. Q?beansQ?/td> |
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. } |
1. ?br />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. ?br />26. } |
1. ?br />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. ?br />20. } |
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?/td> |
![]() ?6 Web层Struts程?/div> |
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?/td> |
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. ?br />22. } |
1. public class FileAction 2. extends DispatchAction 3. { 4. ?br />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. } |
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?/td> |
![]() ?7 FileActionForm |
1. public class FileAction 2. extends DispatchAction 3. { 4. ?br />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. } |
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. ?br />21. Q?web-appQ?/td> |
1. Qweb-appQ?br />2. ?br />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. ?br />16. Q?web-appQ?/td> |