﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-水煮三国</title><link>http://www.blogjava.net/os586/</link><description>孤单是一个人的狂欢，狂欢是一群人的孤单</description><language>zh-cn</language><lastBuildDate>Mon, 04 May 2026 23:17:21 GMT</lastBuildDate><pubDate>Mon, 04 May 2026 23:17:21 GMT</pubDate><ttl>60</ttl><item><title>struts1.x中ActionError,ActionErrors的使用</title><link>http://www.blogjava.net/os586/archive/2009/08/01/289349.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Sat, 01 Aug 2009 03:02:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2009/08/01/289349.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/289349.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2009/08/01/289349.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/289349.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/289349.html</trackback:ping><description><![CDATA[
		<font face="Courier New">
				<font size="2">1.struts1.1中,actionError与actionMessage只能从配置资源中取key 即:<br /><br />new ActionError("user.name")从资源中得到key <br /><br />ActionErrors.add("username",new ActionError("user.name")); <br /><br />在jsp中使用时<?xml:namespace prefix = html /?><html:errors property="username"></html:errors> 只有这样才会正确显示. <br /><br />前提条件是validate设置为false,input需要设置一下. 我不太喜欢actionForm当中的validate方法,业务逻辑或者是验证逻辑写在这里感觉不爽 <br /><br />2.如果不想从properties中取得key,即不想配置,则使用 <br /><br />ActionError("test",false),此处表示不启用配置资源中的key <br /><br />这个方法在1.1.之前没有 <br /><br />3.另摘抄于网络一文:如下<br /><br />在Struts里进行表单验证和业务逻辑验证真是一个很麻烦的事情，看书、上网了解了ActionMessage与ActionErrors的基本知识，可以拿来书上或网上的例程来试试。错、错，又错，还是有错，我说是的我的程序结果有错误，而不是真的显示出了验证错误信息。 怎么回事呢？经过一天的不断测试，成功了... 经验就是： 在ActionFrom中使用ActionErrors 错误信息添加用add(“error_key“,new ActionError(“error.input.name“)) jsp中使用显示错误。<html:errors property="error_key"></html:errors> 在Actoin中使用ActionMessages 错误信息添加使用add(“error_key“,new ActioinMessage(“errors.loginerror“)) <html:messages id="errors" message="true"><font color="red"><?xml:namespace prefix = bean /?><bean:write name="errors"></bean:write></font></html:messages>jsp中使用来显示错误。不要管id和name中是什么，只要两者一样，就会显示所有的ActionMessages出来 <html:messages id="err" message="true">message属性为true，显示ActionMessages中所有信息，为false显示ActionErrors中所有信息 <br /><font color="red"><bean:write name="err"></bean:write></font></html:messages><br />============================================= HTML:MESSAGES,HTML:ERRORS,用法2007-08-12 22:09=======<html:messages>============ Action 中 : ActionMessages message = new ActionMessages(); message.add(" 消息句柄 ",new ActionMessage(" 资源文件中 Key 值 ",String 类型描述信息 )); this.addMessages(request,message); return ActionForward; JSP 页面中 : <html:messages id=" 指定使用消息的标识 " property=" 消息句柄 " message="true|false"><bean:write name=" 以上所指 ID 标识 "></bean:write></html:messages>==========<html:errors>============== Action 中 : ActionMessages message = new ActionMessages(); message.add(" 消息句柄 ",new ActionMessage(" 资源文件中 Key 值 ",String 类型描述信息 )); this.saveErrors(request,message); return ActionForward; JSP 页面中 : <html:errors property=" 消息句柄 "></html:errors>如果Action中这样设定(false)，页面的提示信息将不从资源文件里读取: ActionMessages message = new ActionMessages(); message.add("消息句柄",new ActionMessage("String类型描述信息",false)); this.saveErrors(request,message); return ActionForward; JSP页面: <html:errors></html:errors>或<html:errors property="消息句柄"></html:errors></html:errors></html:messages></font>
		</font>
<img src ="http://www.blogjava.net/os586/aggbug/289349.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2009-08-01 11:02 <a href="http://www.blogjava.net/os586/archive/2009/08/01/289349.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JdbcTemplate 返回对象</title><link>http://www.blogjava.net/os586/archive/2008/07/17/215392.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 17 Jul 2008 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2008/07/17/215392.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/215392.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2008/07/17/215392.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/215392.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/215392.html</trackback:ping><description><![CDATA[JdbcTemplate模板使用起来还是非常方便的，运用RowMapperResultReader比起以往经常用Map.get()来字段值，可谓是省很多的力.<br /><br /><br /><br /><img src ="http://www.blogjava.net/os586/aggbug/215392.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2008-07-17 10:13 <a href="http://www.blogjava.net/os586/archive/2008/07/17/215392.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]FindBugs:Eclipse插件</title><link>http://www.blogjava.net/os586/archive/2007/11/22/162461.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 22 Nov 2007 12:47:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/11/22/162461.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/162461.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/11/22/162461.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/162461.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/162461.html</trackback:ping><description><![CDATA[
		<p>官方网站：<a href="http://findbugs.sourceforge.net/">http://findbugs.sourceforge.net/</a><br />Eclipse插件：<a href="http://findbugs.sourceforge.net/downloads.html">http://findbugs.sourceforge.net/downloads.html</a></p>
		<p>　　<strong>插件管理技巧</strong><br /><br />　　提示：新下载的插件PlugIn一定不要都放在原始的Eclipse目录下去。<br /></p>
		<ol>
				<li>前提是你已经安装好了Eclipse工具了，比如安装在E:\OpenSource\Eclipse\目录下，以下这个目录以%ECLIPSE_HOME%来进行表示； 
</li>
				<li>此时默认的插件是在%ECLIPSE_HOME%\plugins目录中的； 
</li>
				<li>在%ECLIPSE_HOME%下建立一个PlugInsNew的目录；<br />比如：E:\OpenSource\Eclipse\PlugInsNew\ 
</li>
				<li>你下载了个新的插件，比如叫做：XYZ <br />　那么就在%ECLIPSE_HOME%\PlugInsNew\目录下建立XYZ目录，目录里面是eclipse目录，eclipse目录包含有features与plugins两个子目录；结构如下图所示：<br /><br />　　<img height="410" src="http://www.webdn.com/web_file/program/jsp/060208087/images/xq50b3j256x9.jpg" width="220" border="0" /><br /></li>
				<li>把下载的新插件的文件放在以下相应目录中 <br />%ECLIPSE_HOME%\PlugInsNew\XYZ\eclipse\features<br />%ECLIPSE_HOME%\PlugInsNew\ XYZ\eclipse\plugins<br /></li>
				<li>建立相关的.link的文件 <br />然后在%ECLIPSE_HOME%\links目录里建立一个XYZ.link的文件 <br />内容如是：path=E:/OpenSource/Eclipse/PlugInsNew/XYZ就一行这样的路径指示而已。 <br />当然，采用相对路径来表示可能更直观一些，方便进行文件整体移动和小组全部成员的共享命名用，省得移动后要改动Link文件里的绝对路径而费心费力。直接拷贝过去就可以使用。 <br />即XYZ.link文件的内容如是：path=../PlugInsNew/XYZ <br />这样，如果你下载了多个插件就可以如法炮制建立多个Link文件，想加载哪个插件就把哪个插件的Link文件放到%ECLIPSE_HOME%\links的目录中即可，使用与管理都很方便，建议千万不要放在默认的安装目录中； <br />如果你的%ECLIPSE_HOME%与此不同，请修改XYZ.link文件里的路径<br /></li>
				<li>删除，关闭Eclipse <br />删除%ECLIPSE_HOME%\links\XYZ.link文件即可 <br />删除%ECLIPSE_HOME%\PlugInsNew\XYZ整个目录及文件<br /></li>
				<li>重新启动Eclipse即可 </li>
		</ol>
		<p>　　<strong>使用</strong><br /><br />　　重新启动Eclipse后，在Help =&gt; About Eclipse SDK =&gt; Plug-in Details你可以看到由“FindBugs Project”提供的“FindBugs Plug-in”版本0.0.17插件，如下图所示：<br /><br />　　<img height="439" src="http://www.webdn.com/web_file/program/jsp/060208087/images/ifrs62d7h0jt.jpg" width="520" border="0" /><br /><br />　　<strong>FindBugs的使用方法</strong><br /><br />　　FindBugs是一个可以在Java程序中发现Bugs的程序。 <br /><br />　　它是专门用来寻找处于“Bug Patterns”列表中的代码的。 <br /><br />　　Bug Patterns指很有可能是错误的代码的实例。<br /><br />　　目前FindBugs最高版本0.9.4，不过更新速度很快的，你应当经常上去看看是否有新版本发布。Eclipse plugin for FindBugs最高版本0.0.17。<br /><br />　　<strong>系统要求</strong><br /><br />　　使用FindBugs至少需要JDK1.4.0以上版本，FindBugs是平台独立的，可以运行于GNU/Linux、Windows、MacOS X　等平台上。<br /><br />　　运行FindBugs至少需要有256 MB内存，如果你要分析一个很大的项目，那就需要更加多的内存了。<br /><br />　　FindBugs独立运行和与Ant结合的详细操作就不介绍了，可以看官方的文档<a href="http://findbugs.sourceforge.net/manual/" target="_blank"><u>http://findbugs.sourceforge.net/manual/</u></a><br /><br />　　独立运行的效果图如下：<br /><br />　　<img height="509" src="http://www.webdn.com/web_file/program/jsp/060208087/images/622m736481l0.jpg" width="554" border="0" /><br /></p>
		<p>　　本文主要介绍在Eclipse中使用的情况<br /><br />　　打开Bug Details视图<br /><br />　　Windows =&gt; Show View =&gt; Other… =&gt; FindBugs =&gt; BugDetails<br /><br />　　<img height="414" src="http://www.webdn.com/web_file/program/jsp/060208087/images/41175t939i9s.jpg" width="296" border="0" /><br /><br />　　在Package Explorer或Navigator视图中，选中你的Java项目，右键，可以看到“Find Bugs”菜单项，子菜单项里有“Find Bugs”和“Clear Bug Markers”两项内容，如下图所示：<br /><br />　　<img height="459" src="http://www.webdn.com/web_file/program/jsp/060208087/images/2ezt0h504fus.jpg" width="309" border="0" /><br /><br />　　我们建立一个简单的测试文件Test.java 内容如下： <br /><br /></p>
		<pre class="code">public class Test { private String[] name; public String[] getName() { return name; } public void setName(String[] name) { this.name = name; } } </pre>
		<p>
				<br />　　我们点中“Find Bugs”，运行时会出现如下进度框：<br /><br />　　运行结束后可以在Problems中看到增加了如下的警告信息内容<br /><br />　　FindBugs运行后的警告信息内容不仅在Problems视图中显示，而且将标记在源代码标记框中，在源代码编辑器中我们可以看到警告标识，如下图： <br /><br />　　当光标指向你的警告信息的代码上面时，就会有相应的错误提示信息，与Eclipse本身的错误或警告信息提示类似。 <br /><br />　　选中Problems视图里出现的相应问题，就会在代码编辑器里切换到相应的代码上去，方便根据相应的提示信息进行代码的修改。 <br /><br />　　<img height="193" src="http://www.webdn.com/web_file/program/jsp/060208087/images/nrs082xwhx4h.jpg" width="554" border="0" /><br /><br />　　在Problems视图里，选中相应的问题条目，右键，在弹出的菜单中，可以看到“Show Bug Details”，如下图所示：<br /><br />　　<img height="246" src="http://www.webdn.com/web_file/program/jsp/060208087/images/jn3j1644io3y.jpg" width="146" border="0" /><br /><br />　　点中它，会切换到Bug Details视图上去，显示更加详细的提示信息。<br /><br />　　当然，在代码编辑窗口中，点击带有警告提示信息的图标时，也会自动切换到Bud Details窗口去，查看详细的警告信息，如下图所示。<br /><br />　　<img height="160" src="http://www.webdn.com/web_file/program/jsp/060208087/images/t4h5k4q5i5sx.jpg" width="423" border="0" /><br /><br />　　根据这里详细的信息，你可以得到FindBugs为什么会对你的代码报警告信息，及相应的处理办法，根据它的提示，你可以快速方便地进行代码修改。<br /><br />　　<img height="193" src="http://www.webdn.com/web_file/program/jsp/060208087/images/71ll9wu3h2c6.jpg" width="554" border="0" /><br /><br />　　根据提示，我们将代码修改成如下，再运行就不会报有警告信息了。<br /></p>
		<pre class="code">public class Test { private String[] name; public String[] getName() {     String[] temp = name; return temp; } public void setName(String[] name) {     String[] temp = name; this.name = temp; } } </pre>
		<p>　　<strong>配置FindBugs</strong><br /><br />　　选择你的项目，右键 =&gt; Properties =&gt; FindBugs =&gt;<br /><br />　　<img height="454" src="http://www.webdn.com/web_file/program/jsp/060208087/images/w9782i23chf6.jpg" width="553" border="0" /><br /><br />　　可以配置的信息包括如上图所示的四个选项的相关设置：<br /></p>
		<ol>
				<li>Run FindBugs Automatically开关 <br /><br />当此项选中后，FindBugs将会在你修改Java类时自动运行，如你设置了Eclipse自动编译开关后，当你修改完Java文件保存，FindBugs就会运行，并将相应的信息显示出来。 <br /><br />当此项没有选中，你只能每次在需要的时候自己去运行FindBugs来检查你的代码。 <br /><br /></li>
				<li>Minimum priority to report选择项 <br /><br />这个选择项是让你选择哪个级别的信息进行显示，有Low、Medium、High三个选择项可以选择，很类似于Log4J的级别设置啦。 比如： <br /><br />你选择了High选择项，那么只有是High级别的提示信息才会被显示。 <br /><br />你选择了Medium选择项，那么只有是Medium和High级别的提示信息才会被显示。 <br /><br />你选择了Low选择项，那么所有级别的提示信息都会被显示。<br /><br /></li>
				<li>Enable bug categories选择项 <br /><br />在这里是一些显示Bug分类的选择： <br /><br />Correctness关于代码正确性相关方面的 <br /><br />Performance关于代码性能相关方面的 <br /><br />Internationalization关于代码国际化相关方面的 <br /><br />Multithreaded correctness关于代码多线程正确性相关方面的<br /><br />Style关于代码样式相关方面的<br /><br />Malicious code vulnerability关于恶意破坏代码相关方面的 <br /><br />比如：如果你把Style的检查框去掉不选择中它，那么与Style分类相关的警告信息就不会显示了。其它的类似。<br /><br /></li>
				<li>Select bug patterns to check for选择项 <br /><br />在这里你可以选择所要进行检查的相关的Bug Pattern条目 <br /><br />可以从Bug codes、Detector name、Detector description中看到相应的是要检查哪些方面的内容，你可以根据需要选择或去掉相应的 检查条件。 </li>
		</ol>
		<p>　　<strong>总结 </strong><br /><br />　　此插件的功能很不错，可以帮助我们提升Java代码的编写能力，写出更加安全可靠的代码。建议使用或加在Ant里进行持续构建。 <br /><br />　　现在，你可以马上拿出你已经开发的一个项目，检查一下你的代码有没有问题了</p>
