﻿<?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-水煮三国-随笔分类-J2EE</title><link>http://www.blogjava.net/os586/category/8045.html</link><description>态度决定一切，思想决定出路</description><language>zh-cn</language><lastBuildDate>Fri, 23 Nov 2007 07:46:31 GMT</lastBuildDate><pubDate>Fri, 23 Nov 2007 07:46:31 GMT</pubDate><ttl>60</ttl><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>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>0</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>再论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><item><title>Java/JSP中文乱码问题解决心得</title><link>http://www.blogjava.net/os586/archive/2006/09/25/71644.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Mon, 25 Sep 2006 01:13:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/25/71644.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/71644.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/25/71644.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/71644.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/71644.html</trackback:ping><description><![CDATA[自从接触Java和JSP以来，就不断与Java的中文乱码问题打交道，现在终于得到了彻底的解决，现将我们的解决心得与大家共享。<br /><br />一、Java中文问题的由来 <br /><br />Java的内核和class文件是基于unicode的，这使Java程序具有良好的跨平台性，但也带来了一些中文乱码问题的麻烦。原因主要有两方面，Java和JSP文件本身编译时产生的乱码问题和Java程序于其他媒介交互产生的乱码问题。<br /><br />首先Java（包括JSP）源文件中很可能包含有中文，而Java和JSP源文件的保存方式是基于字节流的，如果Java和JSP编译成class文件过程中，使用的编码方式与源文件的编码不一致，就会出现乱码。基于这种乱码，建议在Java文件中尽量不要写中文（注释部分不参与编译，写中文没关系），如果必须写的话，尽量手动带参数－ecoding GBK或－ecoding gb2312编译；对于JSP，在文件头加上&lt;%@ page contentType="text/html;charset=GBK"%&gt;或&lt;%@ page contentType="text/html;charset=gb2312"%&gt;基本上就能解决这类乱码问题。<br /><br />本文要重点讨论的是第二类乱码，即Java程序与其他存储媒介交互时产生的乱码。很多存储媒介，如数据库，文件，流等的存储方式都是基于字节流的，Java程序与这些媒介交互时就会发生字符(char)与字节(byte)之间的转换，具体情况如下：<br /><br />从页面form提交数据到java程序 byte－&gt;char<br />从java程序到页面显示 char?&gt;byte<br /><br />从数据库到java程序 byte?&gt;char<br />从java程序到数据库 char?&gt;byte<br /><br />从文件到java程序 byte－&gt;char<br />从java程序到文件 char－&gt;byte<br /><br />从流到java程序 byte－&gt;char<br />从java程序到流 char－&gt;byte<br /><br />如果在以上转换过程中使用的编码方式与字节原有的编码不一致，很可能就会出现乱码。<br /><br />二、解决方法 <br /><br />前面已经提到了Java程序与其他媒介交互时字符和字节的转换过程，如果这些转换过程中容易产生乱码。解决这些乱码问题的关键在于确保转换时使用的编码方式与字节原有的编码方式保持一致，下面分别论述（Java或JSP自身产生的乱码请参看第一部分）。<br /><br />1、JSP与页面参数之间的乱码 <br />JSP获取页面参数时一般采用系统默认的编码方式，如果页面参数的编码类型和系统默认的编码类型不一致，很可能就会出现乱码。解决这类乱码问题的基本方法是在页面获取参数之前，强制指定request获取参数的编码方式：request.setCharacterEncoding("GBK")或request.setCharacterEncoding("gb2312")。<br />如果在JSP将变量输出到页面时出现了乱码，可以通过设置response.setContentType("text/html;charset=GBK")或response.setContentType("text/html;charset=gb2312")解决。<br />如果不想在每个文件里都写这样两句话，更简洁的办法是使用Servlet规范中的过虑器指定编码，过滤器的在web.xml中的典型配置和主要代码如下：<br />web.xml:<br /><br />&lt;filter&gt;<br />&lt;filter-name&gt;CharacterEncodingFilter&lt;/filter-name&gt;<br />&lt;filter-class&gt;net.vschool.web.CharacterEncodingFilter&lt;/filter-class&gt;<br />&lt;init-param&gt;<br />&lt;param-name&gt;encoding&lt;/param-name&gt;<br />&lt;param-value&gt;GBK&lt;/param-value&gt;<br />&lt;/init-param&gt;<br />&lt;/filter&gt;<br />&lt;filter-mapping&gt;<br />&lt;filter-name&gt;CharacterEncodingFilter&lt;/filter-name&gt;<br />&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;<br /><br />CharacterEncodingFilter.java:<br /><br />public class CharacterEncodingFilter implements Filter <br />{<br /><br />protected String encoding = null; <br /><br />public void init(FilterConfig filterConfig) throws ServletException <br />{<br />this.encoding = filterConfig.getInitParameter("encoding");<br />}<br /><br />public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException <br />{<br />request.setCharacterEncoding(encoding);<br />response.setContentType("text/html;charset="+encoding);<br />chain.doFilter(request, response);<br />}<br /><br />}<br /><br /><br />2、Java与数据库之间的乱码 <br />大部分数据库都支持以unicode编码方式，所以解决Java与数据库之间的乱码问题比较明智的方式是直接使用unicode编码与数据库交互。很多数据库驱动自动支持unicode，如Microsoft的SQLServer驱动。其他大部分数据库驱动，可以在驱动的url参数中指定，如如mm的mysql驱动：jdbc:mysql://localhost/WEBCLDB?useUnicode=true&amp;characterEncoding=GBK。<br /><br />3、Java与文件/流之间的乱码 <br />Java读写文件最常用的类是FileInputStream/FileOutputStream和FileReader/FileWriter。其中FileInputStream和FileOutputStream是基于字节流的，常用于读写二进制文件。读写字符文件建议使用基于字符的FileReader和FileWriter，省去了字节与字符之间的转换。但这两个类的构造函数默认使用系统的编码方式，如果文件内容与系统编码方式不一致，可能会出现乱码。在这种情况下，建议使用FileReader和FileWriter的父类：InputStreamReader/OutputStreamWriter，它们也是基于字符的，但在构造函数中可以指定编码类型：InputStreamReader(InputStream in, Charset cs) 和OutputStreamWriter(OutputStream out, Charset cs)。 <br /><br />4、其他 <br />上面提到的方法应该能解决大部分乱码问题，如果在其他地方还出现乱码，可能需要手动修改代码。解决Java乱码问题的关键在于在字节与字符的转换过程中，你必须知道原来字节或转换后的字节的编码方式，转换时采用的编码必须与这个编码方式保持一致。我们以前使用Resin服务器，使用smartUpload组件上传文件，上传文件同时传递的中文参数获取没有乱码问题。当在Linux中把Resin设置成服务后，上传文件同时的中文参数获取出现了乱码。这个问题困扰了我们很久，后来我们分析smartUpload组件的源文件，因为文件上传采用的是字节流的方式，里面包含的参数名称和值也是字节流的方式传递的。smartUpload组件读取字节流后再将参数名称和值从字节流中解析出来，问题就出现在smartUpload将字节流转换成字符串时采用了系统默认的编码，而将Resin设置成服务后，系统默认的编码可能发生了改变，因此出现了乱码。后来，我们更改了smartUpload的源文件，增加了一个属性charset和setCharset(String)方法，将upload()方法中提取参数语句：<br />String value = new String(m_binArray, m_startData, (m_endData - m_startData) + 1 );<br />改成了<br />String value = new String(m_binArray, m_startData, (m_endData - m_startData) + 1, charset );<br />终于解决了这个乱码问题。<br /><br />三、后记 <br />接触Java和JSP已经有一年多了，这一年来最大的收获是越来越喜欢上了Java，开始把问题当作乐事去研究，没有了以前的恐惧心理，我相信我会继续坚持下去。这一年来，从网上学习了很多同行的宝贵经验，在此表示感谢。这是我第一篇自己总结的Java学习心得，由于水平有限，本文中偏颇和错误之处，欢迎指正。如果对你有些价值，在保留作者信息和文章原始出处的前提下可以随处转载。<br />撰写该文之前已参考了很多关于Java中文问题的文章，其中影响比较大的有owen1944在“Java研究组织”中发表的《这是我们公司总结的一些关于中文乱码问题的一些解决方案和经验和大家分享！》等。本文谈到的解决方法已应用到“基于网络的协作学习系统－WebCL”等项目中，并通过资源绑定的方式实现了该平台中文文两个版本的即时切换。Google根据浏览器自动选择语言，一个页面同时显示多种语言的国际化应用和车东的《Java中文处理学习笔记??Hello Unicode》一文引起了我极大的兴趣，日后想将继续探讨Java的国际化问题，欢迎大家一起讨论。<br /><img src ="http://www.blogjava.net/os586/aggbug/71644.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-09-25 09:13 <a href="http://www.blogjava.net/os586/archive/2006/09/25/71644.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在线编辑器(转摘) </title><link>http://www.blogjava.net/os586/archive/2006/09/22/71319.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 22 Sep 2006 06:44:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/22/71319.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/71319.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/22/71319.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/71319.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/71319.html</trackback:ping><description><![CDATA[
		<p>FCKeditor在线编辑器的使用</p>
		<p>(转载）</p>
		<p>html在线编辑器对于我们作新闻产品之类的程序是很重要的，在网上找录了好了好一段时间，发现FCKeditor,跨平台的，正在进行的jsp项目正需要这款html在线编辑器。试用了一下FCKeditor,根据网上的文章小结一下：<br /><br /><b>1.下载</b><br />FCKeditor.java 2.3 (FCKeditot for java)<br />FCKeditor 2.2 (FCKeditor基本文件)<br />以下是下载地址：<br /><a title="http://www.fckeditor.net/download/default.html" href="http://www.fckeditor.net/download/default.html" target="_blank">http://www.fckeditor.net/download/default.html</a><br /><br /><b>2.建立项目:</b><br />建立项目tomcat/webapps/TestFCKeditor.<br /><br /><b>3.将FCKeditor2.2解压缩</b><br />将FCKeditor2.2解压缩,将整个目录FCKeditor复制到项目的根目录下，<br />目录结构为：tomcat/webapps/TestFCKeditor/FCKeditor<br />然后将FCKeditor-2.3.zip（java）压缩包中\web\WEB-INF\lib\目录下的两个jar文件拷到项目的\WEB-INF\lib\目录下。把其中的src目录下的FCKeditor.tld文件copy到TestFCKedit/FCKeitor/WEB-INF/下<br /><br /><b>4.合并web.xml:</b><br />将FCKeditor-2.3.zip压缩包中\web\WEB-INF\目录下的web.xml文件合并到项目的\WEB-INF\目录下的web.xml文件中。<br /><br /><br /><b>5. 修改合并后的web.xml文件</b><br />修改合并后的web.xml文件，将名为SimpleUploader的Servlet的enabled参数值改为true，<br />以允许上传功能，Connector Servlet的baseDir参数值用于设置上传文件存放的位置。<br />添加标签定义:<br />&lt;taglib&gt;<br />&lt;taglib-uri&gt;/TestFCKeditor&lt;/taglib-uri&gt;<br />&lt;taglib-location&gt;/WEB-INF/FCKeditor.tld&lt;/taglib-location&gt;<br />&lt;/taglib&gt;<br /><br />运行图：<br /></p>
		<div style="OVERFLOW-X: auto; WIDTH: 100%">
				<a href="http://www.java3z.com/cwbwebhome/article/article1/images/fckeditor.gif" target="_blank">
						<img style="WIDTH: 500px; CURSOR: pointer" onclick="javascript:window.open(this.src);" src="http://www.java3z.com/cwbwebhome/article/article1/images/fckeditor.gif" onload="javascript:if(this.width&gt;500)this.style.width=500;" />
				</a>
		</div>
		<br />
		<br />
		<b>6. 映射:</b>
		<br />上面文件中两个servlet的映射分别为：/editor/filemanager/browser/default/connectors/jsp/connector<br />和/editor/filemanager/upload/simpleuploader，需要在两个映射前面加上/FCKeditor，<br />即改为/FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector和<br />/FCKeditor/editor/filemanager/upload/simpleuploader。<br /><br /><b>7.修改skin文件夹</b><br />进入skin文件夹，如果你想使用fckeditor默认的这种奶黄色，<br />那就把除了default文件夹外的另两个文件夹直接删除.<br /><br /><b>8.删除无用文件</b><br />删除/FCKeditor/目录下除fckconfig.js, fckeditor.js, fckstyles.xml, fcktemplates.xml四个文件以外的所有文件 <br />删除目录/editor/_source,<br />删除/editor/filemanager/browser/default/connectors/下的所有文件<br />删除/editor/filemanager/upload/下的所有文件<br />删除/editor/lang/下的除了fcklanguagemanager.js, en.js, zh.js, zh-cn.js四个文件的所有文件<br /><br /><b>9.修改配置：</b><br />打开/FCKeditor/fckconfig.js<br />修改 FCKConfig.DefaultLanguage = 'zh-cn' ; <br />把FCKConfig.LinkBrowserURL等的值替换成以下内容：<br />FCKConfig.LinkBrowserURL<br />= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Connector=connectors/jsp/connector" ;<br /><br />FCKConfig.ImageBrowserURL<br />= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Image&amp;Connector=connectors/jsp/connector" ;<br /><br />FCKConfig.FlashBrowserURL<br />= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Flash&amp;Connector=connectors/jsp/connector" ;<br /><br />FCKConfig.LinkUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=File' ;<br />FCKConfig.FlashUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Flash' ;<br />FCKConfig.ImageUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Image' ;<br /><br /><b>10.其它</b><br />fckconfig.js总配置文件，可用记录本打开，修改后将文件存为utf-8 编码格式。找到：<br /><br />FCKConfig.TabSpaces = 0 ; 改为FCKConfig.TabSpaces = 1 ; 即在编辑器域内可以使用Tab键。<br /><br />如果你的编辑器还用在网站前台的话，比如说用于留言本或是日记回复时，那就不得不考虑安全了，<br />在前台千万不要使用Default的toolbar，要么自定义一下功能，要么就用系统已经定义好的Basic，<br />也就是基本的toolbar，找到：<br />FCKConfig.ToolbarSets["Basic"] = [<br />['Bold','Italic','-','OrderedList','UnorderedList','-',/*'Link',*/'Unlink','-','Style','FontSize','TextColor','BGColor','-',<br />'Smiley','SpecialChar','Replace','Preview'] ] ;<br />这是改过的Basic，把图像功能去掉，把添加链接功能去掉，因为图像和链接和flash和图像按钮添加功能都能让前台<br />页直接访问和上传文件， fckeditor还支持编辑域内的鼠标右键功能。<br /><br />FCKConfig.ContextMenu = ['Generic',/*'Link',*/'Anchor',/*'Image',*/'Flash','Select','Textarea','Checkbox','Radio','TextField','HiddenField',<br />/*'ImageButton',*/'Button','BulletedList','NumberedList','TableCell','Table','Form'] ;<br /><br />这也是改过的把鼠标右键的“链接、图像，FLASH，图像按钮”功能都去掉。<br /><br />　　 找到： FCKConfig.FontNames = 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;<br />加上几种我们常用的字体 <br />FCKConfig.FontNames <br />= '宋体;黑体;隶书;楷体_GB2312;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;<br /><br /><b>11.添加文件</b><br />添加文件 /TestFCKeditor/test.jsp:<br />&lt;%@ page language="java" import="com.fredck.FCKeditor.*" %&gt;<br />&lt;%@ taglib uri="/TestFCKeditor" prefix="FCK" %&gt;<br />&lt;script type="text/javascript" src="/TestFCKeditor/FCKeditor/fckeditor.js"&gt;&lt;/script&gt;<br /><br />&lt;%--<br />三种方法调用FCKeditor<br />1.FCKeditor自定义标签 (必须加头文件 &lt;%@ taglib uri="/TestFCKeditor" prefix="FCK" %&gt; )<br />2.script脚本语言调用 (必须引用 脚本文件 &lt;script type="text/javascript" src="/TestFCKeditor/FCKeditor/fckeditor.js"&gt;&lt;/script&gt; )<br />3.FCKeditor API 调用 (必须加头文件 &lt;%@ page language="java" import="com.fredck.FCKeditor.*" %&gt; )<br />--%&gt;<br /><br />&lt;%--<br />&lt;form action="show.jsp" method="post" target="_blank"&gt;<br />&lt;FCK:editor id="content" basePath="/TestFCKeditor/FCKeditor/"<br />width="700"<br />height="500"<br />skinPath="/TestFCKeditor/FCKeditor/editor/skins/silver/"<br />toolbarSet = "Default"<br />&gt;<br />input<br />&lt;/FCK:editor&gt;<br />&lt;input type="submit" value="Submit"&gt;<br />&lt;/form&gt;<br />--%&gt;<br /><br />&lt;form action="show.jsp" method="post" target="_blank"&gt;<br />&lt;table border="0" width="700"&gt;&lt;tr&gt;&lt;td&gt;<br />&lt;textarea id="content" name="content" style="WIDTH: 100%; HEIGHT: 400px"&gt;input&lt;/textarea&gt;<br />&lt;script type="text/javascript"&gt;<br />var oFCKeditor = new FCKeditor('content') ;<br />oFCKeditor.BasePath = "/TestFCKeditor/FCKeditor/" ;<br />oFCKeditor.Height = 400;<br />oFCKeditor.ToolbarSet = "Default" ; <br />oFCKeditor.ReplaceTextarea();<br />&lt;/script&gt;<br />&lt;input type="submit" value="Submit"&gt;<br />&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;<br />&lt;/form&gt;<br /><br />&lt;%--<br />&lt;form action="show.jsp" method="post" target="_blank"&gt;<br />&lt;%<br />FCKeditor oFCKeditor ;<br />oFCKeditor = new FCKeditor( request, "content" ) ;<br />oFCKeditor.setBasePath( "/TestFCKeditor/FCKeditor/" ) ;<br />oFCKeditor.setValue( "input" );<br />out.println( oFCKeditor.create() ) ;<br />%&gt;<br />&lt;br&gt;<br />&lt;input type="submit" value="Submit"&gt;<br />&lt;/form&gt;<br />--%&gt;<br /><br />添加文件/TestFCKeditor/show.jsp:<br />&lt;%<br />String content = request.getParameter("content");<br />out.print(content);<br />%&gt;<br /><br /><b>12.测试</b><br />浏览<a title="http://localhost:8080/TestFCKeditor/test.jsp" href="http://localhost:8080/TestFCKeditor/test.jsp" target="_blank">http://localhost:8080/TestFCKeditor/test.jsp</a><br /><img src ="http://www.blogjava.net/os586/aggbug/71319.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-09-22 14:44 <a href="http://www.blogjava.net/os586/archive/2006/09/22/71319.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP 制作文件下载碰到的问题</title><link>http://www.blogjava.net/os586/archive/2006/09/08/68521.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 08 Sep 2006 07:22:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/09/08/68521.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/68521.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/09/08/68521.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/68521.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/68521.html</trackback:ping><description><![CDATA[Web开发人员都有过这样的疑问，如何让一个文件，尤其是一个已知类型的文件，发送到客户端，直接提示让浏览者下载，而不是用与它相关联的程序打开。以前我们最常用的办法就是把这样的文件加到链接上，这样可以让浏览者通过点击鼠标右键的目标另存为来下载所链接的文件。但是，这样有两个不足的地方：<br />一是：如果浏览器能够识别已下载文件的扩展名，则浏览器就会激活该扩展名所关联的程序来打开所下载的文件。比如：在Windows平台上，如果用户点击的链接链接的是一个“.doc”文件的话，那么，浏览器就会启动Microsoft Word应用程序来打开它。<br />二是：如果采用链接的办法的话，任何能看到该链接的人都可以下载该文件，你虽然也可以对所下载的文件进行权限设置，但那样做也不是很方便的。有时候我们需要更为灵活和富有弹性的方式，下面的程序能够很方便地克服以上两方面的不足。<br />这种办法是可靠的，但你必须记住：没有授权的用户不能够通过在浏览器地址栏里输入文件的URL来取得该文件的下载权。所以，要下载的文件应该放到虚拟目录之外的一个目录里，比如：如果你的虚拟目录是C:\Mengxianhui\Tomcat4\Website\MyApp的话，那么，存放在该目录和该目录下的任何子目录下所有文件对因特网上的任何用户都是可见的。要直接下载一个文件，我们需要做两件事，第一件事是：设定响应的内容类为“application/octet-stream”，大小写无关。第二件事是：设置HTTP的响应头名字为：Content-Disposition，设定值为：attachment; filename = theFileName。这里的theFileName就是出现在文件下载对话框里的默认文件名，通常和所下载的文件名字相同，但也可以不同。下面，我们就平常最常用的JSP和ASP页面来举一个实际应用的例子。<br /><br />TestFileDownload.JSP页面的例子：<br /><br />&lt;%<br />// 得到文件名字和路径<br />String filename = "MengxianhuiDocTest.doc";<br />String filepath = "D:\\";<br /><br />// 设置响应头和下载保存的文件名<br />response.setContentType("APPLICATION/OCTET-STREAM");<br />response.setHeader("Content-Disposition",<br />"attachment; filename=\"" + filename + "\"");<br /><br />// 打开指定文件的流信息<br />java.io.FileInputStream fileInputStream =<br />new java.io.FileInputStream(filepath + filename);<br /><br />// 写出流信息<br />int i;<br />while ((i=fileInputStream.read()) != -1) {<br />out.write(i);<br />}<br />fileInputStream.close();<br />out.close();<br />%&gt;<br /><br />值得注意的是：在你要下载的文件内容里，除了文件的内容之外，不应该再附加有其它任何的字符，包括空格和回车换行符。我们有时在编写代码的时候，为了使代码清晰可读，往往会添加一些空格、制表符或者回车换行符，这样虽然看起来比较清晰，但有时可能会得不到正确的结果。比如：<br />&lt;%@ page import="java.io.*"<br />%&gt; &lt;jsp:useBean id="MyBeanFromMengxianhui" scope="page"<br />class="com.Mengxianhui.DownloadBean" /&gt;<br />应该写成这样：<br />&lt;%@ page import="java.io.*"%&gt;<br /><br />&lt;jsp:useBean id="MyBeanFromMengxianhui" scope="page" class="com.Mengxianhui.DownloadBean" /&gt; <br /><img src ="http://www.blogjava.net/os586/aggbug/68521.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-09-08 15:22 <a href="http://www.blogjava.net/os586/archive/2006/09/08/68521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>与大家一起分享JAVA源代码查询网站</title><link>http://www.blogjava.net/os586/archive/2006/07/21/59365.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 21 Jul 2006 02:09:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/07/21/59365.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/59365.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/07/21/59365.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/59365.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/59365.html</trackback:ping><description><![CDATA[
		<font face="Tahoma" size="2"> 1. java2s  </font>
		<a href="http://www.java2s.com/">
				<font face="Tahoma" color="#3f68a6" size="2">http://www.java2s.com/</font>
		</a>
		<div>
				<font face="Tahoma" size="2">   这个网站非常好，分成三大类，分别是<font color="#3f68a6"><a href="http://www.java2s.com/">Example</a></font>、</font>
				<a href="http://www.java2s.com/Product/CatalogProduct.htm">
						<font face="Tahoma" color="#003399" size="2">Products</font>
				</a>
				<font size="2">
						<font face="Tahoma">
								<font color="#003399">、</font>
								<u>
										<font color="#800080">Articles</font>
								</u>，每个大类下又分别设许多小类，还有搜索功能，这样查找起来非常方便。。比如，如果要学习SWT/JFace，只要把Example下的</font>
				</font>
				<a href="http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/CatalogSWT-JFace-Eclipse.htm">
						<strong>
								<font face="Tahoma" color="#3f68a6" size="2">SWT JFace Eclipse</font>
						</strong>
				</a>
				<font size="2">
						<font face="Tahoma">
								<strong>
								</strong>研究一下也就可以了。另外，这个网站还有</font>
				</font>
				<a href="http://www.java2s.com/Code/JavaScript/CatalogJavaScript.htm">
						<font face="Tahoma" color="#003399" size="2">JavaScript DHTML</font>
				</a>
				<font face="Tahoma" size="2">、 </font>
				<a href="http://www.java2s.com/Code/CSharp/CatalogCSharp.htm">
						<font face="Tahoma" color="#003399" size="2">C# / C Sharp</font>
				</a>
				<font face="Tahoma" size="2">、 </font>
				<a href="http://www.java2s.com/Code/C/CatalogC.htm">
						<font face="Tahoma" color="#003399" size="2">C / ANSI-C</font>
				</a>
				<font face="Tahoma" size="2">、 </font>
				<a href="http://www.java2s.com/Code/SQL/CatalogSQL.htm">
						<font face="Tahoma" color="#003399" size="2">SQL / MySQL</font>
				</a>
				<font face="Tahoma" size="2">等类。总之，非常好。<br /></font>
		</div>
		<div>
				<font face="Tahoma" size="2">  2. codeZoo </font>
				<a href="http://www.codezoo.com/">
						<font face="Tahoma" color="#3f68a6" size="2">http://www.codezoo.com/</font>
				</a>
		</div>
		<div>
				<font face="Tahoma" size="2">   这是O'Reily旗下的，除了Java之外，还有Ruby、Python。</font>
		</div>
		<div>
				<font face="Tahoma" size="2">
				</font> </div>
		<div>
				<font face="Tahoma" size="2">  3. Java学习源代码检索系统  </font>
				<a href="http://www.chinaitlab.com/www/school/codesearch/index.html">
						<font face="Tahoma" color="#3f68a6" size="2">http://www.chinaitlab.com/www/school/codesearch/index.html</font>
				</a>
		</div>
		<div>
				<font face="Tahoma" size="2">   难得看见国产的，好歹也要支持一下，分类也算清楚。</font>
		</div>
		<div>
				<font face="Tahoma" size="2">
				</font> </div>
		<div>
				<font face="Tahoma" size="2">  4. Koders  </font>
				<a href="http://www.koders.com/">
						<font face="Tahoma" color="#3f68a6" size="2">http://www.koders.com/</font>
				</a>
		</div>
		<div>
				<font face="Tahoma" size="2">   是个综合查询的网站，不过它好像是从代码中查找关键词，包含的语言挺多的。</font>
		</div>
		<div>
				<font face="Tahoma" size="2">
				</font>
		</div>
		<div>
				<font face="Tahoma" size="2">  5. Resources for Java server-side developers  </font>
				<a href="http://www.java201.com/">
						<font face="Tahoma" color="#3f68a6" size="2">http://www.java201.com/</font>
				</a>
		</div>
		<div>
				<font face="Tahoma" size="2">   确切的说，它是一个资源收集的网站，代码查询并不多。不过它分类相当细，如Articles、Books、Examples、Extensions、Frameworks等类，你可以输入Spring或Hibernate作为关键词搜索一下看看。</font>
		</div>
<img src ="http://www.blogjava.net/os586/aggbug/59365.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-07-21 10:09 <a href="http://www.blogjava.net/os586/archive/2006/07/21/59365.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat+Eclipse配置数据库连接池</title><link>http://www.blogjava.net/os586/archive/2006/06/16/53352.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 16 Jun 2006 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/06/16/53352.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/53352.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/06/16/53352.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/53352.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/53352.html</trackback:ping><description><![CDATA[如果在eclipse当中提示没有bound 数据源名给应用程序:<br /><br />那么你需要:<br /><br />在Eclipse项目当中webroot下的Meta-inf下面新建一个Context.xml,然后在里面配置数据选项:<br /><br />  该内容可以通过tomcat的admin图形界面来完成.然后复制到context.xml当中.<br /><br />  <br /><br />   当然除了配置这些内容之外还要在webroot下的web-inf下的web.xml下加入数据源的引用:<br /><br />具体内容:<br /><br /> <br />   &lt;resource-ref&gt;<br />  &lt;description&gt;Loan Sybase&lt;/description&gt;<br />  &lt;res-ref-name&gt;jdbc/loan&lt;/res-ref-name&gt;<br />  &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;<br />  &lt;res-auth&gt;Container&lt;/res-auth&gt;<br /> &lt;/resource-ref&gt;<br /><img src ="http://www.blogjava.net/os586/aggbug/53352.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-06-16 17:15 <a href="http://www.blogjava.net/os586/archive/2006/06/16/53352.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>刚搜到的MyEclipse4.1.1及4.0的注册码</title><link>http://www.blogjava.net/os586/archive/2006/05/16/46333.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Tue, 16 May 2006 01:53:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/05/16/46333.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/46333.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/05/16/46333.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/46333.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/46333.html</trackback:ping><description><![CDATA[
		<p>原来的时候是用注册机,现在搜到了可用的注册码:<br /><br />========4.0====</p>
		<div class="postText">
				<p>license name: csdn license key: pLR8ZC-956-55-5467865159452715 </p>
				<p>hello  uLR8ZC-955-56-6067865798739181</p>
				<p>License Name : shangxingxian<br />License Key : fLR8ZC-955-56-6067865930680921</p>
				<p>=============4.1<br />basten<br />oLR8ZC|957444|535353|6546801608</p>
				<p>pass:uLR8ZC-956-55-5467865991428004</p>
				<p>user:hehe<br /><br />希望能够帮助那些正在寻找注册码的朋友!</p>
		</div>
<img src ="http://www.blogjava.net/os586/aggbug/46333.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-05-16 09:53 <a href="http://www.blogjava.net/os586/archive/2006/05/16/46333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP及Servlet当中的重定向技巧</title><link>http://www.blogjava.net/os586/archive/2006/03/31/38522.html</link><dc:creator>水煮三国</dc:creator><author>水煮三国</author><pubDate>Fri, 31 Mar 2006 10:12:00 GMT</pubDate><guid>http://www.blogjava.net/os586/archive/2006/03/31/38522.html</guid><wfw:comment>http://www.blogjava.net/os586/comments/38522.html</wfw:comment><comments>http://www.blogjava.net/os586/archive/2006/03/31/38522.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/os586/comments/commentRss/38522.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/os586/services/trackbacks/38522.html</trackback:ping><description><![CDATA[
		<font style="FONT-SIZE: 12px" face="Courier New">2006年3月31日17:55:31<br /><br />对于重定向技术以前感觉是比较简单的东西，后来在做东西的过程中发现其实里面还是有很多技巧的!<br /><br />首先我们先比较一下：response.sendRedirect()和RequestDispatcher.forward()方法的使用情况<br /><br />   response.sendRedirect()方法：因为response是JSP的内含对象，因此它可以直接使用，而在Servlet当中它则是HttpServletResponse或是ServletResponse.<br /><br />   sendRedirect()方法是可以实现浏览器的http地址的跳转，它同样可以实现带有frame框架的地址的跳转。而forward()方法则不能完成这种带frame框架的地址的跳转。sendRedirect()方法的重定向可以显示在浏览器的地址栏当中，而forward()则不能。<br /><br />   sendRecirect()不仅可以实现frame的跳转，也可以实现跨网站跨应用程序的跳转。它能够传递带查询参数的变量及值，但是却不能够记录请求前页存的Request.setAttribute()当中的值。因此如果用sendRedirect()方法进行了跳转后的页面，没有记忆功能，但是session中的值可以得到。而forward()就具有记录属性值的功能，跳转后的页面可以取得前一页中保存的值。<br /><br />   forward()方法也可以传递查询参数及值。但是&lt;jsp:forward&gt;则不能传递查询参数，如果要实现查询参数则必须嵌套&lt;jsp:param name="name" value="value"&gt;来完成<br /><br />   通过用&lt;jsp:param&gt;来传递查询参数，它不会显示在浏览器的地址栏当中，因此比response.sendRedirect()要安全一些<br /><br /></font>
<img src ="http://www.blogjava.net/os586/aggbug/38522.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-03-31 18:12 <a href="http://www.blogjava.net/os586/archive/2006/03/31/38522.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>