??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品亚洲精品,日韩亚洲精品福利,亚洲jjzzjjzz在线观看 http://www.tkk7.com/happyfish/category/555.htmlzh-cn Tue, 27 Feb 2007 10:31:09 GMT Tue, 27 Feb 2007 10:31:09 GMT 60 让Struts与Hibernate利协同工作 http://www.tkk7.com/happyfish/archive/2005/03/02/1624.html鱼?/dc:creator>鱼?/author>Wed, 02 Mar 2005 15:02:00 GMT http://www.tkk7.com/happyfish/archive/2005/03/02/1624.html http://www.tkk7.com/happyfish/comments/1624.html http://www.tkk7.com/happyfish/archive/2005/03/02/1624.html#Feedback 0 http://www.tkk7.com/happyfish/comments/commentRss/1624.html http://www.tkk7.com/happyfish/services/trackbacks/1624.html 久久学院 安装?/FONT> 一Q下载安?j2sdk1.4Qwww.sun.com)Q或以上,讄 CLASSPATHQjava_home? 二,下蝲服务器,免费版本的有 tomcat,resin,当然也还?weblogic之类的巨无霸Q不q得看你电脑的配|是否承受的? q里只以resin来说明,其他的配|都差不多,可以查看各个服务器自带的说明文g?BR> resin 服务器可以在 caucho.com下蝲Q选择合适的版本Q下载解压羃可以直接用?BR> q里resin有一?resin-ee版本Q这个主要是带ejb功能支持的?如果用不到ejbQ一般的p够了? 三,然后是数据库,有很多数据库产品可以选择QDB2,Oracle,MSSQL,MySQL{等太多了。这里我选择MySQLQ不仅因为它是免费的Q而且它的4.0版本在承以前版本的快速稳定的基础上,整合了InnoDB(http://www.innodb.com)先进的事务处理机制。相信伴随着Linux的壮大,它将在商业数据库市场占的一席之地。不q就数据库本w,它还~少子查询等强大功能的支持?BR>安装׃多说了,配置好用户名Q密码?然后可以下?MySQL-Front 来可视化操作数据库? 四,在Java~程上,一个IDE的功能显然不可缺,现在行的IDE很多Q有JBuilder,Eclipse,IntellJ IDEA,JCreator{等Q其?eclipse借着开源东风,依靠强大的插件功能被誉ؓ最有前途的工具QJBuilder从来都最强大功能的java工具Q不q大到我的电脑实在运行不了,I啊Q可没钱配新电脑。所以我q是喜欢JCreatorQ小巧而又功能不俗Q应付小规模的应用Ԓl有余。编译开发时要想获得提示支持Q需要在 configure--option--JDK Profiles 导入jar文g?BR> 五,一个站点前台的界面开发,当然M开大名鼎鼎?Dreamweaver 了,它支持jspQasp{很多语a的开发。特别是最q的Dreamweaver MX 2004 增强了站点的功能Q可以方便的对一个站点进行控制。面对struts的前台自定义标签Q有一个mxp插g可以用来支持昄sturts的标{。用前q要在编?-标签?里面导入.tld文gQ目前只支持htmlQ和bean 两个标签?BR> 配置?/FONT> 一Qresin虚拟站点配置
Qhost id='yourweb:8080' app-dir='e:\blog\' class-update-interval='2'Q?BR>Qweb-app id='/'Q?BR>Qdirectory-servlet id='false'/Q? Q?web-appQ?BR>Qerror-log id='log/web-error.log'/Q? QhostQ?/TD>
然后在定义的目录下面建立站点? 二,Dreamweaver站点的配|就不多说了?BR> 三,Struts的配|?BR> q里我们使用的是struts1.1,下蝲q解压羃C时文件夹Q就假设是tem文g夹吧?BR> 首先拯tem/lib/下面所有的.tld文g到站点的/WEB-INF/目录下,再拷贝所有的.jar文g?WEB-INF/lib/目录下,最后web.xml文g中的配置差不多如下:
Q?xml version="1.0" encoding="ISO-8859-1"?Q? Q?DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"Q?BR> Qweb-appQ?BR> QservletQ?BR>Qservlet-nameQactionQ?servlet-nameQ?BR>Qservlet-classQorg.apache.struts.action.ActionServletQ?servlet-classQ?BR>Qinit-paramQ?BR>Qparam-nameQconfigQ?param-nameQ?BR>Qparam-valueQ?WEB-INF/struts-config.xmlQ?param-valueQ?BR>Q?init-paramQ?BR>Qinit-paramQ?BR>Qparam-nameQdebugQ?param-nameQ?BR>Qparam-valueQ?Q?param-valueQ?BR>Q?init-paramQ?BR>Qinit-paramQ?BR>Qparam-nameQdetailQ?param-nameQ?BR>Qparam-valueQ?Q?param-valueQ?BR>Q?init-paramQ?BR>Qload-on-startupQ?Q?load-on-startupQ?BR>Q?servletQ?BR> Qservlet-mappingQ?BR>Qservlet-nameQactionQ?servlet-nameQ?BR>Qurl-patternQ?.doQ?url-patternQ?BR>Q?servlet-mappingQ?BR> Q?-- The Usual Welcome File List --Q?BR>Qwelcome-file-listQ?BR>Qwelcome-fileQindex.jspQ?welcome-fileQ?BR>Q?welcome-file-listQ?BR> Q?-- Struts Tag Library Descriptors --Q?BR>QtaglibQ?BR>Qtaglib-uriQ?tags/struts-beanQ?taglib-uriQ?BR>Qtaglib-locationQ?WEB-INF/struts-bean.tldQ?taglib-locationQ?BR>Q?taglibQ?BR> QtaglibQ?BR>Qtaglib-uriQ?tags/struts-htmlQ?taglib-uriQ?BR>Qtaglib-locationQ?WEB-INF/struts-html.tldQ?taglib-locationQ?BR>Q?taglibQ?BR> QtaglibQ?BR>Qtaglib-uriQ?tags/struts-logicQ?taglib-uriQ?BR>Qtaglib-locationQ?WEB-INF/struts-logic.tldQ?taglib-locationQ?BR>Q?taglibQ?BR> QtaglibQ?BR>Qtaglib-uriQ?tags/struts-nestedQ?taglib-uriQ?BR>Qtaglib-locationQ?WEB-INF/struts-nested.tldQ?taglib-locationQ?BR>Q?taglibQ?BR> QtaglibQ?BR>Qtaglib-uriQ?tags/struts-tilesQ?taglib-uriQ?BR>Qtaglib-locationQ?WEB-INF/struts-tiles.tldQ?taglib-locationQ?BR>Q?taglibQ?BR> Q?web-appQ?/TD>
四,Hibernate配置 下蝲q拷?lib目录下的
hibernate2.jar commons-beanutils.jar commons-collections.jar commons-dbcp.jar commons-lang.jar commons-logging.jar commons-pool.jar dom4j.jar cglib-asm.jar connector.jar
到应用站点的/lib目录下。接下来配置 hibernate.cfg.xml文g
Q?xml version='1.0' encoding='utf-8'?Q?BR>Q?DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"Q? Qhibernate-configurationQ?BR>Qsession-factoryQ?BR> Qproperty name="hibernate.connection.url"Q?BR>jdbc:mysql://localhost:3306/yourdatabase Q?propertyQ?BR>Qproperty name="hibernate.connection.driver_class"Q?BR>org.gjt.mm.mysql.Driver Q?propertyQ?BR>Qproperty name="hibernate.connection.username"Q?BR>yourname Q?propertyQ?BR>Qproperty name="hibernate.connection.password"Q?BR>youyrpassword Q?propertyQ?BR> Q??- 是否运行期生成的SQL输出到日志以供调?-Q?BR>Qproperty name="show_sql"QfalseQ?propertyQ?BR> Q?--dialect Q每个数据库都有其对应的Dialet以匹配其q_Ҏ?-Q?BR>Qpropertyname="dialect"Qnet.sf.hibernate.dialect.MySQLDialectQ?propertyQ?BR>Q??- 事务理cdQ这里我们用JDBC Transaction --Q?BR>Qproperty name="transaction.factory_class"Q?BR>net.sf.hibernate.transaction.JDBCTransactionFactoryQ?propertyQ?BR> Qproperty name="jdbc.batch_size"Q?0Q?propertyQ?BR>Qproperty name="jdbc.use_scrollable_resultset"QtrueQ?propertyQ?BR> Q??映射文g配置Q注意配|文件名必须包含其相对于根的全\?-Q?BR>Qmapping resource="net/seerlog/hbm/Cat.hbm.xml"/Q?BR> Q?session-factoryQ?BR> Q?hibernate-configurationQ?/TD>
以上配置了数据库q接所用的地址和用户名Q密码等。具体参数的含义请参考官Ҏ档?BR> 映射文g的内容可以手工来写,也可通过一些工h自动生成? 整个需要两U文Ӟ .hbm.xml配置文g ?.java持久化对?, 两者是怺兌的,.hbm.xml Ҏ据库的映还需?.javaq个bean来操作。所以整个过E需要首先设计好数据库,然后Ҏ数据库导?.hbm.xml文g ,然后再导?.java 文g?有很多工具可以实现这个工E,我们q里采用 Middlegen-Hibernate来实?数据库到.hbm.xml文g的{化,用Hibernate-Extension工具包中?hbm2java 来实?.hbm.xml ?.java 文g的{化! 查找关键字?FONT color=#ff0000>!ENTITY”,得到Q?BR>
Q?DOCTYPE project [ Q?ENTITY database SYSTEM "file:./config/database/hsqldb.xml "Q?BR>]Q?/TD>
b) Application name
Qproperty name="name" value="airline "/Q?
c) 输出目录 查找关键字“name="build.gen-src.dir"”,得到Q?BR>
Qproperty name="build.gen-src.dir" value="${build.dir}/gen-src "/Q?
d) 对应代码的Package name
Qhibernate destination="${build.gen-src.dir}" package="${name}.hibernate " genXDocletTags="false" genIntergratedCompositeKeys="false" javaTypeMapper="middlegen.plugins.hibernate.HibernateJavaTypeMapper" /Q?
配置完成后,在MiddleGen 根目录下q行antQ就出现MiddleGen的界面: 选择需要的表,单击H口剙的Generate 按钮QMiddleGen 即ؓ我们生成q些数据库表所对应的Hibernate映射文g? 接下来的工作通过Hibernate Extension 来完成,Hibernate Extension 的tools\bin目录下包含三个工P 1Q?hbm2java.bat Ҏ映射文g生成对应的POJO。通过MiddleGen 我们已经得到了映文Ӟ下一步就是通过hbm2java.bat工具生成对应的POJO?BR> 2Q?class2hbm.bat ҎPOJO class 生成映射文gQ这个工具很用刎ͼq里也就不再详细介绍?BR> 3Q?ddl2hbm.bat 由数据库导出库表l构Qƈ生成映射文g以及POJO。这个功能与MiddleGen的功能重叠,但由于目前还不够成熟Q实际上已经被废弃,不再l护Q,提供的功能也有限Q所以我们还是采用MiddleGen生成映射文gQ之后由hbm2javaҎ映射文g生成POJO 的方式? q里我们使用W一个hbm2java.batQ利用刚才生成的.hbm.xml文g自动生成 java 文g? Z使用q个工具Q首先我们需要配|一些参敎ͼ打开tools\bin\setenv.bat 文gQ修改其中的JDBC_DRIVER和HIBERNATE_HOME环境变量Q其指向我们的实际JDBC Driver文g和Hibernate所在目录。同时检查一下环境变量CP中的各个目中是否实际存在,特别?CORELIB%下的jar文gQ某些版本的发行包中Q默认配|中的文件名与实际的文g名有所出入Q如%CORELIB%\commons-logging.jar, 在Hibernate 发行包中Q可能实际的文g名是commons-logging-1.0.3.jarQ诸如此c)? 使用hbm2javaQ根据MiddleGen生成的映文件生成Java 代码Q?BR> 打开Command WindowQ在tools\bin目录下执行: hbm2java c:\sample\org\hibernate\sample\*.xml --output=c:\sample\ 通过以上步骤我们q成了所需要的所有基本配|文件。接下来可以来初始化这些配|啦?
实战?/B> 在这一节我们要配置一个完整的应用配置。其实每一个单独拿出来都能写本书,不过我只是侧重对自己ȝQ在以后我会不断地把学习的经验教训写下来?BR> 一QLog4j 的初始化 配置log4j.properties
### direct log messages to stdout ### #log4j.appender.stdout=org.apache.log4j.ConsoleAppender #log4j.appender.stdout.Target=System.out #log4j.appender.stdout.layout=org.apache.log4j.PatternLayout %c{1}:%L - %m%n #log4j.appender.stdout.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %l%n%m%n log4j.logger.seerlog=DEBUG,A2 log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.file=d:\\log\\applog.txt log4j.appender.A2.DatePattern='.'yyyy-MM-dd log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %m%n #log4j.logger.ALL=DEBUG,A1 log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender log4j.appender.A1.file=d:\\log\\all.log log4j.appender.A1.DatePattern='.'yyyy-MM-dd log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %l%n%m%n ### direct messages to file hibernate.log ### #log4j.appender.file=org.apache.log4j.FileAppender #log4j.appender.file.File=hibernate.log #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### ###log4j.rootLogger=warn, stdout log4j.rootLogger=info, A1 #以下是hibernate API需要的配置 log4j.logger.net.sf.hibernate=info ### log just the SQL #log4j.logger.net.sf.hibernate.SQL=debug ### log JDBC bind parameters ### log4j.logger.net.sf.hibernate.type=info ### log schema export/update ### log4j.logger.net.sf.hibernate.tool.hbm2ddl=debug ### log cache activity ### #log4j.logger.net.sf.hibernate.cache=debug ### enable the following line if you want to track down connection ### ### leakages when using DriverManagerConnectionProvider ### #log4j.logger.net.sf.hibernate.connection.DriverManagerConnectionProvider=trac
配置后如下来调用,首先需要初始化配置文gQ这个过E只需要一ơ,所以我们可以在ServletContextListener中来q行?BR>
String prefix = context.getRealPath("/"); PropertyConfigurator.configure(prefix+"/WEB-INF/classes/log4j.properties");
q里需要你的配|文件的路径来初始化?BR> 初始化完成后Q我们在以后的action中就可以 象下面一h调用Q?BR>
static Logger log=Logger.getLogger("seerlog"); log.warn("it's log4j warn"); log.info("it's log4j info");
关于 log4j 的完全用方法,偶会在以后做详细的说明! 二,hibernate 的初始化 首先我们要把hibernate.cfg.xml 攑ֈ应用?classes 目录中,然后可以使用hibernate参考文档提供的例子来封装对后台的用?BR>
public class Hi{ private static final SessionFactory sessionFactory; private static Connection conn; static { try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session getSession() throws HibernateException { Session s = (Session) session.get(); // 假如没有一个可用的U程Q开启一个新 Session, if (s == null) { conn=DBConnectionManager.getConnection(); s = sessionFactory.openSession(conn); session.set(s); } return s; } public static void closeSession() throws HibernateException { Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); if(conn!=null) DBConnectionManager.returnConnection(conn); } }
文中DBConnectionManager.getConnection()是一个DAOc,提供q接池的实现? 我们使用q个conq接来创Z?session Qsission是一个数据库q接操作的会话周期,它提供了强大的管理数据的能力? 以后我们在action?execute Ҏ中就可以使用 Hi.getSession()来获得一个会话支持。典型的应用如下Q?
try{ //开启一个会话,q启动事务回滚能?BR> Session session = Hi.getSession(); Transaction tx= session.beginTransaction(); //查询数据库,使用HQL Query q = session.createQuery("from Topic as topic order by topic.id desc"); q.setFirstResult(0); q.setMaxResults(5); //得到一个Listcd的数? List newTopicList = q.list(); // 业务处理 NewTopicList ntlBean=new NewTopicList(); ntlBean.setList(newTopicList); req.setAttribute("newtopiclist",ntlBean); //事务提交Q记得关闭会话! tx.commit(); Hi.closeSession(); }//因ؓ整个会话会抛出异常,所以需要用try--catch来包?BR>catch(HibernateException e){ //日志记录 Log.error(e.toString()); }
其中的HQL 可以参?hibernate 官方文档来学习?
实战?/B> 在这一节我们要配置一个完整的应用配置。其实每一个单独拿出来都能写本书,不过我只是侧重对自己ȝQ在以后我会不断地把学习的经验教训写下来?BR> 一QLog4j 的初始化 配置log4j.properties
### direct log messages to stdout ### #log4j.appender.stdout=org.apache.log4j.ConsoleAppender #log4j.appender.stdout.Target=System.out #log4j.appender.stdout.layout=org.apache.log4j.PatternLayout %c{1}:%L - %m%n #log4j.appender.stdout.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %l%n%m%n log4j.logger.seerlog=DEBUG,A2 log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.file=d:\\log\\applog.txt log4j.appender.A2.DatePattern='.'yyyy-MM-dd log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %m%n #log4j.logger.ALL=DEBUG,A1 log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender log4j.appender.A1.file=d:\\log\\all.log log4j.appender.A1.DatePattern='.'yyyy-MM-dd log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %l%n%m%n ### direct messages to file hibernate.log ### #log4j.appender.file=org.apache.log4j.FileAppender #log4j.appender.file.File=hibernate.log #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### ###log4j.rootLogger=warn, stdout log4j.rootLogger=info, A1 #以下是hibernate API需要的配置 log4j.logger.net.sf.hibernate=info ### log just the SQL #log4j.logger.net.sf.hibernate.SQL=debug ### log JDBC bind parameters ### log4j.logger.net.sf.hibernate.type=info ### log schema export/update ### log4j.logger.net.sf.hibernate.tool.hbm2ddl=debug ### log cache activity ### #log4j.logger.net.sf.hibernate.cache=debug ### enable the following line if you want to track down connection ### ### leakages when using DriverManagerConnectionProvider ### #log4j.logger.net.sf.hibernate.connection.DriverManagerConnectionProvider=trac
配置后如下来调用,首先需要初始化配置文gQ这个过E只需要一ơ,所以我们可以在ServletContextListener中来q行?BR>
String prefix = context.getRealPath("/"); PropertyConfigurator.configure(prefix+"/WEB-INF/classes/log4j.properties");
q里需要你的配|文件的路径来初始化?BR> 初始化完成后Q我们在以后的action中就可以 象下面一h调用Q?BR>
static Logger log=Logger.getLogger("seerlog"); log.warn("it's log4j warn"); log.info("it's log4j info");
关于 log4j 的完全用方法,偶会在以后做详细的说明! 二,hibernate 的初始化 首先我们要把hibernate.cfg.xml 攑ֈ应用?classes 目录中,然后可以使用hibernate参考文档提供的例子来封装对后台的用?BR>
public class Hi{ private static final SessionFactory sessionFactory; private static Connection conn; static { try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session getSession() throws HibernateException { Session s = (Session) session.get(); // 假如没有一个可用的U程Q开启一个新 Session, if (s == null) { conn=DBConnectionManager.getConnection(); s = sessionFactory.openSession(conn); session.set(s); } return s; } public static void closeSession() throws HibernateException { Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); if(conn!=null) DBConnectionManager.returnConnection(conn); } }
文中DBConnectionManager.getConnection()是一个DAOc,提供q接池的实现? 我们使用q个conq接来创Z?session Qsission是一个数据库q接操作的会话周期,它提供了强大的管理数据的能力? 以后我们在action?execute Ҏ中就可以使用 Hi.getSession()来获得一个会话支持。典型的应用如下Q?
try{ //开启一个会话,q启动事务回滚能?BR> Session session = Hi.getSession(); Transaction tx= session.beginTransaction(); //查询数据库,使用HQL Query q = session.createQuery("from Topic as topic order by topic.id desc"); q.setFirstResult(0); q.setMaxResults(5); //得到一个Listcd的数? List newTopicList = q.list(); // 业务处理 NewTopicList ntlBean=new NewTopicList(); ntlBean.setList(newTopicList); req.setAttribute("newtopiclist",ntlBean); //事务提交Q记得关闭会话! tx.commit(); Hi.closeSession(); }//因ؓ整个会话会抛出异常,所以需要用try--catch来包?BR>catch(HibernateException e){ //日志记录 Log.error(e.toString()); }
其中的HQL 可以参?hibernate 官方文档来学习?
]]> (?Spring学习W记1 http://www.tkk7.com/happyfish/archive/2005/03/02/1623.html鱼?/dc:creator>鱼?/author>Wed, 02 Mar 2005 14:50:00 GMT http://www.tkk7.com/happyfish/archive/2005/03/02/1623.html http://www.tkk7.com/happyfish/comments/1623.html http://www.tkk7.com/happyfish/archive/2005/03/02/1623.html#Feedback 0 http://www.tkk7.com/happyfish/comments/commentRss/1623.html http://www.tkk7.com/happyfish/services/trackbacks/1623.html 1、概느?/FONT>
对Spring耳闻已久Q但一直没有时间和心情ȝ它,最q它的声x来大了,Java视线http://forum.javaeye.com/ 有不高手在谈论它。于是趁着有空闲时_我也׃两个晚上看了看SpringQ看的是夏昕?lt;Spring开发指?gt;http://www.xiaxin.net/Spring_Dev_Guide.rarQ文章写得不错。以下谈谈我的学习感?/P>
一、Spring的IoC(Inversion of Control)?/FONT> q是Spring中得有特点的一部䆾。IoC又被译成“控制反转”,也不知道是谁译得这么别扭,感觉很深奥的词。其实,原理很简单,用一句通俗的话来说Q就是用XML来定义生成的对象。IoC其实是一U设计模式,Spring只是实现了这U设计模式?/P>
q种设计模式是怎么来的呢?是实践中逐渐形成的?/P>
W一阶段Q用普通的无模式来写JavaE序。一般初学者都要经q这个阶Dc?BR>W二阶段Q频J的开始用接口,q时Q接口一般都会伴随着使用工厂模式?BR>W三阶段Q用IoC模式。工厂模式还不够好:Q?Q因为的cȝ生成代码写死在程序里Q如果你要换一个子c,p修改工厂Ҏ。(2Q一个接口常常意味着一个生成工厂,会多出很多工厂类?BR> 可以把IoC模式看做是工厂模式的升华Q可以把IoC看作是一个大工厂Q只不过q个大工厂里要生成的对象都是在XML文g中给出定义的Q然后利用Java的“反”编E,ҎXML中给出的cd生成相应的对象。从实现来看QIoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文g来定义,也就是把工厂和对象生成这两者独立分隔开来,目的是提高灉|性和可维护性?/P>
IoC中最基本的Java技术就是“反”编E。反又是一个生涩的名词Q通俗的说反射是Ҏl出的类名(字符Ԍ来生成对象。这U编E方式可以让对象在生成时才决定要生成哪一U对象。我在最q的一个项目也用到了反,当时是给Z?properties文本文gQ里面写了一些全cdQ包名+cdQ,然后Q要Ҏq些全类名在E序中生成它们的对象。反的应用是很q泛的,象Hibernate、String中都是用“反”做为最基本的技术手Dc?/P>
在过去,反射~程方式相对于正常的对象生成方式要慢10几倍,q也怹是当时ؓ什么反技术没有普通应用开来的原因。但lSUN改良优化后,反射方式生成对象和通常对象生成方式Q速度已经相差不大了(但依然有一倍以上的差距Q?/P>
所以要理解IoCQ你必须先了解工厂模式和反射~程Q否则对它生的前因后果和实现原理都是无法理解透彻的。只要你理解了这一点,你自׃完全可以自己在程序中实现一个IoC框架Q只不是q还要涉及到XML解析{其他知识,E微ȝ一些?/P>
IoC最大的好处是什么?因ؓ把对象生成放在了XML里定义,所以当我们需要换一个实现子cd会变成很单(一般这L对象都是现实于某U接口的Q,只要修改XML可以了Q这h们甚臛_以实现对象的热插拨(有点象USB接口和SCIS盘了)?/P>
IoC最大的~点是什么?Q?Q生成一个对象的步骤变复杂了Q其实上操作上还是挺单的Q,对于不习惯这U方式的人,会觉得有些别扭和不直观。(2Q对象生成因为是使用反射~程Q在效率上有些损耗。但相对于IoC提高的维护性和灉|性来_q点损耗是微不道的,除非某对象的生成Ҏ率要求特别高。(3Q缺IDE重构操作的支持,如果在Eclipse要对cL名,那么你还需要去XML文g里手工去改了Q这g是所有XML方式的缺憾所在?/P>
ȝ来说IoC无论原理和实现都q算是很单的。一些h曾认为IoC没什么实际作用,q种说法是可以理解的Q因为如果你在编E中很少使用接口Q或很少使用工厂模式Q那么你Ҏ没有用IoC的强烈需要,也不会体会到IoC可贵之处。有些h也说要消除工厂模式、单例模式,但是都语焉不详、h云亦云。但如果你看到IoC模式和用上SpringQ那么工厂模式和单例模式的确基本上可以不用了。但它消׃吗?没有QSpring的IoC实现本n是一个大工厂Q其中也包含了单例对象生成方式,只要用一个设|就可以让对象生成由普通方式变单一实例方式Q非怹单?/P>
ȝQ?BR> Q?QIoC原理很简单,作用的针Ҏ也很强Q不要把它看得很玄乎?BR> Q?Q要理解IoCQ首先要了解“工厂、接口、反”这些概c?/FONT>
二、Spring的MVC
如果你已l熟悉StrutsQ那么不必把MVC做ؓ重点学习内容。基本上我认为Spring MVC是一个鸡肋,它的技术上很先q,但易用性上没有Struts好。而且Struts有这么多q的基础了,Spring很难取代Struts的地位。这是先入Z的优UQ一个项目经理选用一U框Ӟ不能单纯的从它的技术上考虑Q还有开发效率,人员配置{都是考虑因素。但做ؓ研究性的学习QSpring的MVC部䆾q是蛮有价值的?/P>
三、数据库层的模板 Spring主要是提供了一些数据库模板Q模板也是一UJava设计模式Q,让数据部分的代码更简z,那些try...catch都可以不见了。这个的是个好东东?/P>
四、AOP
AOP又称面向斚w~程Q它的实现原理还是用了反:通过Ҏ一个种cȝҎ名做监控来实现统一处理。比如:监控以“insert”字W串开头的Ҏ名,在这U方法执行的前后q行某种处理Q数据库事务{)。但q里我有一个疑问?不一定所有以insert开头的Ҏ都是数据库操作,哪么当某个insert开头的Ҏ不是数据库操作,你又对它q行了数据事务的操作Q这L错误如何防止Q?Q我对这斚w了解不深Q还是只知道一个大概?/P>
曄q一个程序员发出q样的感慨:“框架一个接一个,学也学不完,而且有必要吗Q这样一层层的加上框Ӟq不如直接写JSP来得直接Q效率还高”。我惌U困惑很多h都有吧?但如果你l过的项目渐多,׃发现Q维护项目要比开发项目更艰难Q代h大。那U用JSP直接来写Q层ơ又不清楚的开发,往往最后得C个不可再修改的YӞ一团ؕ麻,UM发而动全n。但软g不象电视机,做好了就不会改动了,软g是一个变化的事物Q用L需求随时会改变Q这时你会体会到分层和用框架的好处了,它们Z做了软g中很多和业务无关的工作,你可以只x业务Qƈ减少代码量。唯一~点是有一个学习的代hQ框枉|上也较ȝ?/P>
学习框架Q我认ؓ应该Q第一步,了解q个框架中的一些关键概念,它的具体含义是什么。第二步Q了解这个框架的_֍在哪里,它能对开发vC么样的作用,最好能对它的原理有一定的了解。第三步Q用q个框架来写几个例子Q实际体会一下。我现在q是刚刚大概完成了前两步Q这几天会再看看Spring的文档ƈ用Spring写几个例子,到时一起发出来?/P>
另外Q很赞赏<Spring开发指?gt;的作者夏昕的观点Q将自已的经验写成文档公开出来Q不q一个h的力量终I太弱。最好能够Ş成一个组l,对一U新技术,׃两个人出一个大UԌ大家把它分了Q更写一章,然后׃三个人总集赗我个h感觉Q由于英文语a的关p,新技术引q到国内的还是太慢了Q至要比国外慢上一q以上,成立一个开源文档组l还是很有意义的事?/P>
]]> (?Spring的下载和安装 http://www.tkk7.com/happyfish/archive/2005/03/02/1622.html鱼?/dc:creator>鱼?/author>Wed, 02 Mar 2005 14:49:00 GMT http://www.tkk7.com/happyfish/archive/2005/03/02/1622.html http://www.tkk7.com/happyfish/comments/1622.html http://www.tkk7.com/happyfish/archive/2005/03/02/1622.html#Feedback 0 http://www.tkk7.com/happyfish/comments/commentRss/1622.html http://www.tkk7.com/happyfish/services/trackbacks/1622.html 下蝲主页 http://www.springframework.org/download.html Q或者直接用链接地址Q?/SPAN>http://voxel.dl.sourceforge.net/sourceforge/springframework/spring-framework-1.1.4-with-dependencies.zip
Spring 的下载包有两U: spring-framework-1.1.4-with-dependencies.zip ?/SPAN>spring-framework-1.1.4.zip Q上面的W二个链接就是下载前者,你也下蝲前者,因ؓ前者比后者多了一?/SPAN>Spring 要用到的W三方包Q如 hibernate ?/SPAN>j2ee ?/SPAN>dom4j ?/SPAN>aopalliance ?/SPAN>jakarta-commons {。下载包名称?/SPAN>dependencies 是“依赖”的意思?/SPAN>
1、解压后的目录结构如下:
目录说明Q?/SPAN>
l dist Spring 自已的核心库
l docs 有一些文档?/SPAN>
l lib 是一些用到的W三方库?/SPAN>
l mock 仿制品?Q?Q?Q?Q?Q?Q?我也不知?/SPAN>
l samples 一些项目例?/SPAN>
l src Spring 的源代码
l test 试用例
2、新Z个Eclipse目
Q?/SPAN>1 Q项目名 myspring
Q?/SPAN>2 Q直接单几Z下一步”,再单几Z完成?/SPAN>
Q?/SPAN>3 Q在目下创Z?/SPAN>lib 目录
Q?/SPAN>4 Q将 Spring 的解压羃目录 dist ?/SPAN>lib 都复制到q个 lib 目录中,然后前者改名成 spring Q后者先暂时不动吧,以后用到时才它?/SPAN>
3、将spring库加入到库引?/SPAN>
?/SPAN>spring 库加入到库引用中Q有如下两种Ҏ?/SPAN>
Ҏ一Q单几Z添?/SPAN>JAR ”把 spring 的核心包加入?/SPAN>
Ҏ二:上面的“方法一”简单易行,但如果一个项目要引入的包U类很多Q那么就昄得较乱。还有一U操作麻烦,但较清晰一些的Ҏ。这U方法是使用 Eclipse 中的“用户库”的方式Q如下图所C:
最后的l果如下图所C,然后单击“确定?/SPAN>
q回上一界面后,再单几Z完成”,得到如下图所C的效果
最后,目里的 spring 包的引用都在一个目录下Q显C层ơ感强很多?/SPAN>
以后如果要引?/SPAN>myspring/lib/lib 目录下的W三方包Q也按方法二较好Q将W三方包的目录复制到 myspring/lib 下,再参照方法二Q将其加入库引用中即?/SPAN>
4、设|日志包的库引用
jakarta-commons ?/SPAN>log4j 包主要是做ؓ Spring 的运行时输出 log Q日志)用,如果不设|日志包Q那么日志就没法输出到控制台Q不利于开发和调试。设|方式如下:
Q?/SPAN>1 Q就照上面的ҎQ放 myspring/lib/lib 目录下的 log4j 目录?/SPAN>jakarta-commons 目录往上移一层到 myspring/lib 目录下。最后设|的l果如下图所C,q里我们?/SPAN>log4j Ud?/SPAN>others 目录Q因?/SPAN>log4j ׃?/SPAN>JAR 包,专门为它?/SPAN>jakarta-commons 创徏一个目录和用户库太不gQ以后可能还会有q种引用单个包的时候,到时都放?/SPAN>others 目录里好了?/SPAN>
Q?/SPAN>2 Q日志的库引用完成之后,q要创徏一个日志的配置文gQ?/SPAN>log4j.properties Q其文g内容如下Q?/SPAN>
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%c{1} - %m%n
log4j.properties 文g的创Z|在 src 目录下,如下图所C:
如果没有讄日志讄或设|不对,在用控制台时会出现下面所C的U字?/SPAN>
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
]]>Struts 用户指南 http://www.tkk7.com/happyfish/archive/2005/03/02/1621.html鱼?/dc:creator>鱼?/author>Wed, 02 Mar 2005 14:48:00 GMT http://www.tkk7.com/happyfish/archive/2005/03/02/1621.html http://www.tkk7.com/happyfish/comments/1621.html http://www.tkk7.com/happyfish/archive/2005/03/02/1621.html#Feedback 0 http://www.tkk7.com/happyfish/comments/commentRss/1621.html http://www.tkk7.com/happyfish/services/trackbacks/1621.html 1. 介绍 1.1 Model-View-Controller (MVC) 设计模式 FIXME - 需要一个对该模式一般性的介绍。(译注Q可以参考机械工业出版社的《设计模式》。) 1.2 MVC概念映射到Strutslg?BR>Struts 的体pȝ构实CModel-View-Controller设计模式的概念,它将q些概念映射到web应用E序的组件和概念中,如下图所C: -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- q一体系l构中每个主要的lg都将在下面做详细的讨论?nbsp; 1.3 Model: pȝ状态和商业逻辑JavaBeans ZMVC的系l中?nbsp;Model 部分可以l分Z个概?nbsp;-- pȝ的内部状? 能够改变状态的行ؓ。用语法术语来说Q我们可以把状态信息当作名词(事物Q,把行为当作动词(事物状态的改变Q?nbsp; 通常说来Q你的应用程序将pȝ内部的状态表CZؓ一l一个或多个的JavaBeansQ用属性(propertiesQ来表示状态的l节。依赖于你的应用E序的复杂度Q这些beans可以是自包含的(以某U方式知道怎样怹C存它们的状态信息)Q或者可以是正面的(facadesQ,知道当被h时怎样从外部数据源Q例如数据库Q中取得信息。Entity EJBs通常也用来表C内部状态?nbsp; 大型应用E序l常系l可能的商业逻辑行ؓ表示为可以被l护状态信息的beans调用的方法。D个例子,你有一个ؓ每个当前用户保存在session中的购物车beanQ里面是表示当前用户军_购买物品的属性。这个bean有一个checkOut()Ҏ用来验证用户的信用卡Q将定单发给库房以选择货品和出货。别的系l分别地表示同样的行为,或许使用Session EJBs?nbsp; 在一些小型应用程序中Q同L行ؓ又可能嵌入到作ؓController一部分?nbsp;Action cM。这在逻辑非常单或者ƈ不想要在其它环境中重用这些商业逻辑时是恰当的。Struts框架支持所有这些方法,但徏议将商业逻辑Q“做什么”)?nbsp;Action c(“决定做什么”)分离开?nbsp; 1.4 View: JSP面和表C组?BR>ZStruts的应用程序中?nbsp;View 部分通常使用JSP技术来构徏。JSP面包含UCؓ“模版文本”的静态HTMLQ或XMLQ文本,加上插入的基于对Ҏ行ؓ标记解释的动态内宏VJSP环境包括了其用途由JSP规范来描q的一套标准的行ؓ标记Q例?nbsp;<jsp:useBean> 。另外,q有一个用来定义你自己标记的标准机Ӟq些自定义的标记l织在“定制标记库”中?nbsp; Struts包括了一个广阔的便于创徏用户界面Qƈ且充分国际化的定制标记库Q与作ؓpȝ Model 部分一部分的ActionForm beans妙地相互配合。这些标记的使用在后面做详l讨论?nbsp; 除了JSP面和其包含的行为及定制标记Q商业对象经帔R要能够基于它们在被请求时的当前状态将自己处理成HTMLQ或XMLQ。从q些对象处理q的输出可以很容易地使用 <jsp:include> 标准行ؓ标记包括在结果的JSP面中?nbsp; 1.5 Controller: ActionServlet和ActionMapping 应用E序?nbsp;Controller 部分集中于从客户端接收请求(典型情况下是一个运行浏览器的用PQ决定执行什么商业逻辑功能Q然后将产生下一步用L面的责Q委派l一个适当的Viewlg。在Struts中,controller的基本组件是一?nbsp;ActionServlet cȝservlet。这个servlet通过定义一l映(由Java接口 ActionMapping 描述Q来配置。每个映定义一个与所h的URI相匹配的路径和一?nbsp;Action c(一个实?nbsp;Action 接口的类Q完整的cdQ这个类负责执行预期的商业逻辑Q然后将控制分派l适当的Viewlg来创建响应?nbsp; Struts也支持用包含有q行框架所必需的标准属性之外的附加属性的 ActionMapping cȝ能力。这允许你保存特定于你的应用E序的附加信息,同时仍可利用框架其余的特性。另外,Struts允许你定义控制将重定向到的逻辑名,q样一个行为方法可以请求“主菜单”页面(举例Q,而不需要知道相应的JSP面的实际名字是什么。这个功能极大地帮助你分L刉辑Q下一步做什么)和显C逻辑Q相应的面的名U是什么)?nbsp; 2. 创徏Modellg 2.1 概述 你用到的应用E序的需求文档很可能集中于创建用L面。然而你应该保证每个提交的请求所需要的处理也要被清楚的定义。通常说来QModel lg的开发者集中于创徏支持所有功能需求的JavaBeanscR一个特D应用要求的beans的精特性依赖于具体需求变化会非常的大Q但是它们通常可以分成下面讨论的几U类型。然而,首先对“范围”概念做一个简短的回顾是有用的Q因为它与beans有关?nbsp; 2.2 JavaBeans和范?BR>在一个基于web的应用程序中QJavaBeans可以被保存在Qƈ从中讉KQ一些不同“属性”的集合中。每一个集合都有集合生存期和所保存的beans可见度的不同的规则。ȝ说来Q定义生存期和可见度的这些规则被叫做q些beans?nbsp;范围 。JSP规范中用以下术语定义可选的范围Q在圆括号中定义servlet API中的{h物)Q?nbsp; page - 在一个单独的JSP面中可见的BeansQ生存期限于当前h。(service()Ҏ中的局部变量) request - 在一个单独的JSP面中可见的BeansQ也包括所有包含于q个面或从q个面重定向到的页面或servlet。(Request属性) session - 参与一个特定的用户session的所有的JSP和servlet都可见的BeansQ跨一个或多个h?Session属性) application - 一个web应用E序的所有JSP面和servlet都可见的Beans。(Servlet context属性) C同一个web应用E序的JSP面和servlets׃n同样一lbean集合是很重要的。例如,一个bean作ؓ一个request属性保存在一个servlet中,pq样Q?nbsp; MyCart mycart = new MyCart(...); request.setAttribute("cart", mycart); 立卌q个servlet重定向到的一个JSP面使用一个标准的行ؓ标记看到Q就象这P <jsp:useBean id="cart" scope="request" class="com.mycompany.MyApp.MyCart"/> 2.3 ActionForm Beans Struts框架通常假定你已lؓ每一个你的应用程序中h的输入创Z一?nbsp;ActionForm beanQ即一个实C ActionForm 接口的类Q。如果你在你?nbsp;ActionMapping 配置文g中定义了q样的beansQ见“创建Controllerlg”)QStruts的controller servlet在调用适当?nbsp;Action Ҏ前将自动Z执行如下的服务: 用适当的关键字查用Lsession中是否有适当的类的bean的一个实例?nbsp; 如果没有q样的session范围的beanQ自动徏立一个新的beanq添加到用户的session中?nbsp; Ҏ个名字对应于bean中的一个属性的h参数Q调用相应的setҎ。这个操作类g当你以通配W?”选择所有属性用标准的JSP行ؓ标记 <jsp:setProperty> ?nbsp; 更新的ActionForm bean在被调用时将被传递给Actoncȝperform()ҎQ以使这些D够立即生效?nbsp; 当你在写你的ActionForm beansӞC以下的原则: ActionForm 接口本n不需要特D的实现Ҏ。它是用来标识这些特定的beans在整个体pȝ构中的作用。典型情况下Q一个ActionForm bean只包括属性的getҎ和setҎQ没有商业逻辑?nbsp; 通常在一个ActionForm bean中只有很的输入验证逻辑。这Lbeans存在的主要理由是保存用户为相关的表单所输入的大部分q期?nbsp;-- 甚至在错误被到?nbsp;-- q样同样的页面可以被重徏Q伴随有一l出错信息,q样用户仅仅需要纠正错误的字段。用戯入的验证应该?nbsp;Action cM执行Q如果是很简单的话)Q或者在适当的商业逻辑beans中执行?nbsp; 为每个表单中出现的字D定义一个属性(用相关的getXxx()和setXxx()ҎQ。字D名和属性名必须按照JavaBeans的约定相匚w。例如,一个名?nbsp;username 的输入字D将引v setUsername() Ҏ被调用?nbsp; 你应该注意一个“表单”在q里讨论时的意义q不必须对应于用L面中的一个单独的JSP面。在很多应用E序中一个“表单”(从用L观点Qg伸至多个面也是很^常的。想想看Q例如,通常在安装新的应用程序时使用的导航安装程序的用户界面。Struts鼓励你定义一个包含所有字D属性的单独的ActionForm bean。不字D实际上是显C在哪个面上。同LQ同一表单的不同的面应该提交到相同的ActioncR如果你늅q个Q在大多数情况下Q页面设计者可以重新组l不同页面中的字D而不需要改变处理逻辑?nbsp; 2.4 pȝ状态Beans pȝ的实际状态通常表示Zl一个或多个的JavaBeansc,其属性定义当前状态。例如,一个购物Rpȝ包括一个表C物R的beanQ这个bean为每个单独的购物者维护,q个bean中包括(在其它事物之中)一l购物者当前选择购买的项目。分别地Q系l也包括保存用户信息Q包括他们的信用卡和送货地址Q、可获得目的目录和它们当前库存水^的不同的beans?nbsp; 对于规模的pȝQ或者对于不需要长旉保存的状态信息,一l系l状态beans可以包含所有系l曾l经历的特定l节的信息。或者经常是Q系l状态beans表示怹保存在一些外部数据库中的信息Q例如CustomerBean对象对应于表 CUSTOMERS 中的特定的一行)Q在需要时从服务器的内存中创徏或清除。在大规模应用程序中QEntity EJBs也用于这U用途?nbsp; 2.5 商业逻辑Beans 你应该把你的应用E序中的功能逻辑装成对为此目的设计的JavaBeans的方法调用。这些方法可以是用于pȝ状态beans的相同的cȝ一部分Q或者可以是在专门执行商业逻辑的独立的cM。在后一U情况下Q你通常需要将pȝ状态beans传递给q些Ҏ作ؓ参数处理?nbsp; Z代码最大的可重用性,商业逻辑beans应该被设计和实现为它们不知道自己被执行于web应用环境中。如果你发现在你的bean中你必须import一?nbsp;javax.servlet.* c,你就把这个商业逻辑捆绑在了web应用环境中。考虑重新l织事物使你?nbsp;Action c(Controllerd的一部分Q在下面描述Q翻译所有从HTTPh中请求被处理为对你的商业逻辑beans属性setҎ调用的信息,然后可以发出一个对 execute() 的调用。这L一个商业逻辑cd以被重用在除它们最初被构造的web应用E序以外的环境中?nbsp; 依赖于你的应用程序的复杂度和范围Q商业逻辑beans可以是与作ؓ参数传递的pȝ状态beans交互作用的普通的JavaBeansQ或者用JDBC调用讉K数据库的普通的JavaBeans。而对于较大的应用E序Q这些beansl常是有状态或无状态的EJBs?nbsp; 2.6 题外? 讉K关系数据?BR>很多web应用E序利用一个关pL据库Q通过一个JDBC driver讉KQ来保存应用E序相关的永久数据。其它应用程序则使用Entity EJBs来实现这个目的,他们委派EJBs自己来决定怎样l护怹状态。如果你是用EJBs来实现这个目的,늅EJB规范中描q的客户端设计模式?nbsp; 对于Z直接数据库访问的web应用E序Q一个普通的设计问题是当需要访问低层数据库时怎样产生一个适当的JDBCq接对象。解册个问题有几种Ҏ -- 以下原则描述了推荐的一U方法: 创徏或得C个允怸l数据库q接被多个用户共享的ConnectionPoolcRStrutsQ当前)没有包括q样的一个类Q但是有很多q样的类可以得到?nbsp; 当应用程序初始化Ӟ在应用程序展开QdeploymentQ描q符中定义一个有一个“启动时加蝲”值的servlet。我们将把这个servlet叫做 启动 servlet。在大多数情况下Q这个servlet不需要处理Q何的hQ所以没有一?nbsp;<servlet-mapping> 会指向它?nbsp; 在启动servlet?nbsp;init() Ҏ中,配置q初始化一个ConnectionPoolcȝ实例Q将其保存ؓ一个servlet context属性(从JSP的观点看{同于一个application范围的beanQ。通常Z传递给启动servlet初始化参数来配置联接~冲池是很方便的?nbsp; 在启动servlet?nbsp;destroy() Ҏ中,包含了释放联接缓冲池所打开的联接的逻辑。这个方法将在servlet容器l束q个应用E序的时候被调用?nbsp; ?nbsp;Action c需要调用一个需要数据库联接的商业逻辑bean中的ҎQ例如“insert a new customer”)Ӟ执行下面的步骤Q?nbsp; 个web应用E序从servelt context属性中得到一个联接缓冲池对象?nbsp; 调用联接~冲池对象的 open() Ҏ来得C个在 Action c调用中使用的联接?nbsp; 调用商业逻辑bean中合适的ҎQ将数据库联接对象作Z个参C递给它?nbsp; 调用分配的联接中?nbsp;close() ҎQ这引赯个联接ؓ了以后其它请求的重用被返回到~冲池中?nbsp; 一个通常的编E错误是忘记了把数据库联接返回给~冲池,q将最l导致用完所有的联接。一定要信 Action cȝ逻辑Lq回联接Q甚臛_商业逻辑bean抛出一个违例时?nbsp; 늅上面推荐的设计模式意味着你能够编写你的商业逻辑c而不需要担心它们怎样得到一个JDBC联接来?- 单地在Q何需要访问数据库的方法中包含一个Connection参数。当你的商业逻辑cd一个web应用E序中被利用Ӟ分配和释N当的联接是 Action cȝ责Q。当你用相同的商业逻辑cLQ例如,在一个批处理工作中,提供一个适当的联接是那个应用E序的责任(q不需要从~冲池中获得Q因为大多数批处理工作运行于一个单U程环境中)?nbsp; 3. 创徏Viewlg 3.1 概述 q一章集中于创徏应用E序中的 View lg的Q务,主要使用JSP技术徏立。特别的QStruts除了提供了与输入表单的交互外q提供了建立国际化应用程序的支持。几个其它的与View相关的主题也被简单地讨论?nbsp; 3.2 国际化消?BR>几年之前Q应用程序开发者能够考虑C仅支持他们本国的只用一U语aQ或者有时候是两种Q和通常只有一U数量表现方式(例如日期、数字、货币|的居民。然而,Zweb技术的应用E序的爆炸性增长,以及这些应用程序展开在Internet或其它被q泛讉K的网l之上,已经在很多情况下使得国家的边界E化到不可见。这U情况{变成ZU对于应用程序支持国际化Q经常被U做“i18n”,因ؓ18是字母“i”和字母“n”之间的字母个数Q和本地化的需求?nbsp; Struts建立于Javaq_之上为徏立国际化和本地化的应用程序提供帮助。需要熟悉的关键概念是: Locale - 基础的支持国际化的JavacL java.util.Locale 。每?nbsp;Locale 代表一个特别的国家和语a选择Q加上一个可选的语言变量Q,以及一套格式假定,例如数字和日期等{?nbsp; ResourceBundle - java.util.ResourceBundle cL供支持多U语a消息的基本工兗查看文档中关于ResourceBundle cM及你的JDK版本的文档包中关于国际化的更多内宏V?nbsp; PropertyResourceBundle - 一?nbsp;ResourceBundle cȝ标准实现允许你用与初始化properties文g同样的“name=value”语法来定义资源。这对于使用为用于一个web应用E序的消息准备资源包是非常方便的Q因些消息通常都是面向文本的?nbsp; MessageFormat - java.text.MessageFormat cd怽使用q行时指定的参数替换一个消息字W串中的一部分Q在q种情况下,是一个从一个资源包得到的消息)。这在你创徏一个句子的场合中是有用的,但是词会以不同的语言按照不同的顺序出现。消息中的占位符字符串{0}用第一个运行时参数替换Q{1}用第二个q行时参数替换,以此cL?nbsp; MessageResources - Struts的类 org.apache.struts.util.MessageResources 使你能够一套资源包视做一个数据库Qƈ且允怽Z个特定的LocaleQ通常是与当前用户相对应)h一个特定的消息Q而不是ؓ服务器运行在其中的缺省的Localeh消息?nbsp; 对于一个国际化的应用程序,늅JDK文档包中国际化文档所描述的步骤来创徏一个包含每U语a的消息的属性文件。下面D一个例子说明?nbsp; 假设你的源代码徏立在?nbsp;com.mycompany.mypackage 中,因此它保存于一个叫做(相对于你的源目录Qcom/mycompany/mypackage 的目录中。ؓ创徏一个叫?nbsp;com.mycompany.mypackage.MyResources 的资源包Q你应该在目?nbsp;com/mycompany/mypackage 中创Z列文Ӟ MyResources.properties - 包含你的服务器的~省语言的消息。如果你的缺省语a是英语,你可能有一个这L条目Q?nbsp; prompt.hello=Hello MyResources_xx.properties - 包含ISO语言~程为“xx”(查看ResourceBundle的Java文档面得到一个当前列表的联接Q的同样的消息。对于上面的消息的法语版Q你可以有这个条目: prompt.hello=Bonjour 你可以有你需要的L多的语言的资源包文g?BR>当你在web应用E序展开描述W中配置controller servletӞ你需要在一个初始化参数中定义的一件事是应用程序的资源包的基础名。在上述的情况中Q这应该?nbsp;com.mycompany.mypackage.MyResources ?nbsp; 3.3 表单和FormBean的交?BR>大部分web开发者曾l用HTML的标准性能来徏立表单,例如使用 <input> 标记。用户希望交互程序具有一定的行ؓQ这些期待中的一个与错误处理有关 -- 如果用户出现一个错误,应用E序应该允许他们仅仅修改需要修改的部分 -- 而不需要重新敲入当前页面或表单中的M其它信息?nbsp; 使用标准的HTML和JSP~程来完全实现这个期望是单调而繁重的。D例来_一个用户名字段的输入元素看h可以象是q样Q在JSP中) <input type="text" name="username" value="<%= loginBean.getUsername() %>"> q很难敲对,会把没有~程概念的HTML开发者搞p涂Qƈ且会在HTML~辑器中造成问题。取而代之的是,Struts提供了一U全面的ZJSP 1.1的定制标记库功能的机制来建立表单。上面的情况使用Struts处理后将象是q样Q?nbsp; <struts:text name="username"/> 没有必要再显式地涉及C中获得初始值的JavaBean。这由框架自动处理?nbsp; 3.3.1 使用Struts建立表单 一个完整的注册表单演CStruts相对于直接用HTML和标准的JSP功能怎样极大地减M处理表单的痛苦。考虑以下UCؓlogon.jsp的页面(来自Struts的例子程序)Q?nbsp; <%@ page language="java" %> <%@ taglib uri="/WEB-INF/struts.tld" prefix="struts" %> <html> <head> <title><struts:message key="logon.title"/></title> <body bgcolor="white"> <struts:errors/> <struts:form action="logon.do" name="logonForm" type="org.apache.struts.example.LogonForm"/> <table border="0" width="100%"> <tr> <th align="right"> <struts:message key="prompt.username"/> </th> <td align="left"> <struts:text name="username" size="16"/> </td> </tr> <tr> <th align="right"> <struts:message key="prompt.password"/> </th> <td align="left"> <struts:password name="password" size="16"/> </td> </tr> <tr> <td align="right"> <struts:submit> <struts:message key="button.submit"/> </struts:submit> </td> <td align="right"> <struts:reset> <struts:message key="button.reset"/> </struts:reset> </td> </tr> </table> </struts:form> </body> </html> 下面的条目基于这个例子演C在Struts中处理表单的关键的特性: taglib指o告诉JSP面~译器从哪里扑ֈStruts标记库的 标记库描q符 。在q种情况下,我们使用struts作ؓ前缀来标识来自这个库中的标记Q但是可以用Q何你想用的前~?nbsp; q个面使用了几?nbsp;message 标记来从一个包含有q个应用E序所有资源的 MessageResources 对象中查扑֛际化的消息字W串。ؓ了让q个面能够工作Q以下的消息关键字必dq些资源中被定义Q?nbsp; logon.title - 注册面的标?nbsp; prompt.username - 一?nbsp;“Username:?nbsp;提示字符?nbsp; prompt.password - 一?nbsp;“Password:?nbsp;提示字符?nbsp; button.submit - “Submit”按钮的标签 button.reset - “Reset”按钮的标签 当用h册时Q应用程序可以在用户的session中保存一?nbsp;Locale 对象。这?nbsp;Locale 用来选择适当语言的消息。这使得l用户一个切换语a的可选项实现h变的Ҏ?nbsp;-- 仅仅改变保存?nbsp;Locale 对象Q所有的消息׃自动切换?nbsp; errors 标记昄׃个商业逻辑lg保存的Q何出错消息,或者如果没有出错消息保存就什么都没有。这个标记将在下面做深入的描q?nbsp; form 标记Z指定的属性对一个HTML <form> 元素q行处理。它也将所有在q个表单中的字段与一个保存在关键?nbsp;logonForm 下的session范围的FormBean相关联。这个bean用来为所有的h与bean中的属性名匚w的名字的输入字段提供初始倹{如果适当的bean没有扑ֈQ一个新的bean会被自动徏立,使用指定的Javacd?nbsp; text 标记对一个类型ؓ“text”的HTML <input> 元素q行处理。在q种情况下,占据览器屏q的字符位置的数字也被指定。当面被执行时Q是相对应的bean?nbsp;username 属性的当前|也就?nbsp;getUsername() 的返回|?nbsp; password 标记使用ҎcM。不同之处是当用h入他们的口o时浏览器回应星号字W,而不是输入倹{?nbsp; submit ?nbsp;reset 标记在表单低部生成相应的按钮。每个按钮的文本标签使用 message 标记建立Q同时带有提C,q样q些值就是国际化的?nbsp; 3.3.2 输入字段cd支持 Struts为所有以下类型的输入字段定义了标讎ͼ带有与其相应的参考信息的联接?nbsp; checkboxes hidden 字段 password 输入字段 radio 按钮 reset 按钮 select 列表和嵌入的 options submit 按钮 text 输入字段 textareas 在所有情况下Q一个字D|记都必须嵌套在一?nbsp;form 标记中,q样字段才知道用哪个bean来初始化昄的倹{?nbsp; 3.3.3 其它有用的表C标?BR>在Struts的标记库中有几个其它的标记对于徏立用L面是有帮助的Q?nbsp; enumerate Z个指定集合的每个元素重复一ơ标CQ可以是一个EnumerationQ一个HashtableQ一个Vector或一个对象数l)?nbsp; getProperty 从指定的bean中得到指定的属性,q且在本面的其余部分作Z个page范围的bean存在。这是访问一个被 enumerate 使用的集合的方便的方法?nbsp; ifAttributeExists 只有在一个指定的属性存在于一个指定的范围中时才对标记体求倹{?nbsp; ifAttributeMissing 只有在一个指定的属性不存在于一个指定的范围中时才对标记体求倹{?nbsp; ifParameterEquals 只有在一个指定的h参数h一个指定的值时才对标记体求倹{?nbsp; ifParameterNotEquals 只有在一个指定的h参数不具有一个指定的值或者不存在时才ҎC求倹{?nbsp; ifParameterNotNull 只有在一个指定的h参数包含在这个请求中q且长度大于0时才ҎC求倹{?nbsp; ifParameterNull 只有在一个指定的h参数不包含在q个h中或者长度等?时才ҎC求倹{?nbsp; iterate Z个指定集合中的每个元素重复一ơ标CQ可以是一个CollectionQ一个IteratorQ一个MapQ或者一个对象数l)。这个标记在Java2环境中代替了 enumerate 标记?nbsp; link 生成一个超联接Q当没有cookie支持时自动应用URL~程来维护session状态?nbsp; parameter 处理指定h参数的|适当地过滤HTML中有Ҏ含义的字W?nbsp; property 昄一个表单中命名的bean属?nbsp;-- 在属性应该是只读时用这个标记而不?nbsp;text 标记?nbsp; 3.3.4 自动表单验证 除了上面描述的表单和bean的交互外Q如果你的bean知道怎样验证它接收的输入字段QStrutsq提供一U附加的机制。ؓ了利用这个特性,使你的beancd?nbsp;ValidatingActionForm 接口Q而不?nbsp;ActionForm 接口。一?nbsp;ValidatingActionForm 增加了一个附加的Ҏ{Q?nbsp; public String[] validate() 对于一个被controller servlet在bean属性已l组装但是在相应的行为类?nbsp;perform() Ҏ被调用之前调用的ҎQvalidate() Ҏ有以下可选项Q?nbsp; 执行适当的验证发现没有错?nbsp;-- q回 null 或者一个非0长度字符串数l,q且controller servletl调用适当?nbsp;Action cȝ perform() Ҏ?nbsp; 执行适当的验证发现有错误 -- q回一个内容ؓ应该被显C的出错消息关键字(q入应用E序的MessageResources 包)的字W串数组。controller servlet作为适合?nbsp;<struts:errors> 标记使用的请求属性保存这个数l,q且控刉定向回输入表单(p?nbsp;ActionMapping ?nbsp;inputForm 属性标识)?nbsp; 正如以前提到的,q个Ҏ完全是可选的。如果你的form bean 仅仅实现?nbsp;ActionForm 接口Qcontroller servlet假设Q何请求的验证由actioncd成?nbsp; 3.4 其它的表C技?BR>管你的应用E序的外表和感觉可以完全Z标准的JSP能力和Struts的定制标记库构徏Q你也应该考虑展开其它改进lg重用、减管理负担或者减出错的技术。在下面的部分讨论几个可选的技术?nbsp; 3.4.1 特定于应用程序的定制标记 在用Struts库提供的定制标记之外Q很Ҏ建立特定于你创徏的应用程序的标记来帮助徏立用L面。Struts包括的例子程序用建立以下仅用于实现这个应用程序的标记演示了这个原则: checkLogon - 查一个特D的会话对象的存在,如果不存在将控制重定向到注册面。这是用来捕捉这L情况Q用户在你的应用E序执行的中间把一个页面做成书{ƈ且试图蟩q注册,或者用L会话时?nbsp; linkSubscription - Z个详l的定单面生成一个超联接Q它需要的d键字gZ个请求属性传递。这在列Z一个用L关的定单q提供编辑或删除定单的联接时使用?nbsp; linkUser - Z个用L一个具体的面生成一个超联接Q它它需要的d键字gZ个请求属性传递?nbsp; q些标记的源代码?nbsp;src/example 目录中,在包 org.apache.struts.example 里,q带有一些其它的用在q个应用E序中的JavacR?nbsp; 3.4.2 有包含文件的面lg 在一个JSP文gQ包含定制标记和beans用来讉Kh的动态数据)中创建完整的表示是一U非常普通的设计ҎQ在Struts包括的例子程序中被采用。然而很多应用程序要求在单独一个页面中昄你的应用E序的多个逻辑上独立的部分?nbsp; 举例来说Q一个入口应用程序可以在入口的主面上有一些或者全部以下的功能Q?nbsp; 讉Kq个入口的一个搜索引擎?nbsp; 一个或更多的“提供新闠Z的昄Q含有按照用L注册信息定制的感兴趣的标题?nbsp; 讉K与这个入口相关的讨论的主题?nbsp; 如果你的入口提供免费邮g帐号Q还要有一个“邮件等待”的提示?nbsp; 如果你能够将工作划分开Q分配不同的开发者去做不同的片段Q那么这个站点不同片D늚开发就会更加简单。然后,你可以用JSP技术的 include 能力来将q些片段l合q一个单独的面。有两种 include 可用Q依赖于你希望输出的l合发生在什么时_ include 指o Q?lt;%@ include file="xxxxx" %>Q在JSP面被编译时处理。它用于包括不需要在h时改变的HTML代码。它把包括进来的文本当作静态文本,很象C或C++中的 #include 指o?nbsp; include 行ؓ Q?lt;jsp:include page="xxxxx" flush="true" />Q在h时处理,q且是由服务器透明处理。这意味着你可以通过把它嵌套在一个类似ifParameterEquals的标C有条件地执行include ?nbsp; 3.4.3 囄处理lg 一些应用程序要求动态生成图片,p一个股市报告站点的h图一栗通常使用两种不同的方法来实现q个需求: 处理一个执行一个servleth的URL的超联接。这个servlet用一个图象库来生成图片,讄适当的contentcdQ例?nbsp;image/gifQ,q且图片的字节发送回览器。浏览器׃象从一个静态文件中接收到的一hC图片?nbsp; 处理HTML代码需要下载一个创求的图象的Java applet。你可以通过为在处理的代码中的这个applet讄适当的初始化参数配置q个图象Q或者你可以让这个applet与服务器建立自己联接来接收这些参数?nbsp; 4. 创徏Controllerlg 4.1 概述 现在我们理解了怎样构造你的应用程序的Model和ViewlgQ现在是集中?nbsp;Controller lg的时候了。Struts包括一个实现映一个请求URIC个行为类的主要功能的servlet。因此你的与Controller有关的主要责LQ?nbsp; 为每一个可能接收的逻辑h写一?nbsp;Action c(也就是,一?nbsp;Action 接口的实玎ͼ 写一个定义类名和与每个可能的映射相关的其它信息的 ActionMapping c(也就是,一?nbsp;ActionMapping 接口的实玎ͼ 写行为映配|文Ӟ用XMLQ用来配|controller servlet?nbsp; Z的应用程序更新web应用E序展开描述W文Ӟ用XMLQ用来包括必需的Strutslg?nbsp; l你的应用程序添加适当的Strutslg?nbsp; 4.2 Actionc?BR>Action 接口定义一个单一的必ȝ一?nbsp;Action cd现的ҎQ就象下面这P public ActionForward perform(ActionServlet servlet, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException; 一?nbsp;Action cȝ目标是处理这个请求,然后q回一个标识JSP面?nbsp;ActionForward 对象Q控制应该重定向q个JSP面以生成相应的响应。在 Model 2 设计模式中,一个典型的 Action cd在它?nbsp;perform() Ҏ中实C面的逻辑Q?nbsp; 验证用户session的当前状态(例如Q检查用户已l成功地注册Q。如?nbsp;Action cd现没有注册存在,h应该重定向到昄用户名和口o用于注册的JSP面。应该这样做是因为用户可能试图从“中间”(也就是,从一个书{)q入你的应用E序Q或者因为session已经时q且servlet容器创徏了一个新的session?nbsp; 如果验证q没有发生(׃使用一个实?nbsp;ValidatingActionForm 接口的form beanQ,验证q个 form bean 的属性是必须的。如果发C个问题,当作一个请求属性保存合适的出错信息关键字,然后控刉定向回输入表单这样错误可以被U正?nbsp; 执行要求的处理来处理q个hQ例如在数据库里保存一行)。这可以用嵌?nbsp;Action cLw的代码来完成,但是通常应该调用一个商业逻辑bean的一个合适的Ҏ来执行?nbsp; 更新用来创Z一个用L面页面的服务器端对象Q典型情况下是request范围或session范围beansQ定义你需要在多长旉内保持这些项目可获得Q?nbsp; q回一个标识生成响应的JSP面的适当?nbsp;ActionForward 对象Q基于新q更新的beans。典型情况下Q你通过在你接收到的 ActionMapping 对象Q如果你使用一个局部于与这个映上的逻辑名)或者在controller servlet 本nQ如果你使用一个全局于应用程序的逻辑名)上调?nbsp;findForward() 得到一个对q样一个对象的引用?nbsp; 当ؓ Action cȝE时要记住的设计要点包括以下q些Q?nbsp; controller servlet仅仅创徏一个你?nbsp;Action cȝ实例Q用于所有的h。这样你需要编写你?nbsp;Action cM其能够在一个多U程环境中正运行,p你必d全地~写一个servlet?nbsp;service() Ҏ一栗?nbsp; 帮助U程安全~程的最重要的原则就是在你的 Action cM仅仅使用局部变量而不是实例变量。局部变量创Z一个分配给Q由你的JVMQ每个请求线E的栈中Q所以没有必要担心会׃n它们?nbsp; 管不应该,代表你的pȝ中Model部分的的beans仍有可能抛出q例。你应该在你?nbsp;perform() Ҏ的逻辑中捕捉所有这Lq例Qƈ且通过执行以下语句它们记录在应用E序的日志文件中Q包括相应的栈跟t信息)Q?nbsp; servlet.log("Error message text", exception); 作ؓ一个通用的规则,分配很少的资源ƈ在来自同一个用P在用Lsession中)的请求间保持它们会导致可伸羃性的问题。你应该在将控制重定向到适当的Viewlg前努力释放这L资源Q例如数据库联接Q?nbsp;-- 甚至在你调用的一个bean抛出了一个违例时?nbsp; 另外Q你会惌防止出现非常大的 Action cR最单的实现途径是将你的功能逻辑嵌入?nbsp;Action cLw,而不是将其写在独立的商业逻辑beans中。除了 Action c难于理解和l护外,q种Ҏ也得难于重用这些商业逻辑代码Q因Z码被嵌入C个组ӞAction c)中ƈ被捆l运行于web应用E序环境中?nbsp; 包括在Struts中的例子E序某种E度上g怺q个设计原则Q因为商业逻辑本n是嵌入到 Action cM的。这应该被看作是在这个样本应用程序设计中的一个bugQ而不是一个Struts体系l构中的固有Ҏ,或者是一个值得仿效的方法?nbsp; 4.3 ActionMapping实现 Z成功地运行,Struts的controller servlet需要知道关于每个URI该怎样映射C个适当?nbsp;Action cȝ几g事。需要了解的知识装在一个叫?nbsp;ActionMapping 的Java接口中,它有以下属性: actionClass - 用于q个映射?nbsp;Action cd整的Javacd。第一ơ一个特定的映射被用,一个这个类的实例将被创建ƈZ后重用而保存?nbsp; formAttribute - session范围的bean的名字,当前的这个映的 ActionForm 被保存在q个bean之下。如果这个属性没有被定义Q没?nbsp;ActionForm 被用?nbsp; formClass - 用于q个映射?nbsp;ActionForm cd整的Javacd。如果你在用对form beans的支持,q个cȝ一个实例将被创建ƈ保存Q在当前的用户会话中Q?nbsp; path - 匚w选择q个映射的请求的URI路径。看下面如何匚w的例子?nbsp; Struts在一个叫?nbsp;ActionMappingBase 的类中包括了一?nbsp;ActionMapping 接口的方便的实现。如果你不需要ؓ你自q映射定义M附加的属性,管把这个类作ؓ你的 ActionMapping cd了,向下面部分描述的那样配|。然而,定义一?nbsp;ActionMapping 实现Q多半是扩展 ActionMappingBase c)来包含附加的属性也是可能的。controller servlet知道怎样自动配置q些定制属性,因ؓ它用Struts的Digester模块来读配置文g?nbsp; 包括在Struts的例子程序中Q这个特性用来定义两个附加的属性: failure - 如果ActioncL到它接收的输入字段的一些问题,控制应该被重定向到的上下文相关的URI。典型情况下是请求发向的JSP面名,它将引v表单被重新显C(包含Actionc设|的出错消息和大部分最q的来自ActionForm bean的输入|?nbsp; success - 如果ActioncL功执行请求的功能Q控制应该被重定向到的上下文相关的URI。典型情况下是准备这个应用程序的会话的下一个页面的JSP面名?nbsp; 使用q两个额外的属性,例子E序中的 Action cd乎完全独立于面设计者用的实际的JSP面名。这个页面可以在重新设计时被重命名,然而几乎不会媄响到 Action cLw。如果“下一个”JSP面的名字被编码到 Action cMQ所有的q些cM需要被修改?nbsp; 4.4 Action映射配置文g controller servlet怎样知道你想要得到的映射Q写一个简单地初始化新?nbsp;ActionMapping 实例q且调用所有适当的setҎ的小的JavacL可能的(但是很麻烦)。ؓ了ɘq个处理单些QStruts包括一个Digester模块能够处理一个想得到的映的ZXML的描qͼ同时创徏适当的对象。看 API 文档 以获得关于Digester更多的信息?nbsp; 开发者的责Q是创Z个叫?nbsp;action.xml 的XML文gQƈ且把它放在你的应用程序的WEB-INF目录中。(注意q个文gq不需?nbsp;DTDQ因为实际用的属性对于不同的用户可以是不同的Q最外面的XML元素必须?lt;action-mappings>Q在q个元素之中是嵌入的0个或更多?nbsp;<action> 元素 -- 每一个对应于你希望定义的一个映?nbsp; 来自例子E序?nbsp;action.xml 文g包括“注册”功能的以下映射条目Q我们用来说明这个需求: <action-mappings> <forward name="logon" path="/logon.jsp"/> <action path="/logon" actionClass="org.apache.struts.example.LogonAction" formAttribute="logonForm" formClass="org.apache.struts.example.LogonForm" inputForm="/logon.jsp"> <forward name="success" path="/mainMenu.jsp"/> </action> </action-mappings> p你所看到的,q个映射匚w路径 /logon Q实际上Q因Z子程序用扩展匹配,你在一个JSP面指定的请求的URIl束?logon.doQ。当接收C个匹配这个\径的hӞ一?nbsp;LogonAction cȝ实例被创徏Q仅仅在W一ơ)q被使用。controller servlet在关键?nbsp;logonForm 下查找一个session范围的beanQ如果需要就为指定的cd建ƈ保存一个bean?nbsp; q个 action 元素也定义了一个逻辑名“success”,它在 LogonAction cM被用来标识当一个用h功注册时使用的页面。象q样使用一个逻辑名允许将 action c隔MM׃重新设计位置而可能发生的面名改变?nbsp; q是W二个在M action 之外宣告?nbsp;forward 元素Q这样它可以被所有的action全局地获得。在q个情况下,它ؓ注册面定义了一个逻辑名。当你调?nbsp;mapping.findForward() 时在你的 action 代码中,Struts首先查找q个action本地定义的逻辑名。如果没有找刎ͼStruts会自动ؓ你查扑օ局定义的逻辑名?nbsp; 4.5 Web应用E序展开描述W?BR>讄应用E序最后的步骤是配|应用程序展开描述W(保存在文件WEB-INF/web.xml中)以包括所有必需的Strutslg。作Z个指南用例子程序的展开描述W,我们看到下面的条目需要被创徏或修攏V?nbsp; 4.5.1 配置Action Servlet实例 d一个条目定义action servlet本nQ同时包括适当的初始化参数。这样一个条目看h象是q样Q?nbsp; <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-p aram> <param-name>application</param-name> <param-value>org.apache.struts.example.ApplicationResources</param-value> </init-param> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/action.xml</param-value> </init-param> <init-param> <param-name>debug</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>mapping</param-name> <param-value>org.apache.struts.example.ApplicationMapping</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> controller servlet支持的初始化参数在下面描qͼ拯?nbsp;ActionServlet cȝ Javadocs 。方括号描述如果你没有ؓ那个初始化参数提供一个值时假设的缺省倹{?nbsp; application - 应用E序资源包基cȝJavacd。[NONE]. config - 包含配置信息的XML资源的上下文相关的\径。[/WEB-INF/action.xml] debug - q个servlet的调试别,它控制记录多信息到日志中。[0] digester - 我们?nbsp;initMapping() 中利用的Digester的调试别,它记录到System.out而不是servlet的日志中。[0] forward - 使用的ActionForward实现的Javacd。[org.apache.struts.action.ActionForward] mapping - 使用的ActionMapping实现的Javacd。[org.apache.struts.action.ActionMappingBase] nocache - 如果讄?nbsp;trueQ增加HTTP头信息到所有响应中使浏览器对于生成或重定向到的M响应不做~冲。[false] null - 如果讄?nbsp;trueQ设|应用程序资源得如果未知的消息关键字被使用则返?nbsp;null。否则,一个包括不Ƣ迎的消息关键字的出错消息将被返回。[true] 4.5.2 配置Action Servlet映射 有两U通常的方法来定义被controller servlet处理的URL -- 前缀匚w和扩展匹配。每U方法的一个适当的映条目将在下面被描述?nbsp; 前缀匚w意思是你想让所有以一个特D值开_在上下文路径部分之后Q的URL传递给q个servlet。这样一个条目看h可以象是q样Q?nbsp; <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>/execute/*</url-pattern> </servlet-mapping> 它意味着一个匹配前面描q的 /logon 路径的请求的URL看v来象是这P http://www.mycompany.com/myapplication/execute/logon q里 /myapplicationis 是你的应用程序展开所在的上下文\径?nbsp; 另一斚wQ扩展映基于URL以一个跟着定义的一l字W的句点l束的事实而将URL匚w到action servlet 。例如,JSP处理servlet映射?nbsp;*.jsp 模式q样它在每个JSP面h时被调用。ؓ了?nbsp;*.do 扩展Q它意味着“做某g事”)映射条目看v来应该象是这P <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> q且一个匹配以前描q的 /logon 路径的请求的URI可以看v来象是这P http://www.mycompany.com/myapplication/logon.do 4.5.3 配置Struts标记?BR>下一步,你必L加一个定义Struts标记库的条目。这个条目看h应该象是q样Q?nbsp; <taglib> <taglib-uri>/WEB-INF/struts.tld</taglib-uri> <taglib-location>/WEB-INF/struts.tld</taglib-location> </taglib> 它告诉JSPpȝ到哪里去找这个库的标记库描述W(在你的应用程序的WEB-INF目录Q而不是在外部互联|上的某个地方)?nbsp; 4.5.4 dStrutslgC的应用程序中 Z在你的应用程序运行时使用StrutsQ你必须?nbsp;struts.tld 文g拯C?nbsp;WEB-INF 目录Q将 struts.jar 文g拯C?nbsp;WEB-INF/lib ?nbsp; ]]> 学习springQ?/title> http://www.tkk7.com/happyfish/archive/2005/03/02/1619.html鱼?/dc:creator>鱼?/author>Wed, 02 Mar 2005 14:44:00 GMT http://www.tkk7.com/happyfish/archive/2005/03/02/1619.html http://www.tkk7.com/happyfish/comments/1619.html http://www.tkk7.com/happyfish/archive/2005/03/02/1619.html#Feedback 0 http://www.tkk7.com/happyfish/comments/commentRss/1619.html http://www.tkk7.com/happyfish/services/trackbacks/1619.html (1) spring下蝲包中doc目录下的MVC-step-by-step和sample目录下的例子都是比较好的spring开发的例子? (2) AppFuse集成了目前最行的几个开源轻量框架或者工?Ant,XDoclet,Spring,Hibernate(iBATIS),JUnit,Cactus,StrutsTestCase,Canoo's WebTest,Struts Menu,Display Tag Library,OSCache,JSTL,Struts ?BR> 通过AppFuse源代码来学习spring?BR> AppFuse|站Qhttp://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse (3)Spring 开发指?夏昕)Qhttp://www.xiaxin.net/Spring_Dev_Guide.rarQ?BR> 一本spring的入门书c?里面介绍了反转控制和依赖注射的概念,以及spring的bean理Qspring的MVCQspring和hibernteQiBatis的结合?BR> (4) spring学习的中文论?BR> SpringFramework中文论坛(http://spring.jactiongroup.net) Java视线论坛(http://forum.javaeye.com)的spring栏目 2、利用Spring框架~程Qconsole打印出log4j:WARN Please initialize the log4j system properlyQ?BR> 说明你的log4j.properties没有配置。请把log4j.properties攑ֈ工程的classpath中,eclipse的classpath为bin目录Q由于编译后src目录下的文g会拷贝到bin目录下,所以你可以把log4j.properties攑ֈsrc目录下?BR> q里l出一个log4j.properties的例子:
log4j.rootLogger=DEBUG,stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %5p (%F:%L) - %m%n
3、出?java.lang.NoClassDefFoundError? 一般情况下是由于你没有把必要的jar包放到lib中?BR> 比如你要采用spring和hibernateQ带事务支持的话Q,你除了spring.jar外还需要hibernat.jar、aopalliance.jar、cglig.jar、jakarta-commons下的几个jar包?BR> http://www.springframework.org/download.html下蝲spring开发包Q提供两Uzip?BR>spring-framework-1.1.3-with-dependencies.zip和spring-framework-1.1.3.zipQ我你下载spring-framework-1.1.3-with-dependencies.zip。这个zip解压~后比后者多一个lib目录Q其中有hibernate、j2ee、dom4j、aopalliance、jakarta-commons{常用包?BR> 4、java.io.FileNotFoundException: Could not open class path resource [....hbm.xml],提示找不到xml文gQ?BR> 原因一般有两个Q?BR> (1)该xml文g没有在classpath中? (2)applicationContext-hibernate.xml中的xml名字没有带包名。比如:
Qbean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"Q?BR>Qproperty name="dataSource"Q<ref bean="dataSource"/Q</propertyQ?BR>Qproperty name="mappingResources"Q?BR> QlistQ?BR> QvalueQUser.hbm.xmlQ?valueQ?BR> 错,改ؓQ? QvalueQcom/yz/spring/domain/User.hbm.xmlQ?valueQ?BR> Q?listQ?BR>Q?propertyQ?BR>Qproperty name="hibernateProperties"Q?BR>QpropsQ? Qprop key="hibernate.dialect"Q?net.sf.hibernate.dialect.MySQLDialect Q?propQ? Qprop key="hibernate.show_sql"QtrueQ?propQ? Q?propsQ? Q?propertyQ?BR>Q?beanQ?/TD>
5、org.springframework.beans.NotWritablePropertyException: Invalid property 'postDao' of bean classQ?BR> 出现异常的原因是在application-xxx.xml中property name的错误?BR> Qproperty name="...."Q?中name的名字是与bean的setҎ相关的,而且要注意大写?BR> 比如
public class PostManageImpl extends BaseManage implements PostManage { private PostDAO dao = null; public void setPostDAO(PostDAO postDAO){ this.dao = postDAO; } }
那么xml的定义应该是Q?BR>
Qbean id="postManage" parent="txProxyTemplate"Q?BR>Qproperty name="target"Q?BR> Qbean class="com.yz.spring.service.implement.PostManageImpl"Q?BR> Qproperty name="postDAO"Q<ref bean="postDAO"/Q</propertyQ??BR> Qproperty name="dao"Q<ref bean="postDAO"/Q</propertyQ??BR> Q?beanQ?BR>Q?propertyQ?BR>Q?beanQ?/TD>
6、Spring中如何实C务管理? 首先Q如果用mysqlQ确定mysql为InnoDBcd?BR> 事务理的控制应该放到商业逻辑层。你可以写个处理商业逻辑的JavaBeanQ在该JavaBean中调用DAOQ然后把该Bean的方法纳入spring的事务管理?BR> 比如Qxml文g定义如下Q?BR>
Qbean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"Q?BR>Qproperty name="transactionManager"Q<ref bean="transactionManager"/Q</propertyQ?BR>Qproperty name="transactionAttributes"Q?BR>QpropsQ?BR>Qprop key="save*"QPROPAGATION_REQUIREDQ?propQ?BR>Qprop key="remove*"QPROPAGATION_REQUIREDQ?propQ?BR>Qprop key="*"QPROPAGATION_REQUIREDQ?propQ?BR>Q?propsQ?BR>Q?propertyQ?BR>Q?beanQ?BR> Qbean id="userManage" parent="txProxyTemplate"Q?BR> Qproperty name="target"Q?BR> Qbean class="com.yz.spring.service.implement.UserManageImpl"Q?BR> Qproperty name="userDAO"Q<ref bean="userDAO"/Q</propertyQ?BR> Q?beanQ?BR> Q?propertyQ?BR>Q?beanQ?/TD>
com.yz.spring.service.implement.UserManageImpl是我们的实现商业逻辑的JavaBean。我们通过parent元素声明其事务支持?BR> 7、如何管理Spring框架下更多的JavaBeanQ?BR> JavaBean多Qspring配置文gp大,q样不易l护。ؓ了配置清晰Q我们可以将JavaBean分类理Q放在不同的配置文g中?应用启动时将所有的xml同时加蝲?BR> 比如Q?BR> DAO层的JavaBean攑ֈapplicationContext-hibernate.xml中,商业逻辑层的JavaBean攑ֈapplicationContext-service.xml中。然后启动类中调用以下代码蝲入所有的ApplicationContext?BR>
String[] paths = {"com/yz/spring/dao/hibernate/applicationContext-hibernate.xml", "com/yz/spring/service/applicationContext-service.xml"}; ctx = new ClassPathXmlApplicationContext(paths);
8、web应用中如何加载ApplicationContextQ?BR> 可以通过定义web.xmlQ由web容器自动加蝲?BR>
QservletQ?BR>Qservlet-nameQcontextQ?servlet-nameQ?BR>Qservlet-classQorg.springframework.web.context.ContextLoaderServletQ?servlet-classQ?BR>Qload-on-startupQ?Q?load-on-startupQ?BR>Q?servletQ?BR> Qcontext-paramQ?BR>Qparam-nameQcontextConfigLocationQ?param-nameQ?BR>Qparam-valueQ?WEB-INF/applicationContext-hibernate.xmlQ?param-valueQ?BR>Qparam-valueQ?WEB-INF/applicationContext-service.xmlQ?param-valueQ?BR>Q?context-paramQ?/TD>
9、在spring中如何配|的log4j? 在web.xml中加入以下代码即可?BR>
Qcontext-paramQ?BR>Qparam-nameQlog4jConfigLocationQ?param-nameQ?BR>Qparam-valueQ?WEB-INF/log4j.propertiesQ?param-valueQ?BR>Q?context-paramQ?/TD>
10、Spring框架入门的编E问题解决了Q我该如何更深地领会Spring框架呢? q两本书你该ȝ看。这两本书是由Spring的作者Rod Johnson~写的?BR>
Expert One on one J2EE Design and Development Expert One on one J2EE Development Without EJB
你也该看看martinfowler的Inversion of Control Containers and the Dependency Injection pattern?BR>
http://www.martinfowler.com/articles/injection.html
再好好研M下spring的文档?BR>
http://www.jactiongroup.net/reference/html/index.htmlQ中文版Q未全部译Q?/TD>
]]>
վ֩ģ壺
պAvĻþþ |
ձva߹ۿ |
ƷһI6 |
ҹƷƬѹۿ |
Ļ |
һ˾Ʒ |
ۺɫƵ߹ۿ |
Ů˱ͰúˬƵ |
ƷڵƵ
|
һƵ |
2019Ļ |
xxƵѹۿ |
߾ƷaaaƬ |
պAVһl |
Ʒ߹ۿ |
ŷղ߹ۿ |
AVƷɫ
|
ѹۿĻƷ |
һ |
ŷղvؼëƬ |
aɻ߹ۿ |
պƷһ |
þþƷA㽶 |
Ѻܻƺɫ߹ۿ |
ƵƷ |
Ļ˾Ʒһվ
|
Ƶ߹ۿƵ |
һ |
AV˾Ʒվ߲ |
ƷƬþ |
ҹ
|
av뾫Ʒվ
|
ˬˬƵ߹ۿ |
һaëһa˽ |
ŮˮƵwww |
ɫַ߹ۿ |
ձ岻aվ |
ĻӰ |
˾ƷѾþþþ
|
ɫͼɫС˵ |
˾Ʒԭ |