<img src ="http://www.blogjava.net/os586/aggbug/162461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-11-22 20:47 <a href="http://www.blogjava.net/os586/archive/2007/11/22/162461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BCP 数据导入导出时经常遇见的错误</title><link>http://www.blogjava.net/os586/archive/2007/08/07/135077.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 07 Aug 2007 13:25:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/08/07/135077.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/135077.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/08/07/135077.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/135077.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/135077.html</trackback:ping><description><![CDATA[
		<p>
				<font size="2">ct_connect(): network packet layer: internal net library error: Net-Lib protocol driver call to connect two endpoints failed<br />Establishing connection failed.<br />无法连接远程服务器</font>
		</p>
		<p>
				<font size="2">cs_convert: cslib user api layer: common library error: The conversion/operation was stopped due to a syntax error in the source field.<br />CSLIB Message: - L0/O0/S0/N36/1/0:<br />导入表对应的列数量不正确</font>
		</p>
		<p>
				<font size="2">cs_convert: cslib user api layer: common library error: The conversion/operation was stopped due to a syntax error in the source field.<br />导入数据存在自增长列，但数据源不存在自增长列</font>
		</p>
		<p>
				<font size="2">blk_rowxfer(): blk layer: internal BLK-Library error: Data truncated while doing local character set conversion. col = 3<br />导入表对应的字段长度不足</font>
		</p>
		<p>
				<font size="2">ct_sendpassthru(): network packet layer: internal net library error: Net-Library operation terminated due to disconnect<br />CTLIB Message: - L5/O3/S5/N5/5/0:</font>
		</p>
<img src ="http://www.blogjava.net/os586/aggbug/135077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-08-07 21:25 <a href="http://www.blogjava.net/os586/archive/2007/08/07/135077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Sybase 我再一次把你拾起</title><link>http://www.blogjava.net/os586/archive/2007/07/05/128440.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 05 Jul 2007 13:13:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/07/05/128440.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/128440.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/07/05/128440.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/128440.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/128440.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Courier New" size="2">最早经手sybase数据库是在电力上使用，那时对这东西很是模糊。因为我只要配置一下自己的客户端连结使用就可以了。而较为系统较为全面的使用还是在以前的一个金融项目中使用。<br /><br /><br /><br />当时对有些东西只是刚刚接触，特别是对设备(主设备，日志设备，转储设备。。)，segment，最恼人的就是sybase的数据库日志问题导致的数据库服务起不来的问题。那时，有一全套手册，真是大补。感觉对这东西有了些较为全面的了解。但是一段时间后，我因为工作关系转到oracle上来了。当时，感觉到非常的失望，公司里不使用sybase，因此又要全新的学习oracle.好在，公司内部还是有一些老项目使用了sybase,呵呵，可以有用武这地了.......<br /><br /><br /><br />这次重新拾起，是因为我经手的这个项目是在sybase上使用，而且这台服务器上有很多数据库了。<br />仔细看了一下，未知管理员配置的数据库服务器，感觉还是不错的。<br /><br />为了使我经手的项目能够顺利的走下去，我还是又拿出了我的全套手册!<br /><br />因此，借用javablog.net我会发一些sybase的一些文章。<br /><br />我会把一些相关的数据库文件链接至此!</font>
		</p>
<img src ="http://www.blogjava.net/os586/aggbug/128440.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-07-05 21:13 <a href="http://www.blogjava.net/os586/archive/2007/07/05/128440.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Sybase 数据库默认设备的更改</title><link>http://www.blogjava.net/os586/archive/2007/07/04/128191.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Wed, 04 Jul 2007 14:01:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/07/04/128191.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/128191.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/07/04/128191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/128191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/128191.html</trackback:ping><description><![CDATA[
		<p>
				<font face="Courier New" size="2">为了防止用户数据库被分配到数据库系统主设备 master 上，应该在安装完数据库后修改默认设备—安装完 sybase ASE 后，master 是唯一的默认设备。Sybase 建议，master 设备只应该提供给系统数据库而不是用户数据库。因此，对于用户数据库，我们应当单独创建设备，并且把用户设备设置成默认状态。<br /><br /><br /><br />  比如我们可能要建立几个用户数据库设备：userData,userLog<br /><br />  首先我们需要先取消master的默认设备：<br /><br /><br /><br />    sp_diskdefault "master","defaultoff"<br /><br />    go<br /><br />    sp_diskdefault "userData","defaulton"<br /><br />    go<br /><br />    sp_diskdefault "userLog","defaulton"<br /><br />    go<br /><br />　　在后面创建用户数据库的过程中，如果不指定数据库设备，则该用户数据库理所当然地创建在默认设备。<br /><br />　　创建数据库：本数据库创建在设备 userData 上，而在分开的设备（userLog）上创建数据库日志。<br /><br />　　1&gt;create database mydatabase //创建一个名为 mydatabase 的数据库<br />　　2&gt; on userData = “50M” //数据库的存储空间为 50M，数据库设备是 userData，而不是 master<br />　　3&gt;log on userLog =”10M” //日志文件的存储空间为 10M<br />　　4&gt;go<br /><br /><br /><br /><br /></font>
		</p>
<img src ="http://www.blogjava.net/os586/aggbug/128191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-07-04 22:01 <a href="http://www.blogjava.net/os586/archive/2007/07/04/128191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的类型怎样映射数据库中字段的自定义类型</title><link>http://www.blogjava.net/os586/archive/2007/06/21/125586.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 21 Jun 2007 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/06/21/125586.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/125586.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/06/21/125586.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/125586.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/125586.html</trackback:ping><description><![CDATA[
		<textarea class="content" style="WIDTH: 698px; HEIGHT: 137px" rows="7" readonly="" cols="74">我在数据库中自定义了数据类型：如UserName,其实它就是一个基本数据类型：varchar(12)的。

但是这种自定义数据类型在hibernate当中我们该怎样进行数据类型的映射？
</textarea>
<img src ="http://www.blogjava.net/os586/aggbug/125586.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-06-21 15:48 <a href="http://www.blogjava.net/os586/archive/2007/06/21/125586.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts 中 html:options 的使用</title><link>http://www.blogjava.net/os586/archive/2007/02/11/99306.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Sun, 11 Feb 2007 14:03:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/02/11/99306.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/99306.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/02/11/99306.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/99306.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/99306.html</trackback:ping><description><![CDATA[　　html:options是Struts中比较复杂的一个tage lib，用法灵活，但是Sturts提供的源码exercise taglib中没有提出常用jsp+ActionForm这样形式的最直接的总结，现从中总结如下，分两种情况：数组和Collection。<br />　　<br />　　需求，要达到：<br />　　&lt;select name="beanCollectionSelect" multiple="multiple" size="10"&gt;<br />　　&lt;option value="value 0"&gt;Label 0&lt;/option&gt;<br />　　&lt;option value="value 1" selected="selected"&gt;Label 1&lt;/option&gt;<br />　　&lt;option value="value 2"&gt;Label 2&lt;/option&gt;<br />　　&lt;option value="value 3" selected="selected"&gt;Label 3&lt;/option&gt;<br />　　&lt;option value="value 4"&gt;Label 4&lt;/option&gt;<br />　　&lt;option value="value 5" selected="selected"&gt;Label 5&lt;/option&gt;<br />　　&lt;option value="value 6"&gt;Label 6&lt;/option&gt;<br />　　&lt;option value="value 7"&gt;Label 7&lt;/option&gt;<br />　　&lt;option value="value 8"&gt;Label 8&lt;/option&gt;<br />　　&lt;option value="value 9"&gt;Label 9&lt;/option&gt;&lt;/select&gt;<br />　　<br />　　要实现上述效果，需要两步：<br />　　第一：设置ActionForm，<br />　　也分两小步：第一小步必须在ActionForm中，有一句<br />　　private Collection beanCollection;<br />　　public Collection getBeanCollection();<br />　　<br />　　Collection beanCollection要确保是一个实现，如ArrayList，如果不是则会报No collection found的错误，Struts的最大不方便就是一旦出问题，定位很难，不知道什么地方使用错误，或忘记设置什么了。<br />　　<br />　　因为前面需求中option的value值和label值不一样，那么在beanCollection中保存的就是一个value和label组成的对象，名为LabelvalueBean，在LabelvalueBean中有两个属性value和label，<br />　　<br />　　在程序某个地方要为beanCollection赋值，如：<br />　　<br />　　Vector entries = new Vector(10);　 <br />　　entries.add(new LabelvalueBean("Label 0", "value 0"));　　　　　<br />　　entries.add(new LabelvalueBean("Label 1", "value 1"));　　　　　<br />　　entries.add(new LabelvalueBean("Label 2", "value 2"));　　　　　<br />　　entries.add(new LabelvalueBean("Label 3", "value 3"));　　　　　<br />　　entries.add(new LabelvalueBean("Label 4", "value 4"));　　　　　　<br />　　entries.add(new LabelvalueBean("Label 5", "value 5"));　　　　　 <br />　　 entries.add(new LabelvalueBean("Label 6", "value 6"));　　　　　　<br />　　entries.add(new LabelvalueBean("Label 7", "value 7"));　　　　　　<br />　　entries.add(new LabelvalueBean("Label 8", "value 8"));　　　　　　<br />　　entries.add(new LabelvalueBean("Label 9", "value 9"));<br />　　<br />　　然后执行setBeanCollection(entries);<br />　　这样ActionForm中的beanCollection算有值了。<br />　　第二小步，需要设置Selected，selected有两种，单选和多选：<br />　　在ActionForm中必须有：<br />　　<br />　　private String singleSelect = "Single 5";　 <br />　　public String getSingleSelect()<br />　　 {<br />　　　　　return (this.singleSelect);<br />　　　　}　 <br />　　public void setSingleSelect(String singleSelect)<br />　　 {<br />　　　　　this.singleSelect = singleSelect;<br />　　　　}<br />　　<br />　　或多选，多选必须是数组：<br />　　<br />　　private String[] beanCollectionSelect = { "value 1", "value 3",<br />　　　　　　　　　　　　　　　　　　　　　　　　　"value 5" };　<br />　　public String[] getBeanCollectionSelect() {<br />　　　 return (this.beanCollectionSelect);　　}<br />　　　　public void setBeanCollectionSelect(String beanCollectionSelect[])<br />　　 {<br />　　　　　　this.beanCollectionSelect = beanCollectionSelect;<br />　　　　}<br />　　<br />　　第二：在Jsp中写入tang lib语句如下：<br />　　<br />　　&lt;html:select property="beanCollectionSelect" size="10" multiple="true"&gt;<br />　　　　　　&lt;html:optionsCollection name="testbean" property="beanCollection"/&gt;　　<br />　　 &lt;/html:select&gt;<br />　　<br />　　其中testbean是ActionForm的名称。<br />　　<br />　　以上是html:options的Collection解决方案，如果option值很少，简单地可以实现为数组，两步：<br />　　第一：在ActionForm中，<br />　　<br />　　private String values[] =<br />　　　　 { "Magazine", "Journal", "News Paper","Other" };　 <br />　　private String labels[] =<br />　　　　 { "L-Magazine", "L-Journal", "L-News Paper","L-Other"};<br />　　　　private String selected = "Magazine";　　<br />　　public String getSelected()<br />　　{<br />　　　　　return selected;<br />　　　　}　　<br />　　public void setSelected(String selected)<br />　　{<br />　　　　　this.selected = selected;<br />　　　　}　 <br />　　public String[] getvalues()<br />　　{<br />　　　　　return values;<br />　　　　}　　<br />　　public void setvalues(String[] values)<br />　　{　　　this.values = values;<br />　　　　}　 <br />　　public String[] getLabels()<br />　　{<br />　　　　　return values;<br />　　　　}　　<br />　　public void setLabels(String[] labels)<br />　　{<br />　　　　　this.labels = labels;<br />　　　　}<br />　　<br />　　第二步在jsp中：<br />　　<br />　　&lt;html:select property="selected" &gt;　　　　　 <br />　　&lt;html:options name="testbean" property="values" labelProperty="label"/&gt;　　　&lt;/html:select&gt;<br />　　<br />　　Struts标签库的使用还是需要小心，不必完全使用Struts的标签库，个人感觉Struts这种替代Html语句的标签库有一种牵强附会，给使用者掌握带来难度，使用者除熟悉html外，还必须理解Struts的对应标签库用法，而且这种调试出错，问题也无法准确定位，总是抽象地告诉你，no bean 或no form<img src ="http://www.blogjava.net/os586/aggbug/99306.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-02-11 22:03 <a href="http://www.blogjava.net/os586/archive/2007/02/11/99306.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Struts的Token机制解决表单重复提交</title><link>http://www.blogjava.net/os586/archive/2007/02/11/99305.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Sun, 11 Feb 2007 14:00:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/02/11/99305.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/99305.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/02/11/99305.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/99305.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/99305.html</trackback:ping><description><![CDATA[　　Struts的Token（令牌）机制能够很好的解决表单重复提交的问题，基本原理是：服务器端在处理到达的请求之前，会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较，看是否匹配。在处理完该请求后，且在答复发送给客户端之前，将会产生一个新的令牌，该令牌除传给客户端以外，也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话，客户端传过来的令牌就和服务器端的令牌不一致，从而有效地防止了重复提交的发生。<br />　　<br />　　这时其实也就是两点，第一：你需要在请求中有这个令牌值，请求中的令牌值如何保存，其实就和我们平时在页面中保存一些信息是一样的，通过隐藏字段来保存，保存的形式如： 〈input type="hidden" name="org.apache.<a href="http://www.javaresource.org/struts/struts-24.html">struts</a>.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉，这个value是TokenProcessor类中的generateToken()获得的，是根据当前用户的session id和当前时间的long值来计算的。第二：在客户端提交后，我们要根据判断在请求中包含的值是否和服务器的令牌一致，因为服务器每次提交都会生成新的Token，所以，如果是重复提交，客户端的Token值和服务器端的Token值就会不一致。下面就以在数据库中插入一条数据来说明如何防止重复提交。<br />　　<br />　　在Action中的add方法中，我们需要将Token值明确的要求保存在页面中，只需增加一条语句：saveToken(request);，如下所示：<br />　　<br />　　public ActionForward add(ActionMapping mapping, ActionForm form,<br />　　<br />　　HttpServletRequest request, HttpServletResponse response)<br />　　<br />　　//前面的处理省略<br />　　<br />　　saveToken(request);<br />　　<br />　　return mapping.findForward("add");<br />　　<br />　　}在Action的insert方法中，我们根据表单中的Token值与服务器端的Token值比较，如下所示：<br />　　<br />　　public ActionForward insert(ActionMapping mapping, ActionForm form,<br />　　<br />　　HttpServletRequest request, HttpServletResponse response)<br />　　<br />　　if (isTokenValid(request, true)) {<br />　　<br />　　// 表单不是重复提交<br />　　<br />　　//这里是保存数据的代码<br />　　<br />　　} else {<br />　　<br />　　//表单重复提交<br />　　<br />　　saveToken(request);<br />　　<br />　　//其它的处理代码<br />　　<br />　　}<br />　　<br />　　}<br />　　<br />　　其实使用起来很简单，举个最简单、最需要使用这个的例子：<br />　　<br />　　一般控制重复提交主要是用在对数据库操作的控制上，比如插入、更新、删除等，由于更新、删除一般都是通过id来操作（例如：updateXXXById, removeXXXById），所以这类操作控制的意义不是很大（不排除个别现象），重复提交的控制也就主要是在插入时的控制了。<br />　　<br />　　先说一下，我们目前所做项目的情况：<br />　　<br />　　目前的项目是用Struts＋Spring＋Ibatis，页面用<a href="http://www.javaresource.org/jstl/jstl-69.html">jstl</a>，Struts复杂View层，Spring在Service层提供事务控制，Ibatis是用来代替<a href="http://www.javaresource.org/jdbc/jdbc-90.html">JDBC</a>，所有页面的访问都不是直接访问jsp，而是访问Structs的Action，再由Action来Forward到一个Jsp，所有针对数据库的操作，比如取数据或修改数据，都是在Action里面完成，所有的Action一般都继承BaseDispatchAction，这个是自己建立的类，目的是为所有的Action做一些统一的控制，在Struts层，对于一个功能，我们一般分为两个Action，一个Action里的功能是不需要调用Struts的验证功能的（常见的方法名称有add,edit,remove,view,list），另一个是需要调用Struts的验证功能的（常见的方法名称有insert,update）。<br />　　<br />　　就拿论坛发贴来说吧，论坛发贴首先需要跳转到一个页面，你可以填写帖子的主题和内容，填写完后，单击“提交”，贴子就发表了，所以这里经过两个步骤：<br />　　<br />　　1、转到一个新增的页面，在Action里我们一般称为add，例如：<br />　　<br />　　public ActionForward add(ActionMapping mapping, ActionForm form,<br />　　<br />　　HttpServletRequest request, HttpServletResponse response)<br />　　<br />　　throws Exception {<br />　　<br />　　//这一句是输出调试信息，表示代码执行到这一段了<br />　　<br />　　log.debug(":: action - subject add");<br />　　<br />　　//your code here<br />　　<br />　　//这里保存Token值<br />　　<br />　　saveToken(request);<br />　　<br />　　//跳转到add页面，在Structs-config.<a href="http://www.javaresource.org/xml/xml-55.html">xml</a>里面定义，例如，跳转到subjectAdd.jsp<br />　　<br />　　return mapping.findForward("add");<br />　　<br />　　}<br />　　<br />　　2、在填写标题和内容后，选择 提交 ，会提交到insert方法，在insert方法里判断，是否重复提交了。<br />　　<br />　　public ActionForward insert(ActionMapping mapping, ActionForm form,<br />　　<br />　　HttpServletRequest request, HttpServletResponse response){<br />　　<br />　　if (isTokenValid(request, true)) {<br />　　<br />　　// 表单不是重复提交<br />　　<br />　　//这里是保存数据的代码<br />　　<br />　　} else {<br />　　<br />　　//表单重复提交<br />　　<br />　　saveToken(request);<br />　　<br />　　//其它的处理代码<br />　　<br />　　}<br />　　<br />　　}<br />　　<br />　　下面更详细一点（注意，下面所有的代码使用全角括号）：<br />　　<br />　　1、你想发贴时，点击“我要发贴”链接的代码可以里这样的：<br />　　<br />　　〈html:link action="subject.do?method=add"〉我要发贴〈/html:link〉<br />　　<br />　　subject.do 和 method 这些在struct-config.<a href="http://www.javaresource.org/xml/xml-55.html">xml</a>如何定义我就不说了，点击链接后，会执行subject.do的add方法，代码如上面说的，跳转到subjectAdd.jsp页面。页面的代码大概如下：<br />　　<br />　　〈html:form action="subjectForm.do?method=insert"〉<br />　　<br />　　〈html:text property="title" /〉<br />　　<br />　　〈html:textarea property="content" /〉<br />　　<br />　　〈html:submit property="发表" /〉<br />　　<br />　　〈html:reset property="重填" /〉<br />　　<br />　　〈html:form〉<br />　　<br />　　如果你在add方法里加了“saveToken(request);”这一句，那在subjectAdd.jsp生成的页面上，会多一个隐藏字段，类似于这样〈input type="hidden" name="org.apache.<a href="http://www.javaresource.org/struts/struts-24.html">struts</a>.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉，<br />　　<br />　　2、点击发表后，表单提交到subjectForm.do里的insert方法后，你在insert方法里要将表单的数据插入到数据库中，如果没有进行重复提交的控制，那么每点击一次浏览器的刷新按钮，都会在数据库中插入一条相同的记录，增加下面的代码，你就可以控制用户的重复提交了。<br />　　<br />　　if (isTokenValid(request, true)) {<br />　　<br />　　// 表单不是重复提交<br />　　<br />　　//这里是保存数据的代码<br />　　<br />　　} else {<br />　　<br />　　//表单重复提交<br />　　<br />　　saveToken(request);<br />　　<br />　　//其它的处理代码<br />　　<br />　　}<br />　　<br />　　注意，你必须在add方法里使用了saveToken(request)，你才能在insert里判断，否则，你每次保存操作都是重复提交。<br />　　<br />　　记住一点，Struts在你每次访问Action的时候，都会产生一个令牌，保存在你的Session里面，如果你在Action里的函数里面，使用了saveToken(request);，那么这个令牌也会保存在这个Action所Forward到的jsp所生成的静态页面里。<br />　　<br />　　如果你在你Action的方法里使用了isTokenValid，那么Struts会将你从你的request里面去获取这个令牌值，然后和Session里的令牌值做比较，如果两者相等，就不是重复提交，如果不相等，就是重复提交了。<br />　　<br />　　由于我们项目的所有Action都是继承自BaseDispatchAction这个类，所以我们基本上都是在这个类里面做了表单重复提交的控制，默认是控制add方法和insert方法，如果需要控制其它的方法，就自己手动写上面这些代码，否则是不需要手写的，控制的代码如下：<br />　　<br />　　public abstract class BaseDispatchAction extends BaseAction {<br />　　<br />　　protected ActionForward perform(ActionMapping mapping, ActionForm form,<br />　　<br />　　HttpServletRequest request, HttpServletResponse response)<br />　　<br />　　throws Exception {<br />　　<br />　　String parameter = mapping.getParameter();<br />　　<br />　　String name = request.getParameter(parameter);<br />　　<br />　　if (null == name) { //如果没有指定 method ，则默认为 list<br />　　<br />　　name = "list";<br />　　<br />　　}<br />　　<br />　　if ("add".equals(name)) {<br />　　<br />　　if ("add".equals(name)) {<br />　　<br />　　saveToken(request);<br />　　<br />　　}<br />　　<br />　　} else if ("insert".equals(name)) {<br />　　<br />　　if (!isTokenValid(request, true)) {<br />　　<br />　　resetToken(request);<br />　　<br />　　saveError(request, new ActionMessage("error.repeatSubmit"));<br />　　<br />　　log.error("重复提交！");<br />　　<br />　　return mapping.findForward("error");<br />　　<br />　　}<br />　　<br />　　}<br />　　<br />　　return dispatchMethod2(mapping, form, request, response, name);<br />　　<br />　　}<br />　　<br />　　} <br /><img src ="http://www.blogjava.net/os586/aggbug/99305.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-02-11 22:00 <a href="http://www.blogjava.net/os586/archive/2007/02/11/99305.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让dreamweaver 支持Struts标签库</title><link>http://www.blogjava.net/os586/archive/2007/02/08/98722.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 08 Feb 2007 05:23:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/02/08/98722.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/98722.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/02/08/98722.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/98722.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/98722.html</trackback:ping><description><![CDATA[我经常使用dreameweaver来编辑网页,所见即所得.<br /><br />但是该软件对struts标签不支持,因此<br /><br />可以在<a href="http://www.cnblogs.com/Files/bjzhanghao/ast-03.zip">http://www.cnblogs.com/Files/bjzhanghao/ast-03.zip</a>下载该软件的插件,用来支持Struts.<br /><br />下载后用dreamweaver的插件管理器来打开.mpx文件,即可使用了.<br /><br /><br /><br />不过我安装后没有找到这个插件的使用菜单.<br /><br />最后我在编辑菜单的标签库当中把相关的 tld文件导入后即可以使用了.<br /><br />大家有没有使用过这个插件的?<br /><br /><br /><br />这样后,标签的提示功能也不错啊.<br /><img src ="http://www.blogjava.net/os586/aggbug/98722.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-02-08 13:23 <a href="http://www.blogjava.net/os586/archive/2007/02/08/98722.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts常见错误及原因分析</title><link>http://www.blogjava.net/os586/archive/2007/02/08/98694.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 08 Feb 2007 03:14:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/02/08/98694.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/98694.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/02/08/98694.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/98694.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/98694.html</trackback:ping><description><![CDATA[
		<p style="TEXT-INDENT: 2em">
				<strong>1异常</strong>
				<br />javax.servlet.jsp.JspException:Cannotretrievemappingforaction/Login（/Login是你的action名字）</p>
		<p style="TEXT-INDENT: 2em">可能原因:action没有再struts-config.xml中定义，或没有找到匹配的action，例如在JSP文件中使用 </p>
		<p style="TEXT-INDENT: 2em">处理:如果出现上述异常，请查看struts-config.xml中的定义部分，有时可能是打错了字符或者是某些不符合规则，可以使用strutsconsole工具来检查。</p>
		<p style="TEXT-INDENT: 2em">
				<strong>2异常</strong>
				<br />org.apache.jasper.JasperException:Cannotretrievedefinitionforformbeannull</p>
		<p style="TEXT-INDENT: 2em">可能原因:这个异常是因为Struts根据struts-config.xml中的mapping没有找到action期望的formbean。大部分的情况可能是因为在form-bean中设置的name属性和action中设置的name属性不匹配所致。换句话说，action和form都应该各自有一个name属性，并且要精确匹配，包括大小写。这个错误当没有name属性和action关联时也会发生，如果没有在action中指定name属性，那么就没有name属性和action相关联。当然当action制作某些控制时，譬如根据参数值跳转到相应的jsp页面，而不是处理表单数据，这是就不用name属性，这也是action的使用方法之一。</p>
		<p style="TEXT-INDENT: 2em">
				<strong>3异常</strong>
				<br />Noactioninstanceforpath/xxxxcouldbecreated</p>
		<p style="TEXT-INDENT: 2em">可能原因</p>
		<p style="TEXT-INDENT: 2em">特别提示：因为有很多中情况会导致这个错误的发生，所以推荐大家调高你的web服务器的日志/调试级别，这样可以从更多的信息中看到潜在的、在试图创建action类时发生的错误，这个action类你已经在struts-config.xml中设置了关联（即添加了<action></action>标签）。</p>
		<p style="TEXT-INDENT: 2em">在struts-config.xml中通过action标签的class属性指定的action类不能被找到有很多种原因，例如：</p>
		<p style="TEXT-INDENT: 2em">定位编译后的.class文件失败。Failuretoplacecompiled.classfilefortheactionintheclasspath(在web开发中，class的的位置在rWEB-INF/classes，所以你的actionclass必须要在这个目录下。例如你的action类位于WEB-INF/classes/action/Login.class,那么在struts-config.xml中设置action的属性type时就是action.Login).</p>
		<p style="TEXT-INDENT: 2em">拼写错误，这个也时有发生，并且不易找到，特别注意第一个字母的大小写和包的名称。</p>
		<p style="TEXT-INDENT: 2em">在struts-config.xml中指定的action类没有继承自Stuts的Action类，或者你自定义的Action类没有继承自Struts提供的Action类。</p>
		<p style="TEXT-INDENT: 2em">你的action类必须继承自Struts提供的Action类。</p>
		<p style="TEXT-INDENT: 2em">你的classpath的问题。例如webserver没有发现你的资源文件，资源文件必须在WEB-INF/classes/目录下。</p>
		<p style="TEXT-INDENT: 2em">
				<strong>4异常</strong>
				<br />javax.servlet.jsp.JspException:Nogettermethodforpropertyusernameofbeanorg.apache.struts.taglib.html.BEAN</p>
		<p style="TEXT-INDENT: 2em">可能原因</p>
		<p style="TEXT-INDENT: 2em">没有位formbean中的某个变量定义getter方法</p>
		<p style="TEXT-INDENT: 2em">这个错误主要发生在表单提交的FormBean中，用struts标记</p>
		<p style="TEXT-INDENT: 2em">5Exceptionjavax.servlet.jsp.JspException:CannotfindActionMappingsorActionFormBeanscollection</p>
		<p style="TEXT-INDENT: 2em">可能原因</p>
		<p style="TEXT-INDENT: 2em">不是标识StrutsactionServlet的<servlet></servlet>标记就是映射.do扩展名的<sevlet-mapping></sevlet-mapping>标记或者两者都没有在web.xml中声明。</p>
		<p style="TEXT-INDENT: 2em">在struts-config.xml中的打字或者拼写错误也可导致这个异常的发生。例如缺少一个标记的关闭符号/&gt;。最好使用strutsconsole工具检查一下。</p>
		<p style="TEXT-INDENT: 2em">另外，load-on-startup必须在web.xml中声明，这要么是一个空标记，要么指定一个数值，这个数值用来表servlet运行的优先级，数值越大优先级越低。</p>
		<p style="TEXT-INDENT: 2em">还有一个和使用load-on-startup有关的是使用Struts预编译JSP文件时也可能导致这个异常。</p>
		<p style="TEXT-INDENT: 2em">6Exception</p>
		<p style="TEXT-INDENT: 2em">javax.servlet.jsp.JspException:Cannotfindbeanorg.apache.struts.taglib.html.BEANinanyscope</p>
		<p style="TEXT-INDENT: 2em">ProbableCauses</p>
		<p style="TEXT-INDENT: 2em">试图在Struts的form标记外使用form的子元素。这常常发生在你在</p>
		<p style="TEXT-INDENT: 2em">后面使用Struts的html标记。</p>
		<p style="TEXT-INDENT: 2em">另外要注意可能你不经意使用的无主体的标记，如，这样web服务器解析时就当作一个无主体的标记，随后使用的所有标记都被认为是在这个标记之外的，如又使用了</p>
		<p style="TEXT-INDENT: 2em">还有就是在使用taglib引入HTML标记库时，你使用的prefix的值不是html。</p>
<img src ="http://www.blogjava.net/os586/aggbug/98694.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-02-08 11:14 <a href="http://www.blogjava.net/os586/archive/2007/02/08/98694.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ForwardAction解决我们的页面转向问题</title><link>http://www.blogjava.net/os586/archive/2007/02/03/97708.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Sat, 03 Feb 2007 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/02/03/97708.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/97708.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/02/03/97708.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/97708.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/97708.html</trackback:ping><description><![CDATA[在应用程序中，可能会经常出现只要将Action对象转发到某个JSP的情况。在上一点中曾提到总是由Action调用JSP是个好习惯。如果我们不必在Action中执行任何业务逻辑，却又想遵循从Action访问页面的话，就可以使用ForwardAction，它可以使你免去创建许多空的Action类。运用ForwardAction的好处是不必创建自己的Action类，你需要做的仅仅是在Struts配置文件中配置一个Action mapping。<br /><br />　　举个例子，假定你有一个JSP文件index.jsp ，而且不能直接调用该页面，必须让程序通过一个Action类调用，那么，你可以建立以下的Action mapping来实现这一点：<br /><br /><br />&lt;action path="/abc" type="com.apache.struts.actions.ForwardAction" parameter="index.jsp"/&gt;<br /><br />这样就可以了，无需再写一个Action类来完成，减少了文件个数。<br /><br />只需要在Struts-config.xml当中配置一个actionMapping即可。<img src ="http://www.blogjava.net/os586/aggbug/97708.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-02-03 10:24 <a href="http://www.blogjava.net/os586/archive/2007/02/03/97708.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>smartUpload上传多个文件时要注意的问题</title><link>http://www.blogjava.net/os586/archive/2007/01/05/92117.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 05 Jan 2007 13:22:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2007/01/05/92117.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/92117.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2007/01/05/92117.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/92117.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/92117.html</trackback:ping><description><![CDATA[我的项目当中需要同时上传多个文件，并且要得到上传文件 的名字，以及上传到服务器上的文件的名字都要写到相应的数据表当中。<br /><br />其实这对于smartUpload来说并不难，但是我还是遇到了文件名重复的问题：<br /><br />我同时上传了五个图片文件(注意文件的字节数并不大)，第一个文件上传成功，而从第二至第五个后就只有一个成功，因为后面的都生成了一个名字。<br /><br />服务器上的名字是通过System.currentTimeMillis()得到当前的毫秒数，然后通过SimpleDateFormate格式化的。<br /><br />通过getFiles().getCount(),与File.isMissing()方法来判断的，但是以为计算机的处理速度比较快，所以后面的几个在毫秒数上也没有区分开来，看来处理的速度太快了。<br /><br />接下来我试了几个大文件，然后就会生成自己想要的文件名了。<br /><br />不过这样还是不行啊，不是解决问题的出路。<br /><br />我们可以通过循环来使我们得到的文件名被改变。<br /><br />得到当前的毫秒数后加一个循环因子就可以实现了。<br /><br />这种小问题竟然花了我很长时间才查出来，惭愧 !<img src ="http://www.blogjava.net/os586/aggbug/92117.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2007-01-05 21:22 <a href="http://www.blogjava.net/os586/archive/2007/01/05/92117.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最近很少来，特别忙!</title><link>http://www.blogjava.net/os586/archive/2006/12/22/89582.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 22 Dec 2006 11:48:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/12/22/89582.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/89582.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/12/22/89582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/89582.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/89582.html</trackback:ping><description><![CDATA[因为很久没来，做了一个月的封闭开发。<br /><br />框架是Spring+Struts+oracle，虽然很累。还是学到了很多东西!<br /><br />对于Spring我以前从未接触过，虽然最近做了项目，但是对其一些运行原理，及内部的各个部分还是不熟悉。<br /><br />就好像是虽然吃了饭，但总是没有品尝它的滋味!<br /><br />我想在接下来的这段时间，仔细的学习一下。<br /><br />当然不可能全部学，只学习自己需要的那部分就行了。<br /><br />Spring是一个比较大的框架，择其而用，择其而学吧。<img src ="http://www.blogjava.net/os586/aggbug/89582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-12-22 19:48 <a href="http://www.blogjava.net/os586/archive/2006/12/22/89582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts -- html:link 标签的使用</title><link>http://www.blogjava.net/os586/archive/2006/11/09/80276.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 09 Nov 2006 14:15:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/11/09/80276.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/80276.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/11/09/80276.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/80276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/80276.html</trackback:ping><description><![CDATA[
		<p>&lt;html:link&gt; 标签用于生成HTML &lt;a&gt; 元素。&lt;html:link&gt; 在创建超链接时，有两个优点：<br />(1) 允许在URL 中以多种方式包含请求参数。<br />(2) 当用户浏览器关闭Cookie 时，会自动重写URL，把SessionID 作为请求参数包含在URL 中，用于跟踪用户的Session 状态。</p>
		<p>&lt;html:link&gt; 标签有以下重要属性：<br />(1) forward：指定全局转发链接。<br />(2) href：指定完整的URL 键接。<br />(3) page：指定相对于当前网页的URL。</p>
		<p>        &lt;html:rewrite&gt; 用于输出超链接中的URI部分，但它并不生成HTML &lt;a&gt; 元素。URI指的是URL 中协议、主机和端口以后的内容。URI 用于指定具体的请求资源。例如，对于URL：HTTP：//localhost:8080/HtmlBasic.do，它的URI为/HtmlBasic.do</p>
		<p>示例：<br />1、创建全局转发链接<br />    首先，在Struts-config.xml 中&lt;global-forwards&gt; 元素中定义一个&lt;forward&gt; 元素：<br />    &lt;global-forwards&gt;<br />        &lt;forward name = "index" path="/index.jsp"/&gt;<br />    &lt;/global-forwards&gt;<br />    接着，在JSP 文件中创建&lt;html:link&gt; 标签：<br />    &lt;html:link forward="index"&gt;<br />        Link to Global ActionForward<br />    &lt;/html:link&gt;<br />    &lt;html:link&gt; 标签的forward 属性和&lt;global-forwards&gt; 元素中的&lt;forward&gt; 子元素匹配。以上代码生成如下HTML 内容：<br />    &lt;a href="/index.jsp"&gt;Link to Global ActionFoward&lt;/a&gt;<br />    值得注意的是，&lt;html:link&gt; 的forward 属性只引用Struts-config.xml 配置文件中&lt;global-forwards&gt;内的&lt;forward&gt; 子元素，如果引用&lt;action&gt; 内的&lt;forward&gt; 子元素，在运行时将会抛出异常：<br />    Cannot create rewrite URL: Java.Net.MalfomedURlException: Cannot retrieve ActionForward</p>
		<p>2、创建具有完整URL 的链接<br />    如果Web 应用需要链接到其他站点，应该给出其他站点完整ＵＲＬ，例如：<br />    &lt;html:link href="<a href="http://jakarta.apache.org/struts/index.html">http://jakarta.apache.org/struts/index.html</a>"&gt;<br />        Generate an "href" directly<br />    &lt;/html:link&gt;<br />    生成HTML 代码如下：<br />    &lt;a href="<a href="http://jakarta.apache.org/struts/index.html&quot;&gt;Generate">http://jakarta.apache.org/struts/index.html"&gt;Generate</a> an "href" directly&lt;/a&gt;<br />    值得注意的是，如果指定了&lt;html:link&gt; 标签的href 属性，即使用户浏览器的Cookie 关闭，&lt;html:link&gt; 标签也不会把用户SessionID 作为请求参数加和到URL 中。</p>
		<p>3、从当前网页中创建相对URL<br />    如果从一个网页链接到同一个应用中的另一网页，可以采用以下方式：<br />    &lt;html:link page="/HtmlBasic.do"&gt;<br />        A relative link from this page<br />    &lt;/html:link&gt;<br />    &lt;html:link&gt; 标签的 page 属性用于指定相对于当前应用的URI。以上代码生成如下HTML 内容：<br />    &lt;a href="/lib/HtmlBasic.do"&gt;......&lt;/a&gt;</p>
		<p>4、在URL 或 URI 中包含请求参数<br />    如果要在URL或URI 中包含请求参数，只要把请求参数加在URL 或 URI的末尾就可以了。例如：<br />    &lt;html:link page="/HtmlBasic.do?prop1=abc&amp;amp;prop2=123"&gt;<br />        Hard-code the url parameters<br />    &lt;/html:link&gt;<br />    &lt;!-- or --&gt;<br />    &lt;html:rewrite page="/HtmlBasic.do?prop1=abc&amp;amp;prop2=123"/&gt;<br />    以上代码生成如下HTML 内容：<br />    &lt;a href=/lib/HtmlBasic.do?prop1=abc&amp;amp;prop2=123"&gt;......&lt;/a&gt;<br />    rewrite: /HtmlBasic.do?prop1=abc&amp;amp;prop2=123</p>
		<p>    提示：在HTML 中&amp;amp 代表特殊字符 "&amp;"</p>
		<p>5、在URL 或 URI 中包含单个请求变量<br />                  <br />        如果要在URL 中包含一个请求参数，而这人参数的值存在于当前网页可访问的一个变量中，可以按以下方法来实现。<br />        为了演示这一功能，首先创建一个当前网页可访问的变量。例如，本例中创建了两个变量，一个是字符类型，一个是CustomerBean ， 它们存存于一个 page 范围内：<br />    &lt;%<br />        /* <br />         * Create a string object to store as a bean in<br />         * the page content and embed in this link<br />         */<br />        String stringBean = "Value to Pass ont URL";<br />        pageContext.setAttribute("stringBean", stringBean);<br />    %&gt;<br />    &lt;jsp:useBean id = "customerBean" scope="page" class="htmltaglibs.beans.CurstomerBean"/&gt;<br />    &lt;jsp:setProperty name="customerBean" property="name" value="weiqin"/&gt;<br />        接着，把这两个变量作为请求参数，加入到URL或URI 中：<br />    &lt;html:link page="/HtmlBasic.do"<br />                      paramId="urlParamName"<br />                      paramName="stringBean"&gt;<br />        URL encode a parameter based on a string bean value<br />    &lt;/html:link&gt;<br />    &lt;html:link page="/HtmlBasic.do"<br />                       paramId="urlParamName"<br />                       paramName="customerBean"<br />                       paramProperty="name"&gt;<br />        URL encode a parameter based on a customer bean value<br />    &lt;/html:link&gt;</p>
		<p>    rewrite: &lt;html:rewrite page="/HtmlBasic.do"<br />                                           paramId="urlParamName" paramName="stringBean"/&gt;<br />    rewrite: &lt;html:rewrite page="/HtmlBasic.do"                                            <br />                                           paramId="urlParamName" paramName="customerBean"<br />                                           paramProperty="name"/&gt;</p>
		<p>    &lt;html:link&gt; 标签的 paramId 属性指定请求参数名，paramName 属性指定变量的名字。如果变量为JavaBean ，用paramProperty 属性指定JavaBean 的属性。<br />    对于本例的stringBean，请求参数值为stringBean 的字符串值。对于customerBean，指定了paramProperty 属性，请求参数值为customerBean 的 name 属性值。<br />    以上代码生成如下HTML 内容：<br />    &lt;a href="/HtmlBasic.do?urlParamName=Value to Pass on Url"&gt;<br />        Url encode a paramter based on a string bean value<br />    &lt;/a&gt;</p>
		<p>    &lt;a href="/HtmlBasic.do?urlParamName=weiqin"&gt;<br />        url encode a parameter based on a customer bean value<br />    &lt;/a&gt;</p>
		<p>    rewrite: /HtmlBasic.do?urlParamName=Value to Pass on Url<br />    rewrite: /HtmlBasic.do?urlParamName=weiqin<br />6、在URL 或 URI 中包含多个请求变量<br />    如果在URL 或 URI 中包含多个请求参数，而这些参数的值来自多个变量，需要先定义一个Map类型的java 类，如java.util.HashMap，用它来存放请求变量。例如：<br />    &lt;%<br />        /*<br />         * Strore values int a Map(HashMap in this case)<br />         * and construct the URL based on the Map<br />         * /<br />        java.util.HashMap myMap = new java.util.HashMap();<br />        myMap.put("myString", new String("myStringValue"));<br />        myMap.put("myArray" , new String[]{"str1","str2","str3"} );<br />        pageContext.setAttribute("map", myMap);<br />    %&gt;<br />    在以上代码的HaspMap 中存放了两个对象，其中第二个对象是个字符串数组。HashMap 被存放在PageContext 中。 接下来就可以把这个HashMap 作为请求参数，加入到URL 或 URI 中：<br />    &lt;%-- For this version of the &lt;html:link&gt; tag: --%&gt;<br />    &lt;%-- map = a map with name/value pairs to pass on the url --%&gt;<br />    &lt;html:link page="/HtmlBasic.do" name="map"&gt;<br />        URL encode a parameter based on value in a Map<br />    &lt;/html:link&gt;<br />    &lt;%-- Create the same rewrite string for the above link. --%&gt;<br />    rewrite:&lt;html:rewrite page="/HtmlBasic.do" name="map"/&gt;</p>
		<p>    &lt;html:link&gt; 标签的name 属性指定包含请求变量的HashMap 对象。HashMap 对象中的每一对"key/value" 代表一对或多对"请求参数名/请求参数值"。以上代码生成如下的Html 内容：<br />    &lt;a href="/HtmlBasic.do?myString=myStringValue&amp;amp;myArray=str1&amp;amp;myArray=str2&amp;amp;myArray=str3"&gt;<br />        URL encode a parameter based on value in a Map<br />    &lt;/a&gt;<br />    <br />    rewrite:/HtmlBasic.do?myString=myStringValue&amp;amp;myArray=str1&amp;amp;myArray=str2&amp;amp;myArray=str3</p>
		<p>       </p>
		<p> </p>
<img src ="http://www.blogjava.net/os586/aggbug/80276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-11-09 22:15 <a href="http://www.blogjava.net/os586/archive/2006/11/09/80276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 堆与栈的使用</title><link>http://www.blogjava.net/os586/archive/2006/10/27/77676.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 27 Oct 2006 08:07:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/27/77676.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/77676.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/27/77676.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/77676.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/77676.html</trackback:ping><description><![CDATA[
		<p>Java栈与堆------------转自javaeye.com</p>
		<p>----对这两个概念的不明好久，终于找到一篇好文，拿来共享（http://www.duduwolf.com/cmd.asp?act=tb&amp;id=3 ）</p>
		<p>1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同，Java自动管理栈和堆，程序员不能直接地设置栈或堆。 </p>
		<p>2. 栈的优势是，存取速度比堆要快，仅次于直接位于CPU中的寄存器。但缺点是，存在栈中的数据大小与生存期必须是确定的，缺乏灵活性。另外，栈数据可以共享，详见第3点。堆的优势是可以动态地分配内存大小，生存期也不必事先告诉编译器，Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是，由于要在运行时动态分配内存，存取速度较慢。</p>
		<p>3. Java中的数据类型有两种。</p>
		<p>一种是基本类型(primitive types), 共有8种，即int, short, long, byte, float, double, boolean, char(注意，并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的，称为自动变量。值得注意的是，自动变量存的是字面值，不是类的实例，即不是类的引用，这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用，指向3这个字面值。这些字面值的数据，由于大小可知，生存期可知(这些字面值固定定义在某个程序块里面，程序块退出后，字段值就消失了)，出于追求速度的原因，就存在于栈中。</p>
		<p>另外，栈有一个很重要的特殊性，就是存在栈中的数据可以共享。假设我们同时定义：</p>
		<p>
		</p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<pre>
						<span class="ident">int</span>
						<span class="ident">a</span>
						<span class="punct">=</span>
						<span class="number">3</span>
						<span class="punct">;</span>
						<br />
						<span class="ident">int</span>
						<span class="ident">b</span>
						<span class="punct">=</span>
						<span class="number">3；</span>
				</pre>
		</div>
		<br />编译器先处理int a = 3；首先它会在栈中创建一个变量为a的引用，然后查找有没有字面值为3的地址，没找到，就开辟一个存放3这个字面值的地址，然后将a指向3的地址。接着处理int b = 3；在创建完b的引用变量后，由于在栈中已经有3这个字面值，便将b直接指向3的地址。这样，就出现了a与b同时均指向3的情况。 
<p></p><p>特别注意的是，这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象，如果一个对象引用变量修改了这个对象的内部状态，那么另一个对象引用变量也即刻反映出这个变化。相反，通过字面值的引用来修改其值，不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例，我们定义完a与b的值后，再令a=4；那么，b不会等于4，还是等于3。在编译器内部，遇到a=4；时，它就会重新搜索栈中是否有4的字面值，如果没有，重新开辟地址存放4的值；如果已经有了，则直接将a指向这个地址。因此a值的改变不会影响到b的值。</p><p>另一种是包装类数据，如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中，Java用new()语句来显示地告诉编译器，在运行时才根据需要动态创建，因此比较灵活，但缺点是要占用更多的时间。 4. String是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建，也可以用String str = "abc"；的形式来创建(作为对比，在JDK 5.0之前，你从未见过Integer i = 3;的表达式，因为类与字面值是不能通用的，除了String。而在JDK 5.0中，这种表达式是可以的！因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程，即在Java中，一切都是对象，而对象是类的实例，全部通过new()的形式来创建。Java中的有些类，如DateFormat类，可以通过该类的getInstance()方法来返回一个新创建的类，似乎违反了此原则。其实不然。该类运用了单例模式来返回类的实例，只不过这个实例是在该类内部通过new()来创建的，而getInstance()向外部隐藏了此细节。那为什么在String str = "abc"；中，并没有通过new()来创建实例，是不是违反了上述原则？其实没有。</p><p>5. 关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤：</p><p>(1)先定义一个名为str的对String类的对象引用变量：String str；</p><p>(2)在栈中查找有没有存放值为"abc"的地址，如果没有，则开辟一个存放字面值为"abc"的地址，接着创建一个新的String类的对象o，并将o的字符串值指向这个地址，而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址，则查找对象o，并返回o的地址。</p><p>(3)将str指向对象o的地址。</p><p>值得注意的是，一般String类中字符串值都是直接存值的。但像String str = "abc"；这种场合下，其字符串值却是保存了一个指向存在栈中数据的引用！</p><p>为了更好地说明这个问题，我们可以通过以下的几个代码进行验证。</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">true</span></pre></div><br />注意，我们这里并不用str1.equals(str2)；的方式，因为这将比较两个字符串的值是否相等。==号，根据JDK的说明，只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是，str1与str2是否都指向了同一个对象。 <br />结果说明，JVM创建了两个引用str1和str2，但只创建了一个对象，而且两个引用都指向了这个对象。 
<p></p><p>我们再来更进一步，将以上代码改成：</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">bcd</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">+</span><span class="punct">"</span><span class="string">,</span><span class="punct">"</span><span class="punct">+</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="ident">bcd</span><span class="punct">,</span><span class="ident">abc</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">false</span></pre></div><p></p><p>这就是说，赋值的变化导致了类对象引用的变化，str1指向了另外一个新对象！而str2仍旧指向原来的对象。上例中，当我们将str1的值改为"bcd"时，JVM发现在栈中没有存放该值的地址，便开辟了这个地址，并创建了一个新的对象，其字符串的值指向这个地址。</p><p>事实上，String类被设计成为不可改变(immutable)的类。如果你要改变其值，可以，但JVM在运行时根据新值悄悄创建了一个新对象，然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的，但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中，会带有一定的不良影响。</p><p>再修改原来代码：</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><p></p><p><span class="ident">str1</span><span class="punct">=</span><span class="punct">"</span><span class="string">bcd</span><span class="punct">";</span></p><p><span class="constant">String</span><span class="ident">str3</span><span class="punct">=</span><span class="ident">str1</span><span class="punct">;</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str3</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="ident">bcd</span></p><p><span class="constant">String</span><span class="ident">str4</span><span class="punct">=</span><span class="punct">"</span><span class="string">bcd</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str4</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">true</span></p></pre></div><br />str3这个对象的引用直接指向str1所指向的对象(注意，str3并没有创建新对象)。当str1改完其值后，再创建一个String的引用str4，并指向因str1修改值而创建的新的对象。可以发现，这回str4也没有创建新的对象，从而再次实现栈中数据的共享。 
<p></p><p>我们再接着看以下的代码。</p><p></p><div class="code_title">代码</div><div class="code_div"><pre><span class="constant">String</span><span class="ident">str1</span><span class="punct">=</span><span class="keyword">new</span><span class="constant">String</span><span class="punct">("</span><span class="string">abc</span><span class="punct">");</span><br /><span class="constant">String</span><span class="ident">str2</span><span class="punct">=</span><span class="punct">"</span><span class="string">abc</span><span class="punct">";</span><br /><span class="constant">System</span><span class="punct">.</span><span class="ident">out</span><span class="punct">.</span><span class="ident">println</span><span class="punct">(</span><span class="ident">str1</span><span class="punct">==</span><span class="ident">str2</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">false</span></pre></div><p></p><p>创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。</p><p>String str1 = "abc"; <br />String str2 = new String("abc"); <br />System.out.println(str1==str2); //false </p><p>创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。</p><p>以上两段代码说明，只要是用new()来新建对象的，都会在堆中创建，而且其字符串是单独存值的，即使与栈中的数据相同，也不会与栈中的数据共享。</p><p>6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改，所有的数据类型包装类都不能更改其内部的值。 7. 结论与建议：</p><p>(1)我们在使用诸如String str = "abc"；的格式定义类时，总是想当然地认为，我们创建了String类的对象str。担心陷阱！对象可能并没有被创建！唯一可以肯定的是，指向String类的引用被创建了。至于这个引用到底是否指向了一个新的对象，必须根据上下文来考虑，除非你通过new()方法来显要地创建一个新的对象。因此，更为准确的说法是，我们创建了一个指向String类的对象的引用变量str，这个对象引用变量指向了某个值为"abc"的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。</p><p>(2)使用String str = "abc"；的方式，可以在一定程度上提高程序的运行速度，因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc")；的代码，则一概在堆中创建新对象，而不管其字符串值是否相等，是否有必要创建新对象，从而加重了程序的负担。这个思想应该是享元模式的思想，但JDK的内部在这里实现是否应用了这个模式，不得而知。</p><p>(3)当比较包装类里面的数值是否相等时，用equals()方法；当测试两个包装类的引用是否指向同一个对象时，用==。</p><p>(4)由于String类的immutable性质，当String变量需要经常变换其值时，应该考虑使用StringBuffer类，以提高程序效率。</p><img src ="http://www.blogjava.net/os586/aggbug/77676.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-27 16:07 <a href="http://www.blogjava.net/os586/archive/2006/10/27/77676.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>NoClassDefDoundErr与ClassNotFoundException区别 </title><link>http://www.blogjava.net/os586/archive/2006/10/27/77564.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 27 Oct 2006 02:53:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/27/77564.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/77564.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/27/77564.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/77564.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/77564.html</trackback:ping><description><![CDATA[
		<p>NoClassDefDoundErr与ClassNotFoundException区别</p>
		<p>作者:langm</p>
		<p>版权声明：本文可以自由转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明 <br />作者:langm <br />原文:http://www.matrix.org.cn/resource/article/44/44056_NoClassDefDoundErr.html <br />关键字:NoClassDefDoundErr ClassNotFoundException</p>
		<p>在读这篇文章之前，你最好了解一下Java的Exception机制。</p>
		<p>也许你在开发的过程中经常地见到ClassNotFoundException和NoClassDefFoundErr这两个异常，每每看到之后，都会一概而论的是类没有找到，但有些时候见到他们的时候又有些疑惑（至少我是这样），为什么Java要用两个异常来表示类定义没有找到那？他们之间有什么区别那？</p>
		<p>正巧今天我又碰到了这个问题，顺便的仔细研究了一下这两个异常的区别。 <br />首先： <br />ClassNotFoundException直接继承与Exception，它是一个checked的异常。 <br />NoClassDefFoundErr 继承自Error-&gt;LinkageError ，它是一个unchecked的异常。</p>
		<p>下面让我们看一下两个异常在API文档中的说明</p>
		<p>ClassNotFoundException： <br />当应用尝试用字符串名称通过下面的方法装载一个类时这个类的定义却没有找到时会抛出的异常。 <br />Class.forName <br />ClassLoader.findSystemClass <br />ClassLoader.loadClass <br /><br />NoClassDefFoundErr： <br />当JVM或者ClassLoader实例尝试装载一个类的定义（这通常是一个方法调用或者new表达式创建一个实例过程的一部分）而这个类定义并没有找时所抛出的错误。 <br />当编译的时候可以找到这个类的定义，但是以后这个类不再存在。</p>
		<p>这比较显而易见了吧，读好文档是很重要的事情。这里我就说一下我对这两个类的区别的理解。</p>
		<p>ClassNotFoundException异常只出现在你的应用程序主动的装载类的过程中，这个异常很多时候出现在我们的应用框架在初始化或者运行中动态装载已配置的类的过程中。这种情况下我们应该首先检查我们的配置或者参数是否错误，是否企图装载一个并不存在的类，如果配置没有错误，我们就应该查看Classpath是否配置错误而导致ClassLoader无法找到这个类，也应该检查要装载的类是否在一个jar包中而我们在引入这个jar包的过程中是否有遗漏或错误（这里jar包的版本也是一个需要格外注意的问题，很多时候混乱的jar包版本会造成太多的麻烦）。 <br /><br />NoClassDefFoundErr异常一般出现在我们编译环境和运行环境不一致的情况下，就是说我们有可能在编译过后更改了Classpath或者jar包所以导致在运行的过程中JVM或者ClassLoader无法找到这个类的定义（我曾经在编译后作了一次jar包的清理，然后应用就送给了我一个这样的礼物）。</p>
		<p>我们经常用SDK开发应用，开发的过程中要引入很多jar包，有些SDK也会设定自己的Classpath。编译过程结束后在运行的过程中就要将已开发的应用和所有引入的jar包拷贝到应用服务器的相应目录下才可以运行，而应用服务器使用的Classpath也很有可能与SDK的不同，在这个过程中就有很大的几率造成双方环境不一致。所以很多开发者就会遇到在SDK中可以编译，运行也没有问题，但是同样的程序放到应用服务器上就出现NoClassDefFoundErr这个异常这种情况，这是让初学者很挠头的一个问题。</p>
		<p>以上就是我对这两个异常的一点个人理解，希望对各位开发者有所帮助，可以让各位开发者在以后的开发过程中能够更快的找到问题所在。祝开发顺利</p>
<img src ="http://www.blogjava.net/os586/aggbug/77564.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-27 10:53 <a href="http://www.blogjava.net/os586/archive/2006/10/27/77564.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>澄清Java语言接口与继承的本质</title><link>http://www.blogjava.net/os586/archive/2006/10/26/77316.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 26 Oct 2006 00:55:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/26/77316.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/77316.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/26/77316.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/77316.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/77316.html</trackback:ping><description><![CDATA[
		<table style="FLOAT: left; MARGIN: 0px 10px 10px" cellspacing="0" cellpadding="0" align="left" border="0">
				<tbody>
						<tr>
								<td>
										<script type="text/javascript">
												<!--
						csdn_AD_Position_GroupID = "{e025b96b-2fda-4e82-84ef-3e0772838ed3}";
						csdn_AD_Page_Url = document.location;
						csdn_AD_CurrPage_CharSet = "gb2312";
						//-->
										</script>
										<script src="http://ggmm.csdn.net/AD/Show_JavaScript_AD.js" type="text/javascript">
										</script>
										<script language="JavaScript1.1" src="http://ggmm.csdn.net/AD/ShowJavaScriptAD.aspx?show=true&amp;position={e025b96b-2fda-4e82-84ef-3e0772838ed3}&amp;CharSet=gb2312">
										</script>
										<br />
										<script src="http://news.csdn.net/ad/news_textlink.js" type="text/javascript">
										</script>
								</td>
						</tr>
				</tbody>
		</table>大多数人认为，接口的意义在于顶替多重继承。众所周知Java没有c++那样多重继承的机制，但是却能够实作多个接口。其实这样做是很牵强的，接口和继承是完全不同的东西，接口没有能力代替多重继承，也没有这个义务。接口的作用，一言以蔽之，就是标志类的类别（type of class）。把不同类型的类归于不同的接口，可以更好的管理他们。OO的精髓，我以为，是对对象的抽象，最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言（比如c++、java、c#等），就是因为设计模式所研究的，实际上就是如何合理的去抽象。（cowboy的名言是“抽象就是抽去像的部分”，看似调侃，实乃至理）。<br /><br />　　设计模式中最基础的是工厂模式（Factory），在我最近的一个很简单的应用中，我想尽量的让我的程序能够在多个数据库间移植，当然，这涉及很多问题，单是如何兼容不同DBMS的SQL就让人头痛。我们不妨先把问题简单化，只考虑如何连接不同的数据库。<br /><br />　　假设我有很多个类，分别是Mysql.java、SQLServer.java、Oracle.java、DB2.java，他们分别连接不同的数据库，统一返回一个Connection对象，并且都有一个close方法，用于关闭连接。只需要针对你的DBMS，选择不同的类，就可以用了，但是我的用户他会使用什么数据库？我不知道，我希望的是尽量少的修改代码，就能满足他的需要。我可以抽象如下接口：<br /><br />package org.bromon.test;<br />public interface DB<br />{<br />　　java.sql.Connection openDB(String url,String user,String password);<br />　　void close();<br />} <br /><br />　　这个接口只定义两个方法，没有任何有实际意义的代码，具体的代码由实作这个接口的类来给出，比如Mysql.java：<br /><br />Package org.bromon.test;<br />import java.sql.*;<br />public class Mysql implements DB<br />{<br />　　private String url=”jdbc:mysql:localhost:3306/test”;<br />　　private String user=”root”;<br />　　private String password=””;<br />　　private Connection conn;<br />　　public Connection openDB(url,user,password)<br />　　{<br />　　　　//连接数据库的代码<br />　　}<br /><br />　　public void close()<br />　　{<br />　　　　//关闭数据库<br />　　}<br />} <br /><br />　　类似的当然还有Oracle.java等等，接口DB给这些类归了个类，在应用程序中我们这样定义对象：<br /><br />　　org.bromon.test.DB myDB;<br /><br />　　使用myDB来操作数据库，就可以不用管实际上我所使用的是哪个类，这就是所谓的“开-闭”原则。但是问题在于接口是不能实例化的，myDB=new DB()，这样的代码是绝对错误的，我们只能myDB=new Mysql()或者myDB=new Oracle()。麻烦了，我还是需要指定具体实例化的是哪个类，用了接口跟没用一样。所以我们需要一个工厂：<br /><br />package org.bromon.test;<br />public class DBFactory<br />{<br />　　public static DB Connection getConn()<br />　　{<br />　　　　Return(new Mysql());<br />　　}<br />} <br /><br />　　所以实例化的代码变成：myDB=DBFactory.getConn()；<br /><br />　　这就是23种模式中最基础的普通工厂(Factory)，工厂类负责具体实例化哪个类，而其他的程序逻辑都是针对DB这个接口进行操作，这就是“针对接口编程”。责任都被推卸给工厂类了，当然你也可以继续定义工厂接口，继续把责任上抛，这就演变成抽象工厂(Abstract Factory)。<br /><br />　　整个过程中接口不负责任何具体操作，其他的程序要连接数据库的话，只需要构造一个DB对象就OK，而不管工厂类如何变化。这就是接口的意义----抽象。<br /><br />　　继承的概念不用多说，很好理解。为什么要继承呢？因为你想重用代码？这绝对不是理由，继承的意义也在于抽象，而不是代码重用。如果对象A有一个run()方法，对象B也想有这个方法，所以有人就Class B extends A。这是不经大脑的做法。如果在B中实例化一个A，调用A的Run()方法，是不是可以达到同样的目的？如下：<br /><br />Class B<br />{<br />　　A a=new A();<br />　　a.run();<br />} <br /><br />　　这就是利用类的聚合来重用代码，是委派模式的雏形，是GoF一贯倡导的做法。<br /><br />　　那么继承的意义何在？其实这是历史原因造成的，最开始的OO语言只有继承，没有接口，所以只能以继承来实现抽象，请一定注意，继承的本意在于抽象，而非代码重用（虽然继承也有这个作用），这是很多Java烂书最严重的错误之一，它们所造成的阴影，我至今还没有完全摆脱，坏书害人啊，尤其是入门类的，流毒太大。什么时候应该使用继承？只在抽象类中使用，其他情况下尽量不使用。抽象类也是不能实例化的，它仅仅提供一个模版而已，这就很能说明问题。<br /><br />　　软件开发的万恶之源，一是重复代码而不是重用代码，二是烂用继承，尤以c++程序员为甚。Java中取缔多重继承，目的就是制止烂用继承，实是非常明智的做法，不过很多人都不理解。Java能够更好的体现设计，这是让我入迷的原因之一。<img src ="http://www.blogjava.net/os586/aggbug/77316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-26 08:55 <a href="http://www.blogjava.net/os586/archive/2006/10/26/77316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>再论Domaion Object [From JavaEye]</title><link>http://www.blogjava.net/os586/archive/2006/10/19/76082.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 19 Oct 2006 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/19/76082.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/76082.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/19/76082.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/76082.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/76082.html</trackback:ping><description><![CDATA[
		<p>既然大家都统一了观点，那么就有了一个很好的讨论问题的基础了。Martin Fowler的Domain Model，或者说我们的第二种模型难道是完美无缺的吗？当然不是，接下来我就要分析一下它的不足，以及可能的解决办法，而这些都来源于我个人的实践探索。</p>
		<p>在第二种模型中，我们可以清楚的把这4个类分为三层：</p>
		<p>1、实体类层，即Item，带有domain logic的domain object <br />2、DAO层，即ItemDao和ItemDaoHibernateImpl，抽象持久化操作的接口和实现类 <br />3、业务逻辑层，即ItemManager，接受容器事务控制，向Web层提供统一的服务调用</p>
		<p>在这三层中我们大家可以看到，domain object和DAO都是非常稳定的层，其实原因也很简单，因为domain object是映射数据库字段的，数据库字段不会频繁变动，所以domain object也相对稳定，而面向数据库持久化编程的DAO层也不过就是CRUD而已，不会有更多的花样，所以也很稳定。</p>
		<p>问题就在于这个充当business workflow facade的业务逻辑对象，它的变动是相当频繁的。<span style="COLOR: red">业务逻辑对象通常都是无状态的、受事务控制的、Singleton类</span>，我们可以考察一下业务逻辑对象都有哪几类业务逻辑方法：</p>
		<p>
				<span style="COLOR: red">第一类：DAO接口方法的代理</span>，就是上面例子中的loadItemById方法和findAll方法。</p>
		<p>ItemManager之所以要代理这种类，目的有两个：<span style="COLOR: red">向Web层提供统一的服务调用入口点和给持久化方法增加事务控制功能</span>。这两点都很容易理解，你不能既给Web层程序员提供xxxManager，也给他提供xxxDao，所以你需要用xxxManager封装xxxDao，在这里，充当了一个简单代理功能；而事务控制也是持久化方法必须的，事务可能需要跨越多个DAO方法调用，所以必须放在业务逻辑层，而不能放在DAO层。</p>
		<p>但是必须看到，对于一个典型的web应用来说，绝大多数的业务逻辑都是简单的CRUD逻辑，所以这种情况下，针对每个DAO方法，xxxManager都需要提供一个对应的封装方法，这不但是非常枯燥的，也是令人感觉非常不好的。</p>
		<p>
				<span style="COLOR: red">第二类：domain logic的方法代理</span>。就是上面例子中placeBid方法。虽然Item已经有了placeBid方法，但是ItemManager仍然需要封装一下Item的placeBid，然后再提供一个简单封装之后的代理方法。</p>
		<p>这和第一种情况类似，其原因也一样，也是为了给Web层提供一个统一的服务调用入口点和给隐式的持久化动作提供事务控制。</p>
		<p>同样，和第一种情况一样，针对每个domain logic方法，xxxManager都需要提供一个对应的封装方法，同样是枯燥的，令人不爽的。</p>
		<p>
				<span style="COLOR: red">第三类：需要多个domain object和DAO参与协作的business workflow</span>。这种情况是业务逻辑对象真正应该完成的职责。</p>
		<p>在这个简单的例子中，没有涉及到这种情况，不过大家都可以想像的出来这种应用场景，因此不必举例说明了。</p>
		<p>通过上面的分析可以看出，只有第三类业务逻辑方法才是业务逻辑对象真正应该承担的职责，而前两类业务逻辑方法都是“无奈之举”，不得不为之的事情，不但枯燥，而且令人沮丧。</p>
		<p>分析完了业务逻辑对象，我们再回头看一下domain object，我们要仔细考察一下domain logic的话，会发现domain logic也分为两类：</p>
		<p>
				<span style="COLOR: red">第一类：需要持久层框架隐式的实现透明持久化的domain logic</span>，例如Item的placeBid方法中的这一句： <br /></p>
		<div class="code_title">代码</div>
		<div class="code_div">
				<pre>
						<span class="ident">this</span>
						<span class="punct">.</span>
						<span class="ident">getBids</span>
						<span class="punct">().</span>
						<span class="ident">add</span>
						<span class="punct">(</span>
						<span class="ident">newBid</span>
						<span class="punct">);</span>
				</pre>
		</div>
		<br />上面已经着重提到，虽然这仅仅只是一个Java集合的添加新元素的操作，但是实际上通过事务的控制，会潜在的触发两条SQL：一条是insert一条记录到bid表，一条是更新item表相应的记录。如果我们让Item脱离Hibernate进行单元测试，它就是一个单纯的Java集合操作，如果我们把他加入到Hibernate框架中，他就会潜在的触发两条SQL，<span style="COLOR: red">这就是隐式的依赖于持久化的domain logic</span>。 <br />特别请注意的一点是：在没有Hibernate/JDO这类可以实现“透明的持久化”工具出现之前，这类domain logic是无法实现的。 
<p></p><p>对于这一类domain logic，业务逻辑对象必须提供相应的封装方法，以实现事务控制。</p><p><span style="COLOR: red">第二类：完全不依赖持久化的domain logic</span>，例如readonly例子中的Topic，如下：</p><p></p><div class="code_title">java代码</div><div class="code_div"><pre><span class="keyword">class </span><span class="class">Topic</span><span class="punct">{</span><br /><span class="ident">boolean</span><span class="ident">isAllowReply</span><span class="punct">()</span><span class="punct">{</span><br /><span class="constant">Calendar</span><span class="ident">dueDate</span><span class="punct">=</span><span class="constant">Calendar</span><span class="punct">.</span><span class="ident">getInstance</span><span class="punct">();</span><br /><span class="ident">dueDate</span><span class="punct">.</span><span class="ident">setTime</span><span class="punct">(</span><span class="ident">lastUpdatedTime</span><span class="punct">);</span><br /><span class="ident">dueDate</span><span class="punct">.</span><span class="ident">add</span><span class="punct">(</span><span class="constant">Calendar</span><span class="punct">.</span><span class="ident">DATE</span><span class="punct">,</span><span class="ident">forum</span><span class="punct">.</span><span class="ident">timeToLive</span><span class="punct">);</span><br /><br /><span class="constant">Date</span><span class="ident">now</span><span class="punct">=</span><span class="keyword">new</span><span class="constant">Date</span><span class="punct">();</span><br /><span class="keyword">return</span><span class="ident">now</span><span class="punct">.</span><span class="ident">after</span><span class="punct">(</span><span class="ident">dueDate</span><span class="punct">.</span><span class="ident">getTime</span><span class="punct">());</span><br /><span class="punct">}</span><br /><span class="punct">}</span></pre></div><p></p><p>注意这个isAllowReply方法，他和持久化完全不发生一丁点关系。在实际的开发中，我们同样会遇到很多这种不需要持久化的业务逻辑(主要发生在日期运算、数值运算和枚举运算方面)，这种domain logic不管脱离不脱离所在的框架，它的行为都是一致的。对于这种domain logic，业务逻辑层并不需要提供封装方法，它可以适用于任何场合。</p><img src ="http://www.blogjava.net/os586/aggbug/76082.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-19 10:01 <a href="http://www.blogjava.net/os586/archive/2006/10/19/76082.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>总结一下最近关于domain object以及相关的讨论 [From:JAVAEYE]</title><link>http://www.blogjava.net/os586/archive/2006/10/19/76070.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Thu, 19 Oct 2006 01:19:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/10/19/76070.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/76070.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/10/19/76070.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/76070.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/76070.html</trackback:ping><description><![CDATA[
		<p>在最近的围绕domain object的讨论中浮现出来了三种模型，(还有一些其他的旁枝，不一一分析了)，经过一番讨论，各种问题逐渐清晰起来，在这里我试图做一个总结，便于大家了解和掌握。</p>
		<p>第一种模型：只有getter/setter方法的纯数据类，所有的业务逻辑完全由business object来完成(又称TransactionScript)，这种模型下的domain object被Martin Fowler称之为“贫血的domain object”。下面用举一个具体的代码来说明，代码来自Hibernate的caveatemptor，但经过我的改写：</p>
		<p>一个实体类叫做Item，指的是一个拍卖项目 <br />一个DAO接口类叫做ItemDao <br />一个DAO接口实现类叫做ItemDaoHibernateImpl <br />一个业务逻辑类叫做ItemManager(或者叫做ItemService) </p>
		<p>
		</p>
		<div class="code_title">java代码</div>
		<div class="code_div">
				<pre>
						<span class="keyword">public</span>
						<span class="keyword">class </span>
						<span class="class">Item</span>
						<span class="keyword">implements</span>
						<span class="constant">Serializable</span>
						<span class="punct">{</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Long</span>
						<span class="ident">id</span>
						<span class="punct">=</span>
						<span class="keyword">null</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="ident">int</span>
						<span class="ident">version</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">String</span>
						<span class="ident">name</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">User</span>
						<span class="ident">seller</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">String</span>
						<span class="ident">description</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">MonetaryAmount</span>
						<span class="ident">initialPrice</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">MonetaryAmount</span>
						<span class="ident">reservePrice</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Date</span>
						<span class="ident">startDate</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Date</span>
						<span class="ident">endDate</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Set</span>
						<span class="ident">categorizedItems</span>
						<span class="punct">=</span>
						<span class="keyword">new</span>
						<span class="constant">HashSet</span>
						<span class="punct">();</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Collection</span>
						<span class="ident">bids</span>
						<span class="punct">=</span>
						<span class="keyword">new</span>
						<span class="constant">ArrayList</span>
						<span class="punct">();</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Bid</span>
						<span class="ident">successfulBid</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">ItemState</span>
						<span class="ident">state</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">User</span>
						<span class="ident">approvedBy</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Date</span>
						<span class="ident">approvalDatetime</span>
						<span class="punct">;</span>
						<br />
						<span class="keyword">private</span>
						<span class="constant">Date</span>
						<span class="ident">created</span>
						<span class="punct">=</span>
						<span class="keyword">new</span>
						<span class="constant">Date</span>
						<span class="punct">();</span>
						<br />
						<span class="punct">/</span>
						<span class="regex">
						</span>
						<span class="punct">/</span>
						<span class="ident">getter</span>
						<span class="punct">/</span>
						<span class="ident">setter方法省略不写，避免篇幅太长</span>
						<br />
						<span class="punct">}</span>
				</pre>
		</div>
		<p>
		</p>
		<p>
		</p>
		<div class="code_title">java代码</div>
		<div class="code_div">
				<pre>
						<span class="keyword">public</span>
						<span class="keyword">interface</span>
						<span class="constant">ItemDao</span>
						<span class="punct">{</span>
						<br />
						<span class="keyword">public</span>
						<span class="constant">Item</span>
						<span class="ident">getItemById</span>
						<span class="punct">(</span>
						<span class="constant">Long</span>
						<span class="ident">id</span>
						<span class="punct">);</span>
						<br />
						<span class="keyword">public</span>
						<span class="constant">Collection</span>
						<span class="ident">findAll</span>
						<span class="punct">();</span>
						<br />
						<span class="keyword">public</span>
						<span class="ident">void</span>
						<span class="ident">updateItem</span>
						<span class="punct">(</span>
						<span class="constant">Item</span>
						<span class="ident">item</span>
						<span class="punct">);</span>
						<br />
						<span class="punct">}</span>
				</pre>
		</div>
		<p>
		</p>
		<p>ItemDao定义持久化操作的接口，用于隔离持久化代码。</p>
		<p>
		</p>
		<div class="code_title">java代码</div>
		<div class="code_div">
				<pre>
						<span class="keyword">public</span>
						<span class="keyword">class </span>
						<span class="class">ItemDaoHibernateImpl</span>
						<span class="keyword">implements</span>
						<span class="constant">ItemDao</span>
						<span class="keyword">extends</span>
						<span class="constant">HibernateDaoSupport</span>
						<span class="punct">{</span>
						<br />
						<span class="keyword">public</span>
						<span class="constant">Item</span>
						<span class="ident">getItemById</span>
						<span class="punct">(</span>
						<span class="constant">Long</span>
						<span class="ident">id</span>
						<span class="punct">)</span>
						<span class="punct">{</span>
						<br />
						<span class="keyword">return</span>
						<span class="punct">(</span>
						<span class="constant">Item</span>
						<span class="punct">)</span>
						<span class="ident">getHibernateTemplate</span>
						<span class="punct">().</span>
						<span class="ident">load</span>
						<span class="punct">(</span>
						<span class="constant">Item</span>
						<span class="punct">.</span>
						<span class="ident">class</span>
						<span class="punct">,</span>
						<span class="ident">id</span>
						<span class="punct">);</span>
						<br />
						<span class="punct">}</span>
						<br />
						<span class="keyword">public</span>
						<span class="constant">Collection</span>
						<span class="ident">findAll</span>
						<span class="punct">()</span>
						<span class="punct">{</span>
						<br />
						<span class="keyword">return</span>
						<span class="punct">(</span>
						<span class="constant">List</span>
						<span class="punct">)</span>
						<span class="ident">getHibernateTemplate</span>
						<span class="punct">().</span>
						<span class="ident">find</span>
						<span class="punct">("</span>
						<span class="string">from Item</span>
						<span class="punct">");</span>
						<br />
						<span class="punct">}</span>
						<br />
						<span class="keyword">public</span>
						<span class="ident">void</span>
						<span class="ident">updateItem</span>
						<span class="punct">(</span>
						<span class="constant">Item</span>
						<span class="ident">item</span>
						<span class="punct">)</span>
						<span class="punct">{</span>
						<br />
						<span class="ident">getHibernateTemplate</span>
						<span class="punct">().</span>
						<span class="ident">update</span>
						<span class="punct">(</span>
						<span class="ident">item</span>
						<span class="punct">);</span>
						<br />
						<span class="punct">}</span>
						<br />
						<span class="punct">}</span>
				</pre>
		</div>
		<br />ItemDaoHibernateImpl完成具体的持久化工作，请注意，数据库资源的获取和释放是在ItemDaoHibernateImpl里面处理的，每个DAO方法调用之前打开Session，DAO方法调用之后，关闭Session。(Session放在ThreadLocal中，保证一次调用只打开关闭一次) 
<p></p><p></p><div class="code_title">java代码</div><div class="code_div"><pre><span class="keyword">public</span><span class="keyword">class </span><span class="class">ItemManager</span><span class="punct">{</span><br /><span class="keyword">private</span><span class="constant">ItemDao</span><span class="ident">itemDao</span><span class="punct">;</span><br /><span class="keyword">public</span><span class="ident">void</span><span class="ident">setItemDao</span><span class="punct">(</span><span class="constant">ItemDao</span><span class="ident">itemDao</span><span class="punct">)</span><span class="punct">{</span><span class="ident">this</span><span class="punct">.</span><span class="ident">itemDao</span><span class="punct">=</span><span class="ident">itemDao</span><span class="punct">;}</span><br /><span class="keyword">public</span><span class="constant">Bid</span><span class="ident">loadItemById</span><span class="punct">(</span><span class="constant">Long</span><span class="ident">id</span><span class="punct">)</span><span class="punct">{</span><br /><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">loadItemById</span><span class="punct">(</span><span class="ident">id</span><span class="punct">);</span><br /><span class="punct">}</span><br /><span class="keyword">public</span><span class="constant">Collection</span><span class="ident">listAllItems</span><span class="punct">()</span><span class="punct">{</span><br /><span class="keyword">return</span><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">findAll</span><span class="punct">();</span><br /><span class="punct">}</span><br /><span class="keyword">public</span><span class="constant">Bid</span><span class="ident">placeBid</span><span class="punct">(</span><span class="constant">Item</span><span class="ident">item</span><span class="punct">,</span><span class="constant">User</span><span class="ident">bidder</span><span class="punct">,</span><span class="constant">MonetaryAmount</span><span class="ident">bidAmount</span><span class="punct">,</span><br /><span class="constant">Bid</span><span class="ident">currentMaxBid</span><span class="punct">,</span><span class="constant">Bid</span><span class="ident">currentMinBid</span><span class="punct">)</span><span class="keyword">throws</span><span class="constant">BusinessException</span><span class="punct">{</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="ident">currentMaxBid</span><span class="punct">!=</span><span class="keyword">null</span><span class="punct">&amp;&amp;</span><span class="ident">currentMaxBid</span><span class="punct">.</span><span class="ident">getAmount</span><span class="punct">().</span><span class="ident">compareTo</span><span class="punct">(</span><span class="ident">bidAmount</span><span class="punct">)</span><span class="punct">&gt;</span><span class="number">0</span><span class="punct">)</span><span class="punct">{</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Bid too low.</span><span class="punct">");</span><br /><span class="punct">}</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Auction</span><span class="ident">is</span><span class="ident">active</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="punct">!</span><span class="ident">state</span><span class="punct">.</span><span class="ident">equals</span><span class="punct">(</span><span class="constant">ItemState</span><span class="punct">.</span><span class="ident">ACTIVE</span><span class="punct">)</span><span class="punct">)</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Auction is not active yet.</span><span class="punct">");</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Auction</span><span class="ident">still</span><span class="ident">valid</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="ident">item</span><span class="punct">.</span><span class="ident">getEndDate</span><span class="punct">().</span><span class="ident">before</span><span class="punct">(</span><span class="keyword">new</span><span class="constant">Date</span><span class="punct">()</span><span class="punct">)</span><span class="punct">)</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Can't place new bid, auction already ended.</span><span class="punct">");</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Create</span><span class="keyword">new</span><span class="constant">Bid</span><br /><span class="constant">Bid</span><span class="ident">newBid</span><span class="punct">=</span><span class="keyword">new</span><span class="constant">Bid</span><span class="punct">(</span><span class="ident">bidAmount</span><span class="punct">,</span><span class="ident">item</span><span class="punct">,</span><span class="ident">bidder</span><span class="punct">);</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Place</span><span class="ident">bid</span><span class="keyword">for</span><span class="ident">this</span><span class="constant">Item</span><br /><span class="ident">item</span><span class="punct">.</span><span class="ident">getBids</span><span class="punct">().</span><span class="ident">add</span><span class="punct">(</span><span class="ident">newBid</span><span class="punct">);</span><br /><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">update</span><span class="punct">(</span><span class="ident">item</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span>  调用<span class="constant">DAO完成持久化操作</span><br /><span class="keyword">return</span><span class="ident">newBid</span><span class="punct">;</span><br /><span class="punct">}</span><br /><span class="punct">}</span></pre></div><p></p><p>事务的管理是在ItemManger这一层完成的，ItemManager实现具体的业务逻辑。除了常见的和CRUD有关的简单逻辑之外，这里还有一个placeBid的逻辑，即项目的竞标。</p><p>以上是一个完整的第一种模型的示例代码。在这个示例中，placeBid，loadItemById，findAll等等业务逻辑统统放在ItemManager中实现，而Item只有getter/setter方法。<br /><br /><br /><br /><br /><br /></p><p>第二种模型，也就是Martin Fowler指的rich domain object是下面这样子的：</p><p>一个带有业务逻辑的实体类，即domain object是Item <br />一个DAO接口ItemDao <br />一个DAO实现ItemDaoHibernateImpl <br />一个业务逻辑对象ItemManager</p><p></p><div class="code_title">java代码</div><div class="code_div"><pre><span class="keyword">public</span><span class="keyword">class </span><span class="class">Item</span><span class="keyword">implements</span><span class="constant">Serializable</span><span class="punct">{</span><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span>  所有的属性和<span class="ident">getter</span><span class="punct">/</span><span class="ident">setter方法同上，省略</span><br /><span class="keyword">public</span><span class="constant">Bid</span><span class="ident">placeBid</span><span class="punct">(</span><span class="constant">User</span><span class="ident">bidder</span><span class="punct">,</span><span class="constant">MonetaryAmount</span><span class="ident">bidAmount</span><span class="punct">,</span><br /><span class="constant">Bid</span><span class="ident">currentMaxBid</span><span class="punct">,</span><span class="constant">Bid</span><span class="ident">currentMinBid</span><span class="punct">)</span><br /><span class="keyword">throws</span><span class="constant">BusinessException</span><span class="punct">{</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Check</span><span class="ident">highest</span><span class="ident">bid</span><span class="punct">(</span><span class="ident">can</span><span class="ident">also</span><span class="ident">be</span><span class="ident">a</span><span class="ident">different</span><span class="constant">Strategy</span><span class="punct">(</span><span class="ident">pattern</span><span class="punct">))</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="ident">currentMaxBid</span><span class="punct">!=</span><span class="keyword">null</span><span class="punct">&amp;&amp;</span><span class="ident">currentMaxBid</span><span class="punct">.</span><span class="ident">getAmount</span><span class="punct">().</span><span class="ident">compareTo</span><span class="punct">(</span><span class="ident">bidAmount</span><span class="punct">)</span><span class="punct">&gt;</span><span class="number">0</span><span class="punct">)</span><span class="punct">{</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Bid too low.</span><span class="punct">");</span><br /><span class="punct">}</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Auction</span><span class="ident">is</span><span class="ident">active</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="punct">!</span><span class="ident">state</span><span class="punct">.</span><span class="ident">equals</span><span class="punct">(</span><span class="constant">ItemState</span><span class="punct">.</span><span class="ident">ACTIVE</span><span class="punct">)</span><span class="punct">)</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Auction is not active yet.</span><span class="punct">");</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Auction</span><span class="ident">still</span><span class="ident">valid</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="ident">this</span><span class="punct">.</span><span class="ident">getEndDate</span><span class="punct">().</span><span class="ident">before</span><span class="punct">(</span><span class="keyword">new</span><span class="constant">Date</span><span class="punct">()</span><span class="punct">)</span><span class="punct">)</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Can't place new bid, auction already ended.</span><span class="punct">");</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Create</span><span class="keyword">new</span><span class="constant">Bid</span><br /><span class="constant">Bid</span><span class="ident">newBid</span><span class="punct">=</span><span class="keyword">new</span><span class="constant">Bid</span><span class="punct">(</span><span class="ident">bidAmount</span><span class="punct">,</span><span class="ident">this</span><span class="punct">,</span><span class="ident">bidder</span><span class="punct">);</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Place</span><span class="ident">bid</span><span class="keyword">for</span><span class="ident">this</span><span class="constant">Item</span><br /><span class="ident">this</span><span class="punct">.</span><span class="ident">getBids</span><span class="punct">.</span><span class="ident">add</span><span class="punct">(</span><span class="ident">newBid</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span> 请注意这一句，透明的进行了持久化，但是不能在这里调用<span class="constant">ItemDao，Item不能对ItemDao产生依赖！</span><br /><br /><span class="keyword">return</span><span class="ident">newBid</span><span class="punct">;</span><br /><span class="punct">}</span><br /><span class="punct">}</span></pre></div><p></p><p>竞标这个业务逻辑被放入到Item中来。请注意this.getBids.add(newBid); 如果没有Hibernate或者JDO这种O/R Mapping的支持，我们是无法实现这种透明的持久化行为的。但是请注意，Item里面不能去调用ItemDAO，对ItemDAO产生依赖！</p><p>ItemDao和ItemDaoHibernateImpl的代码同上，省略。</p><p></p><div class="code_title">java代码</div><div class="code_div"><pre><span class="keyword">public</span><span class="keyword">class </span><span class="class">ItemManager</span><span class="punct">{</span><br /><span class="keyword">private</span><span class="constant">ItemDao</span><span class="ident">itemDao</span><span class="punct">;</span><br /><span class="keyword">public</span><span class="ident">void</span><span class="ident">setItemDao</span><span class="punct">(</span><span class="constant">ItemDao</span><span class="ident">itemDao</span><span class="punct">)</span><span class="punct">{</span><span class="ident">this</span><span class="punct">.</span><span class="ident">itemDao</span><span class="punct">=</span><span class="ident">itemDao</span><span class="punct">;}</span><br /><span class="keyword">public</span><span class="constant">Bid</span><span class="ident">loadItemById</span><span class="punct">(</span><span class="constant">Long</span><span class="ident">id</span><span class="punct">)</span><span class="punct">{</span><br /><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">loadItemById</span><span class="punct">(</span><span class="ident">id</span><span class="punct">);</span><br /><span class="punct">}</span><br /><span class="keyword">public</span><span class="constant">Collection</span><span class="ident">listAllItems</span><span class="punct">()</span><span class="punct">{</span><br /><span class="keyword">return</span><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">findAll</span><span class="punct">();</span><br /><span class="punct">}</span><br /><span class="keyword">public</span><span class="constant">Bid</span><span class="ident">placeBid</span><span class="punct">(</span><span class="constant">Item</span><span class="ident">item</span><span class="punct">,</span><span class="constant">User</span><span class="ident">bidder</span><span class="punct">,</span><span class="constant">MonetaryAmount</span><span class="ident">bidAmount</span><span class="punct">,</span><br /><span class="constant">Bid</span><span class="ident">currentMaxBid</span><span class="punct">,</span><span class="constant">Bid</span><span class="ident">currentMinBid</span><span class="punct">)</span><span class="keyword">throws</span><span class="constant">BusinessException</span><span class="punct">{</span><br /><span class="ident">item</span><span class="punct">.</span><span class="ident">placeBid</span><span class="punct">(</span><span class="ident">bidder</span><span class="punct">,</span><span class="ident">bidAmount</span><span class="punct">,</span><span class="ident">currentMaxBid</span><span class="punct">,</span><span class="ident">currentMinBid</span><span class="punct">);</span><br /><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">update</span><span class="punct">(</span><span class="ident">item</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span> 必须显式的调用<span class="constant">DAO，保持持久化</span><br /><span class="punct">}</span><br /><span class="punct">}</span></pre></div><p></p><p>在第二种模型中，placeBid业务逻辑是放在Item中实现的，而loadItemById和findAll业务逻辑是放在ItemManager中实现的。不过值得注意的是，即使placeBid业务逻辑放在Item中，你仍然需要在ItemManager中简单的封装一层，以保证对placeBid业务逻辑进行事务的管理和持久化的触发。</p><p>这种模型是Martin Fowler所指的真正的domain model。在这种模型中，有三个业务逻辑方法：placeBid，loadItemById和findAll，现在的问题是哪个逻辑应该放在Item中，哪个逻辑应该放在ItemManager中。在我们这个例子中，placeBid放在Item中(但是ItemManager也需要对它进行简单的封装)，loadItemById和findAll是放在ItemManager中的。</p><p>切分的原则是什么呢？ Rod Johnson提出原则是“case by case”，可重用度高的，和domain object状态密切关联的放在Item中，可重用度低的，和domain object状态没有密切关联的放在ItemManager中。</p><p><span style="COLOR: red">我提出的原则是：看业务方法是否显式的依赖持久化。</span></p><p>Item的placeBid这个业务逻辑方法没有显式的对持久化ItemDao接口产生依赖，所以要放在Item中。<span style="COLOR: red">请注意，如果脱离了Hibernate这个持久化框架，Item这个domain object是可以进行单元测试的，他不依赖于Hibernate的持久化机制。它是一个独立的，可移植的，完整的，自包含的域对象</span>。</p><p>而loadItemById和findAll这两个业务逻辑方法是必须显式的对持久化ItemDao接口产生依赖，否则这个业务逻辑就无法完成。如果你要把这两个方法放在Item中，那么Item就无法脱离Hibernate框架，无法在Hibernate框架之外独立存在。<br /><br /><br /><br /></p><p>第三种模型印象中好像是firebody或者是Archie提出的(也有可能不是，记不清楚了)，简单的来说，这种模型就是把第二种模型的domain object和business object合二为一了。所以ItemManager就不需要了，在这种模型下面，只有三个类，他们分别是：</p><p>Item：包含了实体类信息，也包含了所有的业务逻辑 <br />ItemDao：持久化DAO接口类 <br />ItemDaoHibernateImpl：DAO接口的实现类</p><p>由于ItemDao和ItemDaoHibernateImpl和上面完全相同，就省略了。</p><p></p><div class="code_title">java代码</div><div class="code_div"><pre><span class="keyword">public</span><span class="keyword">class </span><span class="class">Item</span><span class="keyword">implements</span><span class="constant">Serializable</span><span class="punct">{</span><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span>  所有的属性和<span class="ident">getter</span><span class="punct">/</span><span class="ident">setter方法都省略</span><br /><span class="keyword">private</span><span class="ident">static</span><span class="constant">ItemDao</span><span class="ident">itemDao</span><span class="punct">;</span><br /><span class="keyword">public</span><span class="ident">void</span><span class="ident">setItemDao</span><span class="punct">(</span><span class="constant">ItemDao</span><span class="ident">itemDao</span><span class="punct">)</span><span class="punct">{</span><span class="ident">this</span><span class="punct">.</span><span class="ident">itemDao</span><span class="punct">=</span><span class="ident">itemDao</span><span class="punct">;}</span><br /><br /><span class="keyword">public</span><span class="ident">static</span><span class="constant">Item</span><span class="ident">loadItemById</span><span class="punct">(</span><span class="constant">Long</span><span class="ident">id</span><span class="punct">)</span><span class="punct">{</span><br /><span class="keyword">return</span><span class="punct">(</span><span class="constant">Item</span><span class="punct">)</span><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">loadItemById</span><span class="punct">(</span><span class="ident">id</span><span class="punct">);</span><br /><span class="punct">}</span><br /><span class="keyword">public</span><span class="ident">static</span><span class="constant">Collection</span><span class="ident">findAll</span><span class="punct">()</span><span class="punct">{</span><br /><span class="keyword">return</span><span class="punct">(</span><span class="constant">List</span><span class="punct">)</span><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">findAll</span><span class="punct">();</span><br /><span class="punct">}</span><p></p><p><span class="keyword">public</span><span class="constant">Bid</span><span class="ident">placeBid</span><span class="punct">(</span><span class="constant">User</span><span class="ident">bidder</span><span class="punct">,</span><span class="constant">MonetaryAmount</span><span class="ident">bidAmount</span><span class="punct">,</span><br /><span class="constant">Bid</span><span class="ident">currentMaxBid</span><span class="punct">,</span><span class="constant">Bid</span><span class="ident">currentMinBid</span><span class="punct">)</span><br /><span class="keyword">throws</span><span class="constant">BusinessException</span><span class="punct">{</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Check</span><span class="ident">highest</span><span class="ident">bid</span><span class="punct">(</span><span class="ident">can</span><span class="ident">also</span><span class="ident">be</span><span class="ident">a</span><span class="ident">different</span><span class="constant">Strategy</span><span class="punct">(</span><span class="ident">pattern</span><span class="punct">))</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="ident">currentMaxBid</span><span class="punct">!=</span><span class="keyword">null</span><span class="punct">&amp;&amp;</span><span class="ident">currentMaxBid</span><span class="punct">.</span><span class="ident">getAmount</span><span class="punct">().</span><span class="ident">compareTo</span><span class="punct">(</span><span class="ident">bidAmount</span><span class="punct">)</span><span class="punct">&gt;</span><span class="number">0</span><span class="punct">)</span><span class="punct">{</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Bid too low.</span><span class="punct">");</span><br /><span class="punct">}</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Auction</span><span class="ident">is</span><span class="ident">active</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="punct">!</span><span class="ident">state</span><span class="punct">.</span><span class="ident">equals</span><span class="punct">(</span><span class="constant">ItemState</span><span class="punct">.</span><span class="ident">ACTIVE</span><span class="punct">)</span><span class="punct">)</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Auction is not active yet.</span><span class="punct">");</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Auction</span><span class="ident">still</span><span class="ident">valid</span><br /><span class="keyword">if</span><span class="punct">(</span><span class="ident">this</span><span class="punct">.</span><span class="ident">getEndDate</span><span class="punct">().</span><span class="ident">before</span><span class="punct">(</span><span class="keyword">new</span><span class="constant">Date</span><span class="punct">()</span><span class="punct">)</span><span class="punct">)</span><br /><span class="ident">throw</span><span class="keyword">new</span><span class="constant">BusinessException</span><span class="punct">("</span><span class="string">Can't place new bid, auction already ended.</span><span class="punct">");</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Create</span><span class="keyword">new</span><span class="constant">Bid</span><br /><span class="constant">Bid</span><span class="ident">newBid</span><span class="punct">=</span><span class="keyword">new</span><span class="constant">Bid</span><span class="punct">(</span><span class="ident">bidAmount</span><span class="punct">,</span><span class="ident">this</span><span class="punct">,</span><span class="ident">bidder</span><span class="punct">);</span><br /><br /><span class="punct">/</span><span class="regex"></span><span class="punct">/</span><span class="constant">Place</span><span class="ident">bid</span><span class="keyword">for</span><span class="ident">this</span><span class="constant">Item</span><br /><span class="ident">this</span><span class="punct">.</span><span class="ident">addBid</span><span class="punct">(</span><span class="ident">newBid</span><span class="punct">);</span><br /><span class="ident">itemDao</span><span class="punct">.</span><span class="ident">update</span><span class="punct">(</span><span class="ident">this</span><span class="punct">);</span><span class="punct">/</span><span class="regex"></span><span class="punct">/</span>  调用<span class="constant">DAO进行显式持久化</span><br /><span class="keyword">return</span><span class="ident">newBid</span><span class="punct">;</span><br /><span class="punct">}</span><br /><span class="punct">}</span></p></pre></div><p></p><p>在这种模型中，所有的业务逻辑全部都在Item中，事务管理也在Item中实现。</p><img src ="http://www.blogjava.net/os586/aggbug/76070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/os586/" target="_blank">水煮三国</a> 2006-10-19 09:19 <a href="http://www.blogjava.net/os586/archive/2006/10/19/76070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>