<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>Java论坛最新讨论 - JavaEye</title>
    <description>Java编程、Java Web开发、Java企业应用、Java设计模式、Java开源框架、Java应用服务器 <br/>
圈子: 
<a href="http://android.group.javaeye.com/" target="_blank">Android</a>
<a href="http://jbpm.group.javaeye.com/" target="_blank">JBPM</a>
<a href="http://jsfgroup.group.javaeye.com/" target="_blank">JSF</a>
<a href="http://seam.group.javaeye.com/" target="_blank">Seam</a>
<a href="http://tapestrying.group.javaeye.com/" target="_blank">Tapestry</a>
<a href="http://grails.group.javaeye.com" target="_blank">Groovy</a>
<a href="http://lucene-group.group.javaeye.com/" target="_blank">Lucene</a>
<a href="http://ecside.group.javaeye.com/" target="_blank">GT-Grid</a>

 - Java编程，Ruby编程，微软.net，AJAX，敏捷软件开发，综合软件技术</description>
    <link>http://www.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>为什么缓存策略不适合企业应用?</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://joo.javaeye.com">Joo</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/191326" style="color:red;">http://www.javaeye.com/topic/191326</a>&nbsp;
          发表时间: 2008年05月09日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          一个应用中可以有很多类型很多层次的缓存,我这里说的缓存特指memcached,因为最近在JE上看得比较多,一直心存疑惑,终于在昨天看到一片文章里面论述到企业应用一般都不使用缓存策略,我终于忍不住想问了:<strong>企业应用中同样存在大量重复的数据库read操作,命中率应该较高才对</strong>,这种情况下可以使用缓存来缓解服务器磁盘IO负担难道不是很好的办法吗?为什么说不适合呢?<br />虽然企业应用的重点落在业务逻辑上,在PV量和并发IP访问上<strong>可能</strong>不如互联网应用,但是类似OA和报表这样大数据量查询操作的应用中,我觉得缓存还是能立奇功的.而且因为memcached是基于对象的缓存机制,相对于数据库查询缓存来说应该在业务逻辑处理上更具优势才对,因为类似MySQL的查询缓存在表被更新以后缓存就被clear掉,这样针对写操作频繁的应用来说资源消耗将非常之大,相对来说memcached如此白利而无一害的策略为什么却被说成不适合呢?
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/191326#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 09 May 2008 10:19:18 +0800</pubDate>
        <link>http://www.javaeye.com/topic/191326</link>
        <guid>http://www.javaeye.com/topic/191326</guid>
      </item>
          <item>
        <title>请问使用Quartz调度框架能像Window的任务调度执行程序吗？</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://nick-jian.javaeye.com">nick_jian</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192170" style="color:red;">http://www.javaeye.com/topic/192170</a>&nbsp;
          发表时间: 2008年05月12日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          各位大虾好。<br />       请问使用Quartz调度框架能像Window的任务调度执行程序吗？我现在手头上有一个编译好的class类文件（没有源文件了），我们公司现在的做法是用bat文件执行它，公司现在要我改成用Quartz来实现，前提是class类文件是固定，没有源代码。而且这个类是要读配置文件的。如果我把这些bat里面执行的程序运用到Quartz中，能实现吗？能的话是怎么一个思路呢?或者有什么好的想法，建议呢？在此万分感谢！
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192170#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 11:46:53 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192170</link>
        <guid>http://www.javaeye.com/topic/192170</guid>
      </item>
          <item>
        <title>webwork2.24 Action注入问题</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://12true.javaeye.com">12True</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192158" style="color:red;">http://www.javaeye.com/topic/192158</a>&nbsp;
          发表时间: 2008年05月12日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          spring2.08 webwork2.24<br />注入Action中的service出现问题，注入的service，和引用的service不是同一个对象。<br />无论是不是singleton都出现execute方法里面引用的service为null，声明为singleton="true"时初始化时setter方法里的service有效。<br />或者把service声明为static的也没问题。<br /><br />Action<br /><br /><pre name="code" class="java">
public class SystemAction extends ActionSupport implements ModelDriven{
    SystemModel sm = new SystemModel();
    private SystemService systemService;
    
    public String execute() throws Exception {
        System.out.println("in execute systemservice is "+systemService);
        systemService.TestSystemDAO();
        return SUCCESS;
    }

..setter..省略
</pre><br /><br />Action的注入<br /><pre name="code" class="java">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
&lt;beans>
		&lt;bean id="systemAction" class="net.xx.control.action.SystemAction" singleton="false">
		&lt;property name="systemService">
			&lt;ref bean="userService"/>
		&lt;/property>
		&lt;/bean>
&lt;/beans>
</pre><br /><br />xwork.xml<br /><br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">
&lt;xwork>
	&lt;include file="webwork-default.xml" />
	&lt;package name="default" extends="webwork-default">
		&lt;interceptors>
			&lt;interceptor-stack name="modelParamsStack">
				&lt;interceptor-ref name="params" />
				&lt;interceptor-ref name="model-driven"/>
			&lt;/interceptor-stack>
		&lt;/interceptors>
	&lt;/package>
&lt;include file="net\xx\control\config\webwork-user.xml"/>
&lt;/xwork></pre><br /><br />webwork-user.xml<br /><br /><pre name="code" class="java">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">
&lt;xwork>
 &lt;package name="login" extends="webwork-default" namespace="/user">  
	&lt;action name="login" class="net.xx.control.action.SystemAction">
			&lt;result name="success" type="dispatcher">
				&lt;param name="location">/index.jsp&lt;/param>
			&lt;/result>
			&lt;result name="error" type="dispatcher">
				&lt;param name="location">/login.jsp&lt;/param>
			&lt;/result>
		&lt;interceptor-ref name="modelParamsStack"/>
	&lt;/action>
 &lt;/package> 
&lt;/xwork></pre><br /><br />web.xml<br /><br /><pre name="code" class="java">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;web-app version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	&lt;servlet>
		&lt;servlet-name>webwork&lt;/servlet-name>
		&lt;servlet-class>
			com.opensymphony.webwork.dispatcher.ServletDispatcher
		&lt;/servlet-class>
		&lt;init-param>
			&lt;param-name>contextConfigLocation&lt;/param-name>
			&lt;param-value>/WEB-INF/applicationContext*.xml&lt;/param-value>
		&lt;/init-param>
	&lt;load-on-startup>1&lt;/load-on-startup>
	&lt;/servlet>

	&lt;servlet-mapping>
		&lt;servlet-name>webwork&lt;/servlet-name>
		&lt;url-pattern>*.action&lt;/url-pattern>
	&lt;/servlet-mapping>
&lt;listener>
    &lt;listener-class>org.springframework.web.context.ContextLoaderListener&lt;/listener-class>
&lt;/listener>

	&lt;context-param>
		&lt;param-name>contextConfigLocation&lt;/param-name>
		&lt;param-value>/WEB-INF/applicationContext*.xml&lt;/param-value>
	&lt;/context-param> 
	 	&lt;filter> 
        &lt;filter-name>openSessionInViewFilter&lt;/filter-name> 
        &lt;filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&lt;/filter-class> 
	&lt;/filter> 

	&lt;filter-mapping> 
        &lt;filter-name>openSessionInViewFilter&lt;/filter-name> 
        &lt;url-pattern>/*&lt;/url-pattern> 
	&lt;/filter-mapping>
&lt;/web-app>
</pre><br /><br />在javae也搜索到类似的问题，但。。还是没解决<br />http://www.javaeye.com/post/139291
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192158#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 11:15:56 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192158</link>
        <guid>http://www.javaeye.com/topic/192158</guid>
      </item>
          <item>
        <title>请教一个swing线程的问题</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://kruby.javaeye.com">kruby</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190963" style="color:red;">http://www.javaeye.com/topic/190963</a>&nbsp;
          发表时间: 2008年05月08日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          下面这段代码是简单模拟我遇到的问题，<br />分两个线程<br />线程A显示一个进度条<br />线程B循环输出数字<br /><br />点击“开始”以后，我要的效果是进度条在那边滚，同时循环输出，输出结束后再显示一个新框。<br />而现在的现象是等输出结束后，显示新框，这时候进度条才开始滚。<br />请教怎么解决这个问题<br /><br /><br /><pre name="code" class="java">import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

public class ProgressSample
{
	static class BarThread extends Thread
	{
		private static int DELAY = 500;
		JProgressBar progressBar;

		public BarThread(JProgressBar bar)
		{
			progressBar = bar;
		}

		public void run()
		{
			int minimum = progressBar.getMinimum();
			int maximum = progressBar.getMaximum();
			Runnable runner = new Runnable()
			{
				public void run()
				{
					int value = progressBar.getValue();
					progressBar.setValue(value + 1);
				}
			};
			for (int i = minimum; i &lt; maximum; i++)
			{
				try
				{
					SwingUtilities.invokeAndWait(runner);
					// Our task for each step is to just sleep
					Thread.sleep(DELAY);
				} catch (InterruptedException ignoredException)
				{
				} catch (InvocationTargetException ignoredException)
				{
				}
			}
		}
	}

	public static void main(String args[])
	{
		// Initialize
		final JProgressBar aJProgressBar = new JProgressBar(0, 100);
		final JButton aJButton = new JButton("Start");
		ActionListener actionListener = new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				aJButton.setEnabled(false);
				Thread stepper = new BarThread(aJProgressBar);
				stepper.start();
				
				whileThread wt = new whileThread();
				wt.start();
				try
				{
					wt.join();
				} catch (InterruptedException e1)
				{
					// TODO 自动生成 catch 块
					e1.printStackTrace();
				}
				JFrame newFrame = new JFrame("&&&&&&&&&&&&&&&&&&&&&&");
				newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				newFrame.setLocation(500, 400);
				newFrame.setSize(300, 100);
				newFrame.show();
			}
		};
		aJButton.addActionListener(actionListener);
		JFrame theFrame = new JFrame("Progress Bars");
		theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container contentPane = theFrame.getContentPane();
		contentPane.add(aJProgressBar, BorderLayout.NORTH);
		contentPane.add(aJButton, BorderLayout.SOUTH);
		theFrame.setLocation(500, 200);
		theFrame.setSize(300, 100);
		theFrame.show();
	}
	
	
}
class whileThread extends Thread
{
	public void run()
	{
		int i =0;
		while(i &lt; 1000000)
		{
			System.out.println(i++);
		}
	}
}
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190963#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:59:05 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190963</link>
        <guid>http://www.javaeye.com/topic/190963</guid>
      </item>
          <item>
        <title>解决eclipse+myeclipse的Processing Dirty Regions错误</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://rennuoting.javaeye.com">rennuoting</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192152" style="color:red;">http://www.javaeye.com/topic/192152</a>&nbsp;
          发表时间: 2008年05月12日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          我的Eclipse 3.3.2 + MyEclipse 6.0.1在打开JSP文件时出现以下错误：<br />An internal error occurred during: "Processing Dirty Regions".<br />org/eclipse/wst/sse/ui/internal/reconcile/validator/ValidationHelper<br /><br />An internal error occurred during: "JSP Content Validator".<br />org/eclipse/wst/sse/ui/internal/reconcile/validator/ValidationHelper<br /><br />An internal error occurred during: "JSP Semantics Validator (JSF)".<br />org/eclipse/wst/sse/ui/internal/reconcile/validator/ValidationHelper<br /><br />An internal error occurred during: "JSP Syntax Validator".<br />org/eclipse/wst/sse/ui/internal/reconcile/validator/ValidationHelper<br /> <br /> 这是一些网上的解决方案：<br />一. 这是由于插件org.eclipse.wst.sse.ui所致，myeclipse中的这个插件是修改过的zmyeclipse版本（在 myeclipse安装目录/eclipse/plugins中），但之后自动升级功能下载了更新版本的未修改版插件（在原eclipse的plugin 中），所以myeclipse据版本号判断加载了更新的插件。<br />但myeclipse的运行依赖修改版本的插件添加的一些功能，可是新的插件未包含这些功能。<br /><br />如错误中出现的org/eclipse/wst/sse/ui/internal/reconcile/validator/ValidationHelper.class，其实在未修改版本中根本不存在这个类，所以出错。<br />解决方案：将原eclipse中plugins中的org.eclipse.wst.sse.ui_1.x.xxxxxxx.jar挪到其他地方。<br />二.<br />有更好的解决方法<br />myeclips中，到Help -> Software Updates -> Manage Configuration<br />展开后有两项，一项是原有eclipse，一项是myeclipse，展开原有eclipse，<br />右键选中Web Standard Tools(WST)xxx那一项，disable，重启myeclipse<br /><br />我的解决方法：<br />但在我的原eclipse中根本找不到上面所说的那个文件，我于是怀疑是我安装的其他插件的问题，终于我找到了问题的所在，原来是我的JBPM流程设计器插件和myeclipse插件产生了冲突的问题，根据上面所说的解决方法，我认为myeclipse不但会和eclipse本身产生冲突，还会和 eclipse安装的其他插件产生问题，我在我安装的所有插件的目录中查找org.eclipse.wst.sse.ui这个关键字，结果在JBPM流程设计器的plugins目录中找到了org.eclipse.wst.sse.ui_1.0.305.v200802142230.jar这样一个文件，所以我怀疑是这个文件搞得怪，我把该文件移到其他地方，并把eclipse的configuration目录下除config.ini文件外全部删掉，这样可以让eclipse回复到初始状态，重新启动eclipse，打开JSP文件看看，终于可以了，eclipse不在报错，完全正常。<br />通过这个解决过程，我明白了eclipse的一些原理，eclipse的插件会和eclipse本身产生冲突，而且eclipse的插件之间也会相互产生冲突， eclipse插件总是会启用最新更新下载的插件类，这样就会产生一个问题，其他的插件会不会兼容这个更新的插件类。从这个解决过程我也明白了以后出现类似的问题，可以从安装的eclipse的插件入手来解决。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192152#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 11:05:39 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192152</link>
        <guid>http://www.javaeye.com/topic/192152</guid>
      </item>
          <item>
        <title>let's placeBid</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://taowen.javaeye.com">taowen</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192121" style="color:red;">http://www.javaeye.com/topic/192121</a>&nbsp;
          发表时间: 2008年05月12日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          这个例子很老啦，在之前的Domain Model的争论中被广泛引用（参见：http://www.javaeye.com/topic/11712）。我再来炒炒冷饭。<br /><br />这个Domain可以简化为这样：<br /><br /><pre name="code" class="java">
public class Item {
  private Set&lt;Bid> bids = new HashSet&lt;Bid>();
}
</pre><br /><br /><pre name="code" class="java">
public class Bid {
  private User bidder;
  private int amount;
}
</pre><br /><br />现在我们要添加一个行为叫placeBid。于是我们可以写出如下的贫血代码：<br /><br /><pre name="code" class="java">
    Bid currentMaxBid = itemDAO.getMaxBid(itemId);
    Item item = itemDAO.findById(itemId, true);
    if (currentMaxBid != null && bidAmount &lt;= currentMaxBid.getAmount()) {
        throw new BizException("Bid too low.");
    }
    Bid newBid = new Bid(this, bidder, bidAmount);
    item.getBids().add(bid);
    itemDao.save(item);
</pre><br /><br />这样的代码有什么问题吗？我觉得在没有更多的需求，系统规模不大的情况下，无法拿出有力的证据证明这样做的缺陷。那么我们再来看看如何用经典的Hibernate做法来做领域模型（参见robbin的第二种模型）：<br /><br /><pre name="code" class="java">
public class Item {
  public Bid placeBid(User bidder, int bidAmount, Bid currentMaxBid) {
     if (currentMaxBid != null && bidAmount &lt;= currentMaxBid.getAmount()) {
        throw new BizException("Bid too low.");
     }
     Bid newBid = new Bid(this, bidder, bidAmount);
     bids.add(newBid);
     return newBid;
  }
}
</pre><br /><br />在那篇老帖子（我知道，n年前了）中，七彩狼提出了一个问题，就是:<br /><br /><div class="quote_title">引用</div><div class="quote_div"><br />第三类DomainLogic，也就是需要依赖到复杂查询的Logic<br /></div><br /><br />那需要这样的逻辑的是什么？远在天边，近在眼前。currentMaxBid哪来的？不还是从DAO中取出来的嘛。我Item包含了自己的bids，它居然没有办法知道maxBid是什么，还需要从外边用参数传进来。这是不合理的，但是却是不得已的。Hibernate的经典解决方案制约我们必须把这样的查询逻辑放在Domain的使用者那一边中调用DAO来完成。如果改用（http://www.javaeye.com/topic/191261）我说的RichSet，就可以轻松解决：<br /><br /><pre name="code" class="java">
public class Item {
  private RichSet&lt;Bid> bids = new DefaultRichSet&lt;Bid>();
  public Bid placeBid(User bidder, int bidAmount) {
     Bid currentMaxBid = bids.max("amount");
     if (currentMaxBid != null && bidAmount &lt;= currentMaxBid.getAmount()) {
        throw new BizException("Bid too low.");
     }
     Bid newBid = new Bid(this, bidder, bidAmount);
     bids.add(newBid);
     return newBid;
  }
}
</pre><br /><br />max在缺省情况下的实现是遍历列表。在Hibernate增强之后就变成了SQL查询。类似于bids.add在缺省情况是列表操作，Hibernate存储的时候变成了SQL的INSERT。<br /><br />我的观点是，所谓的大批量操作不属于Domain Logic是由于Hibernate造成的限制。实际情况中，Domain中应该有一个叫Repository的对象。它封装了一个List。<br /><br /><pre name="code" class="java">
public class ItemRepository {
  private RichList&lt;Item> items
  public ItemRepository(RichList&lt;Item> items) {
    this.items = items;
  }
}
</pre><br /><br />作为领域对象的ItemRepository，它是不关心items是从哪里来的。它就认为这个items是domain中的所有的item。于是，addItem的item没名字不重复的校验就可以自然的放在ItemRepository上。<br /><br /><pre name="code" class="java">
public class ItemRepository {
  public void addItem(String name) {
    if (items.find("name").eq(name).size() > 0) {
       throw new BizException("name duplicated");
    }
    Item item = new Item(name);
    items.add(item);
    return item;
  }
}
</pre><br /><br />在Domain中，所有的Item列表，都应该经过ItemRepository包装。从而保证Item的名字唯一性。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192121#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 10:11:13 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192121</link>
        <guid>http://www.javaeye.com/topic/192121</guid>
      </item>
          <item>
        <title>tomcat 优化到每秒并发1000</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://webeasymail.javaeye.com">webeasymail</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190329" style="color:red;">http://www.javaeye.com/topic/190329</a>&nbsp;
          发表时间: 2008年05月06日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          <div class="quote_title"><br /></div>
<div class="quote_title">现在系统部署只能达到240+ , tomcat + apache 也只能到 900 + ，看到robbin的发帖能达到1000 ，不知道该如何配置，特来请教：</div>
<div class="quote_title">http://www.javaeye.com/post/370111?page=8<br /></div>
<div class="quote_title">
</div>
<div class="quote_title">
</div>
<div class="quote_title">robbin 写道</div>
<div class="quote_div">既然你用tomcat4都可以达到并发600，那tomcat5.5在同样环境下经过调优完全可以达到1000，看来问题还是在于你们tomcat没有配置好。</div>
<p><strong>附带环境配置如下：</strong></p>
<p>&nbsp;</p>
<p>&nbsp; 环境配置如下: （jdk没有用 -server）</p>
<pre name="code" class="java">windows 2003 企业版 sp2

Intel(R) Xeon(R) 4 CPU 5130 @ 2.0GHz 4.00GB 内存

apache_2.2.8-win32-x86

mod_jk-apache-2.0.59

jdk-1_5_0_14-windows-i586-p.exe -client

Tomcat-6.0.16 + apr</pre>
&nbsp;
<p>
<img src="file:///C:/DOCUME%7E1/ADMINI%7E1/LOCALS%7E1/Temp/moz-screenshot.jpg" alt="" />
</p>
<p>&nbsp;</p>
<p>server.xml </p>
<pre name="code" class="xml"> 
    &lt;Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="2000" minSpareThreads="1000"/&gt;
    

    &lt;Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="2000" 
               redirectPort="8443"  enableLookups="false" 
			   acceptCount="5000" maxThreads="2000"/&gt;</pre>
&nbsp;
<p>catalina.bat</p>
<pre name="code" class="java">set JAVA_OPTS=-Xms1400m -Xmx1400m -Djava.awt.headless=true</pre>
<p>&nbsp;</p>
<p>index.jsp (除了下面这些代码，还有200行html代码，没有一个图片)</p>
<pre name="code" class="java">&lt;%
for(int i=0;i&lt;1000;i++){
   request.setAttribute("key_"+i,"value_"+i);	
}


for(int i=0;i&lt;100;i++){
   request.getSession().setAttribute("key_"+i,"value_"+i);	
}
%&gt;
&lt;br /&gt;
&lt;%=request.getSession().getAttribute("key_0")%&gt;
&lt;%=request.getSession().getAttribute("key_0")%&gt;
&lt;%=request.getSession().getAttribute("key_0")%&gt;
&lt;%=request.getSession().getAttribute("key_0")%&gt;
&lt;%=request.getSession().getAttribute("key_0")%&gt;
&lt;%=request.getSession().getAttribute("key_0")%&gt;</pre>
<p>tomat 启动信息如下：</p>
<pre name="code" class="java">2008-5-6 17:54:52 org.apache.catalina.core.AprLifecycleListener init
信息: Loaded APR based Apache Tomcat Native library 1.1.10.
2008-5-6 17:54:52 org.apache.catalina.core.AprLifecycleListener init
信息: APR capabilities: IPv6 [false], sendfile [true], accept filters [false], r
andom [true].
2008-5-6 17:54:52 org.apache.coyote.http11.Http11AprProtocol init
信息: Initializing Coyote HTTP/1.1 on http-8080
2008-5-6 17:54:52 org.apache.coyote.ajp.AjpAprProtocol init
信息: Initializing Coyote AJP/1.3 on ajp-30008
2008-5-6 17:54:52 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 973 ms
2008-5-6 17:54:52 org.apache.catalina.core.StandardService start
信息: Starting service Catalina
2008-5-6 17:54:52 org.apache.catalina.core.StandardEngine start
信息: Starting Servlet Engine: Apache Tomcat/6.0.16
2008-5-6 17:54:52 org.apache.coyote.http11.Http11AprProtocol start
信息: Starting Coyote HTTP/1.1 on http-8080
2008-5-6 17:54:53 org.apache.coyote.ajp.AjpAprProtocol start
信息: Starting Coyote AJP/1.3 on ajp-30008
2008-5-6 17:54:53 org.apache.catalina.startup.Catalina start
信息: Server startup in 310 ms
</pre>
&nbsp;
<p><span style="text-decoration: line-through;"><em><strong>-----------------------------------------------------------------------------------------</strong></em></span></p>
<p>下面是测试结果：</p>
<p>&nbsp;</p>
<p>tomcat + apache 测试结果:</p>
<pre name="code" class="java">D:\Apache2.2\bin&gt;ab -n 10000 -c 800 http://127.0.0.1/index.jsp

Server Software:        Apache/2.2.4
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /index.jsp
Document Length:        41078 bytes

Concurrency Level:      800
Time taken for tests:   34.46875 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      413090000 bytes
HTML transferred:       410780000 bytes
Requests per second:    293.71 [#/sec] (mean)
Time per request:       2723.750 [ms] (mean)
Time per request:       3.405 [ms] (mean, across all concurrent requests)
Transfer rate:          11848.61 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.8      0      15
Processing:    15 2034 3425.1    921   23265
Waiting:        0 2025 3423.8    921   23250
Total:         15 2034 3425.1    921   23265

Percentage of the requests served within a certain time (ms)
  50%    921
  66%   1343
  75%   1656
  80%   1875
  90%   5078
  95%   9421
  98%  15828
  99%  18171
 100%  23265 (longest request)

D:\Apache2.2\bin&gt;ab -n 10000 -c 1000 http://127.0.0.1/index.jsp

Server Software:        Apache/2.2.4
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /index.jsp
Document Length:        323 bytes

Concurrency Level:      1000
Time taken for tests:   24.265625 seconds
Complete requests:      10000
Failed requests:        3953
   (Connect: 0, Length: 3953, Exceptions: 0)
Write errors:           0
Non-2xx responses:      8686
Total transferred:      58651479 bytes
HTML transferred:       56541921 bytes
Requests per second:    412.11 [#/sec] (mean)
Time per request:       2426.563 [ms] (mean)
Time per request:       2.427 [ms] (mean, across all concurrent requests)
Transfer rate:          2360.38 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.7      0      15
Processing:     0 1573 4416.4     31   23984
Waiting:        0 1563 4402.5     31   23984
Total:          0 1573 4416.5     31   23984

Percentage of the requests served within a certain time (ms)
  50%     31
  66%     62
  75%     62
  80%     62
  90%   7031
  95%  13234
  98%  18218
  99%  19859
 100%  23984 (longest request)</pre>
<p>&nbsp;tomcat 单独测试结果 (250并发会经常失败，200比较正常，偶尔有少量错误):</p>
<pre name="code" class="java">D:\Apache2.2\bin&gt;ab -n 1000 -c 250 http://127.0.0.1:8080/index.jsp
This is ApacheBench, Version 2.0.40-dev &lt;$Revision: 1.146 $&gt; apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Send request failed!
Send request failed!
Send request failed!
Send request failed!
Send request failed!
Completed 200 requests
Send request failed!
apr_socket_recv: 远程主机强迫关闭了一个现有的连接。   (730054)
Total of 223 requests completed

D:\Apache2.2\bin&gt;ab -n 1000 -c 250 http://127.0.0.1:8080/index.jsp

Server Software:        Apache-Coyote/1.1
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /index.jsp
Document Length:        41078 bytes

Concurrency Level:      250
Time taken for tests:   2.390625 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      41292000 bytes
HTML transferred:       41078000 bytes
Requests per second:    418.30 [#/sec] (mean)
Time per request:       597.656 [ms] (mean)
Time per request:       2.391 [ms] (mean, across all concurrent requests)
Transfer rate:          16867.56 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.9      0      15
Processing:   109  575 314.1    515    1218
Waiting:       62  550 315.0    453    1156
Total:        109  575 314.1    515    1218

Percentage of the requests served within a certain time (ms)
  50%    515
  66%    609
  75%    921
  80%   1031
  90%   1062
  95%   1125
  98%   1140
  99%   1140
 100%   1218 (longest request)</pre>
&nbsp;
<p>单独测试tomcat基本上只能达到240+左右的并发，tomcat+apache 900+并发，如果是静态页面tomcat并发1000+没有任何问题。</p>
<p>tomcat基本上都保持在 20% - 45% 之间 ， 内存在 80M -- 600M +之间 ，根据并发和请求的大小，内存的变法比较明显，cpu基本保存在这里，apache占用的cpu基本上是在 15% - 40%。</p>
<p>因为JRockit收费，所以就没有测试。（主要是真实部署的时候会采用这些配置，收费的公司目前也不会购买！^_^）</p>
<p>&nbsp;</p>
<p>不知道大家如何配置tomcat能并发1000左右 ？？？？？？？？</p>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190329#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 18:00:55 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190329</link>
        <guid>http://www.javaeye.com/topic/190329</guid>
      </item>
          <item>
        <title>Struts 验证图片。</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://sunsja.javaeye.com">sunsja</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192112" style="color:red;">http://www.javaeye.com/topic/192112</a>&nbsp;
          发表时间: 2008年05月12日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          <pre name="code" class="java">package cn.com.lough.struts.action;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.commons.lang.RandomStringUtils;

/**
 * MyEclipse Struts Creation date: 01-11-2007
 * 
 * XDoclet definition:
 * 
 * @struts.action validate="true"
 */
public class ValidatecodeAction extends Action {
	/*
	 * Generated Methods
	 */

	/**
	 * Method execute
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return ActionForward
	 */
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		try {
			int width = 50;
			int height = 18;
			// 取得一个4位随机字母数字字符串
			String s = RandomStringUtils.random(4, true, true);

			// 保存入session,用于与用户的输入进行比较.
			// 注意比较完之后清除session.
			HttpSession session = request.getSession(true);
			session.setAttribute("validateCode", s);

			response.setContentType("images/jpeg");
			response.setHeader("Pragma", "No-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", 0);

			ServletOutputStream out = response.getOutputStream();
			BufferedImage image = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);
			Graphics g = image.getGraphics();
			// 设定背景色
			g.setColor(getRandColor(200, 250));
			g.fillRect(0, 0, width, height);

			// 设定字体
			Font mFont = new Font("Times New Roman", Font.BOLD, 18);// 设置字体
			g.setFont(mFont);

			// 画边框
			// g.setColor(Color.BLACK);
			// g.drawRect(0, 0, width - 1, height - 1);

			// 随机产生干扰线，使图象中的认证码不易被其它程序探测到
			g.setColor(getRandColor(160, 200));
			// 生成随机类
			Random random = new Random();
			for (int i = 0; i &lt; 155; i++) {
				int x2 = random.nextInt(width);
				int y2 = random.nextInt(height);
				int x3 = random.nextInt(12);
				int y3 = random.nextInt(12);
				g.drawLine(x2, y2, x2 + x3, y2 + y3);
			}

			// 将认证码显示到图象中
			g.setColor(new Color(20 + random.nextInt(110), 20 + random
					.nextInt(110), 20 + random.nextInt(110)));

			g.drawString(s, 2, 16);

			// 图象生效
			g.dispose();
			// 输出图象到页面
			ImageIO.write((BufferedImage) image, "JPEG", out);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private Color getRandColor(int fc, int bc) { // 给定范围获得随机颜色
		Random random = new Random();
		if (fc &gt; 255)
			fc = 255;
		if (bc &gt; 255)
			bc = 255;
		int r = fc + random.nextInt(bc - fc);
		int g = fc + random.nextInt(bc - fc);
		int b = fc + random.nextInt(bc - fc);
		return new Color(r, g, b);
	}
}


jsp页面的调用 
&lt;html:img page="/validatecode.do" border="0" onclick="this.src='/validatecode.do'" alt="请输入此验证码，如看不清请点击刷新。" style="cursor:pointer" /&gt; 
</pre>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192112#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 09:54:55 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192112</link>
        <guid>http://www.javaeye.com/topic/192112</guid>
      </item>
          <item>
        <title>Hibernate中二级缓存的建立 </title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://article2008.javaeye.com">article2008</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192109" style="color:red;">http://www.javaeye.com/topic/192109</a>&nbsp;
          发表时间: 2008年05月12日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          1、在hbm.xml中增加&lt;cache>声明。<br /><br />例如：<br /><br />&lt;class<br /> name="Account"<br /> table="account"<br /> lazy="false"<br />><br /> &lt;meta attribute="sync-DAO">true&lt;/meta><br /> <span style="color: red">&lt;cache usage="read-write"/></span><br /> &lt;id<br />  name="Id"<br />  type="integer"<br />  column="i_account_id"<br /> ><br />  &lt;generator class="assigned"/><br /> &lt;/id><br /><br />  &lt;property<br />......<br />&lt;/class><br /><br />2、就是在ehcache.xml中增加对该缓存的声明，让该对象的二级缓存真正开始起作用。<br /><br />&lt;<span style="color: red">cache name="cn.techtiger.model.Account"</span> <br /> maxElementsInMemory="1000" <br /> eternal="false" <br /> timeToIdleSeconds="300" <br /> timeToLiveSeconds="600" <br /> overflowToDisk="false"<br />/>       <br /><br />注意的问题：<br /><br />1、如果在hbm.xml中配置了，但是在ehcache.xml中没有设置，那么系统启动的时候，会报告：<br /><br />[WARN]Could not find configuration [cn.techtiger.model.Account]; using defaults.<br /><br />2、ehcache起作用，还需要在hibernate的配置文件中声明cache provider：<br /><br />  &lt;property name="hibernateProperties"><br />   &lt;props><br />     &lt;prop <span style="color: red">key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</span>&lt;/prop><br />   &lt;/props><br />  &lt;/property>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192109#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 May 2008 09:51:03 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192109</link>
        <guid>http://www.javaeye.com/topic/192109</guid>
      </item>
          <item>
        <title>Struts2 Map 映射</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://sunchaohui-koko.javaeye.com">sunchaohui_koko</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/191915" style="color:red;">http://www.javaeye.com/topic/191915</a>&nbsp;
          发表时间: 2008年05月11日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          最近写了一段JSP，目的是想完成一段关系映射，选用了Map,如下。<br /><pre name="code" class="java">
&lt;s:iterator value="acList" id="item" status="stat">
	&lt;s:select name="reMap[%{#item.acUniqueId}]" list="pFormList" listKey="id" listValue="displayName" value="%{reMap[#item.acUniqueId]}" cssStyle="width:150px;font-size: 12px;">
	&lt;/s:select>
&lt;/s:iterator>
</pre><br />但是奇怪的是，当reMap的key([%{#item.acUniqueId}])太长的时候，Map就莫名其妙的错了。譬如有reMap[1234567890]=6就不能映射了，而reMap[1234]=4就可以。有那位能够解答一下呢？
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/191915#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 May 2008 11:50:06 +0800</pubDate>
        <link>http://www.javaeye.com/topic/191915</link>
        <guid>http://www.javaeye.com/topic/191915</guid>
      </item>
          <item>
        <title>spring怎么对struts的ActionForm实现注入啊???</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://yongyong17.javaeye.com">yongyong17</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192053" style="color:red;">http://www.javaeye.com/topic/192053</a>&nbsp;
          发表时间: 2008年05月11日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          spring怎么对struts的ActionForm实现注入啊???<br />那个大哥帮下忙嘛,我实在是整不来了啊.<br />LookuserForm代码<br /><pre name="code" class="java">package org.shan.student.form;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.shan.student.service.IDaoService;
import org.shan.student.util.Bean;

public class LookuserForm extends ActionForm {

	private static final long serialVersionUID = 1L;

	protected IDaoService daoService;
	private String userName;
	private String userClass;
	private String passWord;
	private String id;

	public void setDaoService(IDaoService daoService) {
		this.daoService = daoService;
	}

	public ActionErrors validate(ActionMapping mapping,
			HttpServletRequest request) {
		ActionErrors errors = new ActionErrors();
		if (null == id || "".equals(id))
			errors.add("id", new ActionMessage("error.id"));
		else if (null == userName || "".equals(userName))
			errors.add("userName", new ActionMessage("error.username"));
		else if (null == passWord || "".equals(passWord))
			errors.add("passWord", new ActionMessage("error.password"));
		return errors;
	}

	public void reset(ActionMapping mapping, HttpServletRequest request) {
		String action = request.getParameter("action");
		Object id = request.getParameter("id");
		if (null != action) {
			Object o = daoService.getDataById("org.shan.student.vo.UserInfo",
					id);
			if (action.equals("del")) {
				daoService.delete(o);
			} else {
				Bean bean = new Bean();
				this.id = (String) bean.invoke("id", o);
				this.userName = (String) bean.invoke("userName", o);
				this.passWord = (String) bean.invoke("passWord", o);
				this.userClass = (String) bean.invoke("userClass", o);
				request.getSession().setAttribute("edit", "edit");
				return;
			}
		}
		List&lt;?> list = daoService.getData("from UserInfo");
		request.getSession().setAttribute("list", list);
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getUserClass() {
		return userClass;
	}

	public void setUserClass(String userClass) {
		this.userClass = userClass;
	}

	public String getPassWord() {
		return passWord;
	}

	public void setPassWord(String passWord) {
		this.passWord = passWord;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
}</pre><br />struts配置文件<br /><pre name="code" class="xml">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">

&lt;struts-config>
	&lt;form-beans>
		&lt;form-bean name="loginForm"
			type="org.shan.student.form.LoginForm" />
		&lt;form-bean name="editPassWordForm"
			type="org.shan.student.form.EditPassWordForm" />
		&lt;form-bean name="addUserForm"
			type="org.shan.student.form.AddUserForm" />
		&lt;form-bean name="lookuserForm"
			type="org.springframework.web.struts.SpringBindingActionForm" />
	&lt;/form-beans>

	&lt;global-exceptions />
	&lt;global-forwards />
	&lt;action-mappings>
		&lt;action attribute="loginForm" input="/login.jsp"
			name="loginForm" path="/login" scope="request"
			type="org.springframework.web.struts.DelegatingActionProxy">
			&lt;forward name="student" path="/student.jsp" />
			&lt;forward name="admin" path="/admin.jsp" />
		&lt;/action>
		&lt;action attribute="editPassWordForm" input="/EditPassWord.jsp"
			name="editPassWordForm" path="/editPassWord" scope="request"
			type="org.springframework.web.struts.DelegatingActionProxy">
			&lt;forward name="EditPassWord" path="/EditPassWord.jsp"
				redirect="true" />
		&lt;/action>
		&lt;action attribute="addUserForm" input="/addUser.jsp"
			name="addUserForm" path="/addUser" scope="request"
			type="org.springframework.web.struts.DelegatingActionProxy">
			&lt;forward name="addUser" path="/addUser.jsp" redirect="true" />
		&lt;/action>
		&lt;action attribute="lookuserForm" input="/lookuser.jsp"
			name="lookuserForm" path="/lookuser" scope="request"
			type="org.springframework.web.struts.DelegatingActionProxy" />
	&lt;/action-mappings>

	&lt;message-resources
		parameter="org.shan.student.action.ApplicationResources" />
	&lt;plug-in
		className="org.springframework.web.struts.ContextLoaderPlugIn">
		&lt;set-property property="contextConfigLocation"
			value="/WEB-INF/applicationContext.xml" />
	&lt;/plug-in>
&lt;/struts-config>

</pre><br /><br />spring配置文件<br /><pre name="code" class="xml">&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

&lt;beans>
	&lt;bean id="datasource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		&lt;property name="driverClassName">
			&lt;value>net.sourceforge.jtds.jdbc.Driver&lt;/value>
		&lt;/property>
		&lt;property name="url">
			&lt;value>jdbc:jtds:sqlserver://localhost:1433/Student&lt;/value>
		&lt;/property>
		&lt;property name="username">
			&lt;value>sa&lt;/value>
		&lt;/property>
	&lt;/bean>
	&lt;bean id="SessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		&lt;property name="dataSource">
			&lt;ref bean="datasource" />
		&lt;/property>
		&lt;property name="hibernateProperties">
			&lt;props>
				&lt;prop key="hibernate.show_sql">true&lt;/prop>
			&lt;/props>
		&lt;/property>
		&lt;property name="mappingResources">
			&lt;list>
				&lt;value>org/shan/student/vo/Accounts.hbm.xml&lt;/value>
				&lt;value>org/shan/student/vo/UserInfo.hbm.xml&lt;/value>
			&lt;/list>
		&lt;/property>
	&lt;/bean>
	&lt;bean id="BaseDao" class="org.shan.student.dao.BaseDao"
		abstract="true">
		&lt;property name="sessionFactory">
			&lt;ref bean="SessionFactory" />
		&lt;/property>
	&lt;/bean>
	&lt;bean id="DaoBean" class="org.shan.student.dao.impl.DaoBean"
		parent="BaseDao">
	&lt;/bean>
	&lt;bean id="DaoService"
		class="org.shan.student.service.impl.DaoService">
		&lt;property name="daoBean">
			&lt;ref bean="DaoBean" />
		&lt;/property>
	&lt;/bean>
	&lt;bean id="login" name="/login"
		class="org.shan.student.action.LoginAction">
		&lt;property name="daoService">
			&lt;ref bean="DaoService" />
		&lt;/property>
	&lt;/bean>
	&lt;bean id="editPassWord" name="/editPassWord"
		class="org.shan.student.action.EditPassWordAction">
		&lt;property name="daoService">
			&lt;ref bean="DaoService" />
		&lt;/property>
	&lt;/bean>
	&lt;bean id="addUser" name="/addUser"
		class="org.shan.student.action.AddUserAction">
		&lt;property name="daoService">
			&lt;ref bean="DaoService" />
		&lt;/property>
	&lt;/bean>
	&lt;bean id="lookuser" name="/lookuser"
		class="org.shan.student.action.LookuserAction">
		&lt;property name="daoService">
			&lt;ref bean="DaoService" />
		&lt;/property>
	&lt;/bean>
	&lt;bean id="lookuserForm" name="lookuserForm"
		class="org.shan.student.form.LookuserForm">
		&lt;property name="daoService">
			&lt;ref bean="DaoService" />
		&lt;/property>
	&lt;/bean>
&lt;/beans></pre>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192053#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 May 2008 23:49:36 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192053</link>
        <guid>http://www.javaeye.com/topic/192053</guid>
      </item>
          <item>
        <title>请教多线程的问题</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://zhanggok.javaeye.com">zhanggok</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192026" style="color:red;">http://www.javaeye.com/topic/192026</a>&nbsp;
          发表时间: 2008年05月11日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          最近我帮我朋友写个小程序，用JAVA模拟提交表单。假如有个网上电影订票系统（一个用户只能一天只能选一场电影），选择电影和电影放映厅后画面上还有验证码的图片。我要同时帮3-5个人订票，程序启动同时启动多个线程模拟3-5登录，因为有验证码这时全部的线程需要中断阻塞，等把图片在SWING的控件中显示后，输入验证码后再一个一个的启动线程。JAVA1.4中wait()暂停一个线程后;需要启动时在用notifyAll()唤醒全部的线程在用个变量来判断该线程是否应唤醒如果不在暂停。<br />   我已经2年没有写JAVA了好多东西都忘了以前一直用的JAVA1.4，请教在1.5中有没有更好的方法如线程池，暂停和启动线程有没有更好的方法。最好能说明用到那些类。谢谢了。<br />图片中USER1是用来显示验证码，开始是用户登录，订票是唤醒给其中一个用户订票
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192026#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 May 2008 22:59:09 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192026</link>
        <guid>http://www.javaeye.com/topic/192026</guid>
      </item>
          <item>
        <title>动态properties转换</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://ajoo.javaeye.com">ajoo</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190440" style="color:red;">http://www.javaeye.com/topic/190440</a>&nbsp;
          发表时间: 2008年05月07日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          今天同事和我讨论他遇到的一个问题。具体要求是这样的，在运行时，我们会从模块G得到一个Map，这个Map里面都是一些字符串对，你可以理解成一个字典，有字符串的key和字符串的value。简短节说，就是<br /><pre name="code" class="java">Map&lt;String, String></pre><br />非常非常复杂深奥。<br /><br />好，现在我们事先知道要从这个map里读取一些数据点，比如：id, name, sex等等。<br /><br />对id，我们知道读出来的是int；对name，是string；对sex，应该对应一个叫Gender的enum类型。<br /><br />这就涉及一个自动类型转换的问题。我们希望不用对每个数据点做手工类型转换。<br /><br />另外一个需求，一些数据点是有缺省值的。比如name我们可以缺省为空字符串。<br />这样，如果map里面没有某个值，我们就看缺省值，如果有，就用这个缺省值，如果没有，就抛异常。<br /><br />手工做的话，大概是这样：<br /><pre name="code" class="java">
String idValue = map.get("id");
if (idValue == null) {
  throw ...;
}
int id = Integer.parseInt(idValue);

String name = map.get("name");
if (name == null) {
  name = "";
}

String sexValue = map.get("sex");
if (sexValue == null) {
  throw ...;
}
Gender sex = Gender.valueOf(sexValue);
...
</pre><br /><br />比较痛苦。于是做了一个动态代理：<br /><pre name="code" class="java">
public final class PropertyConverter&lt;T> {
  private final Class&lt;T> targetType;
  
  private PropertyConverter(Class&lt;T> targetType) {...}

  public static &lt;T> PropertyConverter&lt;T> to(Class&lt;T> targetType) {
    return new PropertyConverter&lt;T>(targetType);
  }

  public T from(final Map&lt;String, String> map) {
    return Proxy.newProxyInstance(
      new Class[]{targetType}, targetType.getClassLoader(), new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object[] args) {
          String value = map.get(method.getName());
          if (value == null) {
            Object defaultValue = method.getDefaultValue();
            if (defaultValue == null) {
              throw ...;
            }
            return defaultValue;
          }
          return convert(value, method.getReturnType());
        }
    });
  }
}
</pre><br /><br />convert()函数是调用apache的ConvertUtilsBean做的，没什么说的。<br /><br />那么，用法呢？<br /><br /><pre name="code" class="java">
@interface Foo {
  int id();
  String name() default "";
  Gender sex();
}

Map&lt;String, String> map = ...;
Foo foo = PropertyConverter.to(Foo.class).from(map);
foo.id();
foo.name();
</pre><br /><br />这里面，对annotation的用法比较特别。不过不这么做，java也不提供一个简单并且类型安全的指定缺省值的方法。当然，如果你凑巧不需要缺省值，那么也不用annotation，直接用interface就好。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190440#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 07 May 2008 06:06:13 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190440</link>
        <guid>http://www.javaeye.com/topic/190440</guid>
      </item>
          <item>
        <title>请教重复提交及验证码的问题</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://zhanggok.javaeye.com">zhanggok</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/192010" style="color:red;">http://www.javaeye.com/topic/192010</a>&nbsp;
          发表时间: 2008年05月11日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          请教重复提交及验证码的问题<br />假如有个网上电影订票系统（一个用户只能一天只能选一场电影），选择电影和电影放映厅后画面上还有验证码的图片，我猜想后台的处理是先判断验证码的正确性然后查询数据库看看放映厅是否还有位子，如果没有了给用户提示没有位子，换其他的放映厅这时验证码更换。如果我用JAVA程序模拟提交表单用FOR循环提交只是放映厅不同，相当于同时开多个IE同时提交会出现什么样情况。第一个登陆所选的放映厅人已经满了，第二，三....个登陆的验证码是否还有效。这个系统安全性一般，后台没有什么令牌之类的限制，最多把页面的BUTTON灰化。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/192010#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 May 2008 22:19:10 +0800</pubDate>
        <link>http://www.javaeye.com/topic/192010</link>
        <guid>http://www.javaeye.com/topic/192010</guid>
      </item>
          <item>
        <title>贫血的Domain Model</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://taowen.javaeye.com">taowen</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/191261" style="color:red;">http://www.javaeye.com/topic/191261</a>&nbsp;
          发表时间: 2008年05月09日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          好老的话题啦。拿出来炒炒冷饭。各位见谅。<br />——————————————————————<br />Domain Model贫血是说属于Domain Model的逻辑没有放在Domain Model中。那是哪些逻辑没有放到Domain Model中，从而导致贫血一说呢？原因有很多，但是我认为最主要是Service中的那些逻辑。而这些逻辑又有一个共同的特点就是依赖于DAO，或者说需要查询数据库。Robbin的帖子：http://www.javaeye.com/topic/57075，举了一个很好的例子。我取其中的一个部分在这里做演示用。<br /><br /><pre name="code" class="java">
public class Employee {
    private Set&lt;Task> tasks = new HashSet&lt;Task>();
}
</pre><br /><br /><pre name="code" class="java">
public class Task {
    private String name;
    private Employee owner;
    private Date startTime;
    private Date endTime;
}
</pre><br /><br />这是一个很简单的一对多的关系。现在要查找指定员工的处理中的任务。如果忽略数据库的存在，我想大部分的同志都会这么实现：<br /><br /><pre name="code" class="java">
public class Employee {
    private Set&lt;Task> tasks = new HashSet&lt;Task>();
    public Set&lt;Task> getProcessingTask() {
       ...
    }
}
</pre><br /><br />这也符合OO数据隐藏的基本原则。但是如果有数据库存在，怎么写就不那么容易决定了。如果没有Hibernate这样的ORM。那肯定是：<br /><br /><pre name="code" class="java">
public class TaskDAO {
   public Set&lt;Task> getProcessingTasks(Employee employee) {
      ...//sql
   }
}
</pre><br /><br />那我觉得，这就导致了Domain Model的失血。因为没有数据库的时候，这这个方法本来应该在Employee上的，而不是在DAO上的。<br />如果有Hibernate呢？是不是我就可以把这段代码写到Employee里面去呢？<br /><br /><pre name="code" class="java">
@Entity
public class Employee {
    @OneToMany
    private Set&lt;Task> tasks = new HashSet&lt;Task>();
    public Set&lt;Task> getProcessingTask() {
       ...
    }
}
</pre><br /><br />还是有问题。因为访问tasks的时候，Hibernate会去加载数据。getProcessingTask会便利所有的task。如果task的数量很多，这降极大的影响性能。所以为了能够享受到关系数据库查询速度的好处，我们要还要利用SQL。于是DAO又再次地找到了自己的位置。那么怎么解决这个问题呢？在http://www.javaeye.com/topic/57075的回帖中nihongye同学提出了一个解决方案。本质来说就是不让hibernate来映射tasks，改由查询来获得。加上Spring支持的@Configurable标记，我们可以把代码写成这样<br /><br /><pre name="code" class="java">
@Entity
@Configurable
public class Employee {
    private TaskDao dao;
    public Set&lt;Task> getProcessingTask() {
        return dao.getProcessingTask(this);
    }
    public void setTaskDao(TaskDao dao) {
        this.dao = dao;
    }
}
</pre><br /><br />我们当然还可以把TaskDao替换成变的形式。比如http://www.javaeye.com/topic/65406里firebody提到的那样。但是本质上来说，都是让Employee能够直接去使用Hibernate做查询。但是坏处是给Domain纯净分子的口实。虽然，我认为和ActiveRecord类似，entity绑定在数据库上没啥不好。另外一个缺点就是，要么仍然有一个Dao来封装查询逻辑的实现，要么Employee的实现中出现太多的hibernate api，而且写法复杂。这也就是Robbin一再强调，ActiveRecord那样的api在Java世界中不是不可以，而是实现复杂难度高的原因。注入可以解决问题，但是对Hibernate的依赖强而且写法丑陋。<br />那么有没有更优美的方案呢？有：<br /><br /><pre name="code" class="java">
public class Employee {
    private RichSet&lt;Task> tasks = new DefaultRichSet&lt;Task>();
    public RichSet&lt;Task> getProcessingTasks() {
        return tasks.find("startTime").le(new Date()).find("endTime").isNull();
    }
...
}
</pre><br /><br /><br />RichSet是我自己编造的一个名字。它是一个”rich“的set。其实就是附加了一些find，sort，sum之类的操作。<br /><br /><pre name="code" class="java">
public interface RichSet&lt;T> extends Set&lt;T> {
    Finder&lt;RichSet&lt;T>> find(String expression);
    int sum(String expression);
}
</pre><br /><br />DefaultRichSet是这些附加操作的内存版本的实现。这个能解决问题么？还是不能，这时候getProcessingTasks的时候，richSet还是去遍历内部的_tasks，然后把结果过滤出来。而且，hibernate还拒绝接受这样set。为了让hibernate能够接受RichSet，我们需要这么写配置文件。<br /><br /><pre name="code" class="xml">
&lt;hibernate-mapping default-access="field" package="net.sf.ferrum.example.domain">
    &lt;class name="Employee">
        &lt;tuplizer entity-mode="pojo" class="net.sf.ferrum.RichEntityTuplizer"/>
        &lt;id name="id">
            &lt;generator class="native"/>
        &lt;/id>
        &lt;property name="name"/>
        &lt;property name="salary"/>
        &lt;many-to-one name="department"/>
        &lt;set name="tasks" cascade="all" inverse="true" lazy="true">
            &lt;key/>
            &lt;one-to-many class="Task" />
        &lt;/set>
    &lt;/class>
&lt;/hibernate-mapping>
</pre><br /><br />通过指定RichEntityTuplizer，我们可以控制Hibernate的动态增强过程。<br /><br /><pre name="code" class="java">
public class RichEntityTuplizer extends PojoEntityTuplizer {
    public RichEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
    }

    protected Setter buildPropertySetter(final Property mappedProperty, PersistentClass mappedEntity) {
        final Setter setter = super.buildPropertySetter(mappedProperty, mappedEntity);
        if (!(mappedProperty.getValue() instanceof org.hibernate.mapping.Set)) {
            return setter;
        }
        return new Setter() {
            public void set(Object target, Object value, SessionFactoryImplementor factory) throws HibernateException {
                Object wrappedValue = value;
                if (value instanceof Set) {
                    HibernateRepository repository = new HibernateRepository();
                    repository.setSessionFactory(factory);
                    wrappedValue = new HibernateRichSet((Set) value, repository, getCriteria(mappedProperty, target));
                }
                setter.set(target, wrappedValue, factory);
            }

            public String getMethodName() {
                return setter.getMethodName();
            }

            public Method getMethod() {
                return setter.getMethod();
            }
        };
    }
}
</pre><br /><br />这样，tasks就不再是DefaultRichSet了。Hibernate会尝试去增强为PersisentSet，但是被RichEntityTuplizer改写为增强HibernateRichSet了。这样就形成了HibernateRichSet -> PersisentSet -> DefaultRichSet -> HashSet 的包含关系。<br /><br />当用户尝试在tasks上做find的时候，就不再是DefaultRichSet来做collection遍历了，而是HibernateRichSet去拼装一个DetachedCriteria。最后当用户在查询的结果上取size()或者取具体元素的时候，这个criteria被拿去求值。<br /><br />通过使用RichSet，domain model具有了对自身进行查询的能力。更重要的是，这种能力的获得，不是通过把Hibernate session注入到domain model中。domain仍然是纯净的，没有依赖于数据库的东西。而且domain是可以脱离容器使用的。new Employee出来就可以直接使用，测试。区别只是经过repository增强的entity会使用sql，而transient的entity所有的查询都是通过遍历实现的。<br /><br />没有了DAO之后，Domain Model是不是能够摆脱贫血的困扰呢？这个还需要观察。不过我认为至少是向前迈了一步了。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/191261#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 09 May 2008 00:18:47 +0800</pubDate>
        <link>http://www.javaeye.com/topic/191261</link>
        <guid>http://www.javaeye.com/topic/191261</guid>
      </item>
          <item>
        <title>hibernate入门使用系列 4-- 关系映射篇（下）</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://ryanpoy.javaeye.com">RyanPoy</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190679" style="color:red;">http://www.javaeye.com/topic/190679</a>&nbsp;
          发表时间: 2008年05月07日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          <p>接上篇 <a href="190597" target="_blank">hibernate入门使用系列 3-- 关系映射篇（中）</a>

<br />

<br />

<br />

<br />

开我写的前3篇中，分别讲了one-to-one, one--to-many, many-to-one 。<br />

<br />

这篇，主要讲的是 n：n 的关系。即：many-to-many。<br />

<br />

我们以老师和学生为例，一个老师可以交很多学生，同样一个学生可以拥有多个老师，所以，他们之间的关系就是n：n的。<br />

<br />

实体模型：<br />

<br />

<br />

<img src="../../../topics/download/7cd30464-261e-377c-8b88-5409eda5740f" alt="" />

<br />

从实体模型来看。有2个对象，但是为了在数据库中表示出2者的n:n的关系，我们还得引入一张表。所以，sql脚本如下：</p>
<pre name="code" class="sql"> use HibernateQuickUse;
drop table if exists teacher_student_relation;
drop table if exists Teacher;
drop table if exists Student;

create table Teacher (
	tid varchar(32) primary key,
	name varchar(32) not null
);

create table Student (
	sid varchar(32) primary key,
	name varchar(128) not null
);

create table teacher_student_relation (
	id integer auto_increment primary key,
	teacher_id varchar(32) not null,
	student_id varchar(32) not null,
	foreign key(teacher_id) references Teacher(tid),
	foreign key(student_id) references Student(sid)
);
</pre>
<p>
<br />

<br />

通过模型，创建java类如下：</p>
<p>Student.java</p>
<pre name="code" class="java">package org.py.hib.relation.many2many;

import java.util.HashSet;
import java.util.Set;

/**
 * Student entity.
 */

@SuppressWarnings(&quot;serial&quot;)
public class Student implements java.io.Serializable
{
	private String id;

	private String name;

	private Set&lt;Teacher&gt; teachers = new HashSet&lt;Teacher&gt;(0);

	public Student()
	{
	}

	public String getId()
	{
		return this.id;
	}

	public void setId(String id)
	{
		this.id = id;
	}

	public String getName()
	{
		return this.name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public Set&lt;Teacher&gt; getTeachers()
	{
		return teachers;
	}

	public void setTeachers(Set&lt;Teacher&gt; teachers)
	{
		this.teachers = teachers;
	}
}</pre>
<p>&nbsp;</p>
<p>Teacher.java:</p>
<pre name="code" class="java">package org.py.hib.relation.many2many;

import java.util.HashSet;
import java.util.Set;

/**
 * Teacher entity.
 */

@SuppressWarnings(&quot;serial&quot;)
public class Teacher implements java.io.Serializable
{
	private String id;

	private String name;

	private Set&lt;Student&gt; students = new HashSet&lt;Student&gt;(0);

	public Teacher()
	{
	}

	public String getId()
	{
		return this.id;
	}

	public void setId(String id)
	{
		this.id = id;
	}

	public String getName()
	{
		return this.name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public Set&lt;Student&gt; getStudents()
	{
		return students;
	}

	public void setStudents(Set&lt;Student&gt; students)
	{
		this.students = students;
	}

}</pre>
&nbsp;
<p>xml映射文件如下</p>
<p>Student.hbm.xml</p>
<pre name="code" class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!DOCTYPE hibernate-mapping PUBLIC &quot;-//Hibernate/Hibernate Mapping DTD 3.0//EN&quot;
&quot;http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd&quot;&gt;

&lt;hibernate-mapping&gt;
	&lt;class name=&quot;org.py.hib.relation.many2many.Student&quot;
		table=&quot;student&quot;&gt;
		&lt;id name=&quot;id&quot; type=&quot;java.lang.String&quot; column=&quot;sid&quot; length=&quot;32&quot;&gt;
			&lt;generator class=&quot;uuid&quot; /&gt;
		&lt;/id&gt;

		&lt;property name=&quot;name&quot; type=&quot;java.lang.String&quot; column=&quot;name&quot;
			length=&quot;128&quot; not-null=&quot;true&quot; /&gt;

		&lt;set name=&quot;teachers&quot; table=&quot;teacher_student_relation&quot; cascade=&quot;save-update&quot; inverse=&quot;false&quot;&gt;
			&lt;key column=&quot;student_id&quot; not-null=&quot;true&quot; /&gt;

			&lt;many-to-many column=&quot;teacher_id&quot;
				class=&quot;org.py.hib.relation.many2many.Teacher&quot; 
				/&gt;
		&lt;/set&gt;
	&lt;/class&gt;
&lt;/hibernate-mapping&gt;
</pre>
<p><span style="color: #ff0000;">&nbsp;注意：</span>

</p>
<p>&nbsp;set中的 table 指向的是数据库中的关联表。</p>
<p>cascade 用的是<span style="color: #ff0000;">save-update</span>
, 且inverse用的是false，这样的话，当进行修改和保存和删除时，关联表中的记录也会删掉. </p>
<p>如果cascade 用的是 <span style="color: #ff0000;">all</span>
 那么连同student表中的记录也会被删除掉。</p>
<p>key中的column指的是： 关联表中与Student发生关系的字段。</p>
<p>而many-to-many中的column指的是：关联表中，与class(这里是：org.py.hib.relation.many2many.Teacher)发生关系的字段。</p>
<p>关于inverse，请参考上篇：<a href="190597" target="_blank">hibernate入门使用系列 3-- 关系映射篇（中）</a>

</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Teacher.hbm.xml</p>
<pre name="code" class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!DOCTYPE hibernate-mapping PUBLIC &quot;-//Hibernate/Hibernate Mapping DTD 3.0//EN&quot;
&quot;http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd&quot;&gt;

&lt;hibernate-mapping&gt;
	&lt;class name=&quot;org.py.hib.relation.many2many.Teacher&quot;
		table=&quot;teacher&quot;&gt;
		&lt;id name=&quot;id&quot; type=&quot;java.lang.String&quot; column=&quot;tid&quot;
			length=&quot;32&quot;&gt;
			&lt;generator class=&quot;uuid&quot; /&gt;
		&lt;/id&gt;

		&lt;property name=&quot;name&quot; type=&quot;java.lang.String&quot; column=&quot;name&quot;
			length=&quot;32&quot; not-null=&quot;true&quot; /&gt;

		&lt;set name=&quot;students&quot; table=&quot;teacher_student_relation&quot; cascade=&quot;save-update&quot;
			inverse=&quot;false&quot;&gt;
			&lt;key column=&quot;teacher_id&quot; not-null=&quot;true&quot; /&gt;
			&lt;many-to-many class=&quot;org.py.hib.relation.many2many.Student&quot;
				column=&quot;student_id&quot; /&gt;
		&lt;/set&gt;
	&lt;/class&gt;
&lt;/hibernate-mapping&gt;
</pre>
<p><span style="color: #ff0000;">&nbsp;
注意：</span>
</p>
<p>这里的inverse也采用了false，这样子的话，Teacher和Student都维护关系表中的关系。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>测试类，Many2ManyTest.java</p>
<pre name="code" class="java">package org.py.hib.relation.many2many;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import junit.framework.Assert;
import junit.framework.TestCase;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;

public class Many2ManyTest extends TestCase
{
	private SessionFactory factory;

	@Before
	public void setUp() throws Exception
	{
		Configuration conf = new Configuration().configure();
		factory = conf.buildSessionFactory();
	}

	/**
	 * 测试添加
	 * @throws Exception
	 */
	public void testSave() throws Exception
	{
		System.out.println(&quot;\n=== test save ===&quot;);

		Teacher teacher1 = new Teacher();
		teacher1.setName(&quot;teacher_1&quot;);

		Teacher teacher2 = new Teacher();
		teacher2.setName(&quot;teacher_2&quot;);

		Student stu1 = new Student();
		stu1.setName(&quot;student_1&quot;);

		Student stu2 = new Student();
		stu2.setName(&quot;student_2&quot;);

		stu1.getTeachers().add(teacher1);
		stu1.getTeachers().add(teacher2);

		stu2.getTeachers().add(teacher2);
		teacher1.getStudents().add(stu2);

		Session session = null;
		Transaction tran = null;
		try
		{
			session = factory.openSession();
			tran = session.beginTransaction();

			session.save(stu1);
			session.save(stu2);
			tran.commit();

			Assert.assertNotNull(teacher1.getId());
			Assert.assertNotNull(teacher2.getId());

			Assert.assertNotNull(stu1.getId());
			Assert.assertNotNull(stu2.getId());

		} catch (Exception ex)
		{
			tran.rollback();
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}
	}

	/**
	 * 测试从Teacher查询
	 * @throws Exception
	 */
	@SuppressWarnings(&quot;unchecked&quot;)
	public void testFindFromTeacher() throws Exception
	{
		System.out.println(&quot;\n=== test find from Teacher ===&quot;);
		Session session = null;
		try
		{
			session = factory.openSession();
			Iterator&lt;Teacher&gt; iter = session.createQuery(&quot;from Teacher&quot;).iterate();
			while (iter.hasNext())
			{
				Teacher teacher = iter.next();
				Assert.assertNotNull(teacher.getId());
				String teacherName = teacher.getName();
				if (&quot;teacher_1&quot;.equals(teacherName))
				{
					Set&lt;Student&gt; stus = teacher.getStudents();
					Assert.assertEquals(stus.size(), 2);
					for (Student stu : stus)
					{
						String stuName = stu.getName();
						Assert.assertNotNull(stu.getId());
						Assert.assertTrue(stuName.equals(&quot;student_1&quot;) || stuName.equals(&quot;student_2&quot;));
					}
				} else if (&quot;teacher_2&quot;.equals(teacherName))
				{
					Set&lt;Student&gt; stus = teacher.getStudents();
					Assert.assertEquals(stus.size(), 2);

					for (Student stu : stus)
					{
						String stuName = stu.getName();
						Assert.assertNotNull(stu.getId());
						Assert.assertTrue(stuName.equals(&quot;student_1&quot;) || stuName.equals(&quot;student_2&quot;));
					}
				} else
				{
					throw new Exception(&quot;teacher name error exception.&quot;);
				}
			}
		} catch (Exception ex)
		{
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}
	}

	/**
	 * 测试从Student查询
	 * @throws Exception
	 */
	@SuppressWarnings(&quot;unchecked&quot;)
	public void testFindFromStudent() throws Exception
	{
		System.out.println(&quot;\n=== test find from Student ===&quot;);
		Session session = null;
		try
		{
			session = factory.openSession();
			Iterator&lt;Student&gt; iter = session.createQuery(&quot;from Student&quot;).iterate();
			while (iter.hasNext())
			{
				Student stu = iter.next();
				Assert.assertNotNull(stu.getId());
				String stuName = stu.getName();
				if (&quot;student_1&quot;.equals(stuName))
				{
					Set&lt;Teacher&gt; teachers = stu.getTeachers();
					Assert.assertEquals(teachers.size(), 2);
					for (Teacher teacher : teachers)
					{
						String tName = teacher.getName();
						Assert.assertNotNull(teacher.getId());
						Assert.assertTrue(tName.equals(&quot;teacher_1&quot;) || tName.equals(&quot;teacher_2&quot;));
					}
				} else if (&quot;student_2&quot;.equals(stuName))
				{
					Set&lt;Teacher&gt; teachers = stu.getTeachers();
					Assert.assertEquals(teachers.size(), 2);
					for (Teacher teacher : teachers)
					{
						String tName = teacher.getName();
						Assert.assertNotNull(teacher.getId());
						Assert.assertTrue(tName.equals(&quot;teacher_1&quot;) || tName.equals(&quot;teacher_2&quot;));
					}
				} else
				{
					throw new Exception(&quot;student name error exception.&quot;);
				}
			}
		} catch (Exception ex)
		{
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}
	}

	/**
	 * 测试修改
	 * @throws Exception
	 */
	public void testModify() throws Exception
	{
		System.out.println(&quot;\n=== test modify ===&quot;);
		Session session = null;
		Transaction tran = null;
		try
		{
			session = factory.openSession();
			tran = session.beginTransaction();

			Teacher t1 = (Teacher) session.createQuery(&quot;from Teacher t where t.name='teacher_1'&quot;).list().get(0);
			t1.setName(&quot;new_teacher_1&quot;); // 修改用户名 = m_name2.（原来用户名= m_name）

			Set&lt;Student&gt; stus = t1.getStudents();
			for (Student stu : stus)
			{
				if (stu.getName().equals(&quot;student_1&quot;))
				{
					stus.remove(stu);
					break;
				}
			}

			tran.commit();

		} catch (Exception ex)
		{
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}

		/*
		 * 修改后再查询
		 */
		System.out.println(&quot;\n=== test find from Teacher after modify===&quot;);
		try
		{
			session = factory.openSession();
			Iterator&lt;Teacher&gt; iter = session.createQuery(&quot;from Teacher&quot;).iterate();
			while (iter.hasNext())
			{
				Teacher teacher = iter.next();
				Assert.assertNotNull(teacher.getId());
				String teacherName = teacher.getName();
				if (&quot;new_teacher_1&quot;.equals(teacherName))
				{
					Set&lt;Student&gt; stus = teacher.getStudents();
					Assert.assertEquals(stus.size(), 1);
					for (Student stu : stus)
					{
						String stuName = stu.getName();
						Assert.assertNotNull(stu.getId());
						Assert.assertTrue(stuName.equals(&quot;student_2&quot;));
					}
				} else if (&quot;teacher_2&quot;.equals(teacherName))
				{
					Set&lt;Student&gt; stus = teacher.getStudents();
					Assert.assertEquals(stus.size(), 2);

					for (Student stu : stus)
					{
						String stuName = stu.getName();
						Assert.assertNotNull(stu.getId());
						Assert.assertTrue(stuName.equals(&quot;student_1&quot;) || stuName.equals(&quot;student_2&quot;));
					}
				} else
				{
					throw new Exception(&quot;teacher name error exception.&quot;);
				}
			}
		} catch (Exception ex)
		{
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}
	}

	/**
	 * 测试删除
	 * @throws Exception
	 */
	public void testDelete() throws Exception
	{
		System.out.println(&quot;\n=== test delete ===&quot;);
		Session session = null;
		Transaction tran = null;
		try
		{
			session = factory.openSession();
			tran = session.beginTransaction();

			Iterator&lt;Teacher&gt; iter = session.createQuery(&quot;from Teacher&quot;).iterate();
			while (iter.hasNext())
				session.delete(iter.next());

			tran.commit();

			Integer count = (Integer) session.createQuery(&quot;select count(*) from Teacher&quot;).list().get(0);
			Assert.assertEquals(0, count.intValue());

		} catch (Exception ex)
		{
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}

		/*
		 * 删除后再查询
		 */
		System.out.println(&quot;\n=== test find after delete ===&quot;);
		try
		{
			session = factory.openSession();

			Integer num = (Integer) session.createQuery(&quot;from Father&quot;).list().size();
			Assert.assertEquals(0, num.intValue());

			num = (Integer) session.createQuery(&quot;from Child&quot;).list().size();
			Assert.assertEquals(0, num.intValue());

		} catch (Exception ex)
		{
			throw ex;
		} finally
		{
			if (session != null)
			{
				try
				{
					session.close();
				} catch (Exception ex)
				{
					// nothing to do
				} finally
				{
					if (session != null)
						session = null;
				}
			}
		}
	}

	/**
	 * 
	 */
	@After
	public void tearDown() throws Exception
	{
		factory.close();
	}

}
</pre>
<p>&nbsp;</p>
<p>从这个例子中可以看出，many-to-many中，需要引入第3张表来表示关系。</p>
<p>附件中有源代码。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190679#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 07 May 2008 17:39:31 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190679</link>
        <guid>http://www.javaeye.com/topic/190679</guid>
      </item>
          <item>
        <title>泛型BaseDAO</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://nicholasbugs.javaeye.com">NicholasBugs</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190094" style="color:red;">http://www.javaeye.com/topic/190094</a>&nbsp;
          发表时间: 2008年05月06日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          对于属性比较多的bean,如果不使用hibernate 或者ibatis等持久化解决方案，写查询函数时，单单将ResultSet 转换成Object就是一件很痛苦的事情，因此可以采用java反射机制做一个BaseDao，把ResultSet 映射到Object 的操作封装起来，简化了DAO的开发，<br />本文参照了[url]http://blog.csdn.net/cping1982/archive/2007/10/01/1808647.aspx<br />[/url]并且做了一点改进<br /><pre name="code" class="java">public static String[][] proterty2Column = 
	    {{"member_id","memberId"},		
		{"name", "name"}};
	/**
	 * change the first char to upper case
	 * @param s
	 * @return
	 */
	private static String upperFirstChar(String s){
		char [] chars = s.toCharArray();
		chars[0] = Character.toUpperCase(chars[0]);
		return new String(chars);
	}
	/**
* ResultSet 映射成 Object
	 * @param clzz
	 * @param rs 
	 * @param obj
	 * @param fieldName
	 * @param varibleName
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws SQLException
	 * @throws NoSuchFieldException 
	 * @throws SecurityException 
	 */
    private void  mapResultSet2Object(ResultSet rs, Object obj, String propertyName,
 String columName) 
throws NoSuchMethodException, IllegalAccessException, 
InvocationTargetException, SQLException, 
SecurityException, NoSuchFieldException {
    	 Class &lt; ? extends Object >clazz = obj.getClass();
         Class &lt; ? extends Object >propertyType = clazz.getDeclaredField(propertyName).
getType();
       Method method = clazz.getDeclaredMethod("set"+ 
     upperFirstChar( propertyName ), new Class[] { propertyType });
       if (propertyType == String.class)
           method.invoke(obj, (Object [])new String[] 
{rs.getString( columName ) });
       else if (propertyType == int.class)
           method.invoke(obj, (Object [])new Integer[] 
{new Integer( rs.getInt( columName )) });
       else if (propertyType == float.class)
           method.invoke(obj, (Object [])new Float[] 
{new Float( rs.getFloat( columName )) });
       else if (propertyType == long.class)
           method.invoke(obj, (Object [])new Long[]
 {new Long( rs.getLong( columName )) });
       else if (propertyType == double.class)
           method.invoke(obj, (Object [])new Double[] 
{new Double( rs.getDouble( columName )) });
       else if(propertyType == Date.class){
    	   method.invoke(obj, (Object [])new Date[] 
{rs.getDate(columName)});
       }
   }
    /**
     * 单行查询
     * @param 
     * @param conn
     * @param sql
     * @param clazz
     * @param params
     * @return
     * @throws Exception
     */
    public  &lt;T> T getItem(Connection conn, String sql, Class&lt;T> clazz, 
  String params[])throws Exception{
    	PreparedStatement pstmt = null;
    	ResultSet rset = null;
    	T t  = null;
    	try {
    		pstmt = conn.prepareStatement(sql);
    		//set parameter 
               for(int i=0; i&lt;params.length; i++){
    			pstmt.setString(i+1, (String)params[i]);
    		}
              rset = pstmt.executeQuery();
            if (rset.next()) {
                t =  clazz.newInstance();
    		for(int i=0; i&lt; proterty2Column.length; i++) {
                	String propertyName = proterty2Column[i][1].trim();
                    String ColumnName = proterty2Column[i][0].trim();
                    mapResultSet2Object(rset, t, propertyName, ColumnName);
                }
            }
        } catch (Exception e) {
        	e.printStackTrace();
	    } finally {
	        DBUtil.closeAll(conn, pstmt, rset);
	    }
     return t;
    }</pre><br /><pre name="code" class="java">
   /**
     * 多行查询
     * @param 
     * @param conn
     * @param sql
     * @param proterty2Column
     * @param clazz
     * @return
     * @throws Exception
     */
    public   &lt;T> List &lt;T> getItems(Connection conn, String sql, Class&lt;T> clazz,  
String[] params) throws Exception{
    	if (proterty2Column.length == 0)
            return null;
    	PreparedStatement pstmt = null;
    	ResultSet rset = null;
    	List&lt;T> list = new ArrayList&lt;T>();
    	try {
    		pstmt = conn.prepareStatement(sql);
               for(int i=0; i&lt;params.length; i++){
    			pstmt.setString(i+1, (String)params[i]);
    		}
    		rset = pstmt.executeQuery();
            while (rset.next()) {
    		for(int i=0; i&lt; proterty2Column.length; i++) {
                	String propertyName = proterty2Column[i][1].trim();
                    String ColumnName = proterty2Column[i][0].trim();
                    fetchResult2Object(rset, obj, propertyName, ColumnName);
                }
                if( null == obj ) continue;
                list.add(obj);
            }
        } catch (Exception e) {
        	e.printStackTrace();
	    } finally {
	        DBUtil.closeAll(conn, pstmt, rset);
	    }
     return list;
    }
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190094#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 11:57:21 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190094</link>
        <guid>http://www.javaeye.com/topic/190094</guid>
      </item>
          <item>
        <title>&lt;提问&gt; JBPM 如何在流程控制中管理业务数据？</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://abo123.javaeye.com">abo123</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/191949" style="color:red;">http://www.javaeye.com/topic/191949</a>&nbsp;
          发表时间: 2008年05月11日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          新手提问: <br />看了JBPM的DOC,大致明白了它是如何定义和控制流程的,但是如何和业务数据整合起来还想不太明白,希望大家指教: <br /><br />案例情况: 有一个流程,每个节点都会有很多结果数据(信息表,审核表,合同等),如何把这些信息与流程的流转结合起来? 并且每个节点必须在这些数输入或者处理后才能结束? <br /><br />我想了想: <br /><br />方法一:把每个节点涉及到的所有信息均用JBPM中的Variable来处理,这样就相对简单.但是如果节点很多,信息也很多.这样处理的话 以后维护起来不方便;另外如果这些信息只是作为流程变量存储,就没有其他的入口进行管理.如果以后需要修改,也只能通过流程节点,再一步一步检索出信息,想起来也不是很方便. <br /><br />方法二:对业务中涉及到的信息分类,分别建表,如建立&lt;合同表>,其中合同ID作为主键; 在jbpm的节点中,设置一个变量 : contractID,用来索引到合同表,在流程流转的时候,调用其他页面来处理合同信息,再返回到流程流转页面,进行跳转. <br /><br />问题: <br /><br />1、大家采用以上那种方式进行业务数据的存储，或者有更好的解决办法？ <br /><br />2、如何来控制必须先填写（处理）业务数据，才能继续流程的流转？ 是通过设置一个《完成变量》吗？如果已经填写业务信息，就把变量设置为true？？ <br /><br /><br />很希望得到大家的指点 ：） 多谢 <br /><br />我的email 是 wangtlx@163.com.
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/191949#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 May 2008 16:21:38 +0800</pubDate>
        <link>http://www.javaeye.com/topic/191949</link>
        <guid>http://www.javaeye.com/topic/191949</guid>
      </item>
          <item>
        <title>通过jvm参数启动tomcat如何加载外部的property文件</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://yebigroc.javaeye.com">yebigroc</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/191937" style="color:red;">http://www.javaeye.com/topic/191937</a>&nbsp;
          发表时间: 2008年05月11日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          &lt;java classname="org.apache.catalina.startup.Bootstrap" fork="true" maxmemory="${Xmx}" dir="${webapps}/ROOT"<br />              spawn="true"><br />            &lt;classpath refid="tomcat.classpath"/><br />            &lt;classpath refid="app.classpath"/><br />            &lt;jvmarg value="-Dcatalina.home=${tomcatHome}"/><br />            &lt;jvmarg value="-Dcatalina.base=${webapps}"/><br />            &lt;jvmarg value="-Xms${Xms}"/><br />            &lt;jvmarg value="-Xmx${Xmx}"/><br />          <br />            &lt;sysproperty key="propertyFile" value="${propertyFile}" /><br /><br />            &lt;jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${debug.port}"/><br />            &lt;jvmarg value="-Xdebug"/>            <br />            &lt;arg line="${arg}" />            <br />        &lt;/java>        <br /><br /><br />指定了${propertyFile}， tomcat在启动的时候如何去寻找这个property文件，是在server.xml中配置吗<br /><br /><br />谢谢
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/191937#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 11 May 2008 14:56:30 +0800</pubDate>
        <link>http://www.javaeye.com/topic/191937</link>
        <guid>http://www.javaeye.com/topic/191937</guid>
      </item>
          <item>
        <title>Scala拾趣--从Java7说开来</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://eastsun.javaeye.com">Eastsun</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190608" style="color:red;">http://www.javaeye.com/topic/190608</a>&nbsp;
          发表时间: 2008年05月07日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          　　我们知道，关于当前正在进行中的Java7在Java社区有很多讨论。其焦点集中在要不要在Java7中引入一些新的语言特性，尤其是闭包：不仅有要不要加入闭包的争论，还有采用那种实现方式的问题。在<a href="http://www.javaeye.com/news/598" target="_blank">javapolis举行的关于JAVA7语言特性投票的结果</a>一文中列出了Java7中可能会加入的语言特性，那么我们先来看看在Scala中对于这些语言特性有何解决方式呢？<br />　　首先把闭包撇出来，因为对闭包不甚了解，所以就不多说。不过以我的看法，因为Scala本身就支持函数式编程，而Java还需要向后兼容性的考虑，所以我觉得Java7中无论以那种方式来实现闭包，也不太可能比Scala中的实现更加有效，或更加优雅。<br />　　下面我们就逐条来分析Java7中的十种语法提议：<br /><br /><span style="font-size: large"><span style="color: blue">1.Property declaration <br />2.Property access</span></span><br />　　这两条都是为了简化书写代码，这里用一个具体的例子来说明：<br />　　考虑一个Person类，这个类有两个属性，一个是表示姓名的forename，在JAVA7中可能的实现方式：<br /><br /><pre name="code" class="java">public class Person {   
 public property String forename;   
 public property int age;   
} </pre>  <br /><br />　　而使用Scala，则可以使用下列方式（参考资料:<a href="http://scala.sygneca.com/code/defining-bean-properties" target="_blank">Defining a BeanProperty</a>）：<br /><br /><pre name="code" class="java">class Person(@BeanProperty var forename:String,@BeanProperty var age:Int)</pre><br /><br />　　一行代码搞定！<br /><br /><br /><br /><span style="font-size: large"><span style="color: blue">3.Improve generics </span></span><br />　　Scala中也支持泛型，而且貌似比JAVA中的更灵活。不过其实现方式与目前的JAVA一样，都是使用擦除化。因此对于JAVA中泛型存在的一些问题，Scala中也存在（唔，至少这条提议中列出的两个问题在Scala中也同样存在。其他的我不太清楚，目前对Scala中的泛型理解尚浅）。<br /><br /><br /><span style="font-size: large"><span style="color: blue">4.Access List and Map using [] </span></span><br />　　在Scala中可以像下面一样使用Map：<br /><br /><pre name="code" class="java">import scala.collection.mutable.HashMap
object MapAccess extends Application{
    var map =new HashMap[Int,String]
    map(0) ="Zero"
    map += 1 -> "One"
    map += 2 -> "Two"
    var value =map(2)
    println(value)
}</pre><br />　　可以看到，在Scala中可以通过map(key)来读取value，通过map(key) =value来写入值对...<br />　　事实上，Scala中并没有对Map提供特别的语法支持。也就是说，对任意的类，你都可以像操作Map一样。只要你在一个类a中定义了apply方法，你就可以把这个类当作一个函数来使：<br />   　　a(something)<br />　　这等价于：<br />   　　a.apply(something)<br />　　如果你还定义了update方法，你就可以使用<br />   　　a(key) =value<br />　　这等价于<br />   　　a.update(key,value)<br />　　怎么样，不赖吧？<br /><br /><span style="font-size: large"><span style="color: blue">5,10.Null-handling and chaining </span></span><br />　　之所以有这两个提议，是由于在Java中存在null以及void类型的方法。在Java中，很多方法会返回一个null表示没有得到预期的结果或结果为空。事实上大部分情况这样做是不恰当的，这时抛出一个异常或返回一个表示“空”的对象（比如字符串“”，或空的List）可能更合理。而且这样造成的后果是对于很多方法调用后需要对其结果是否为null进行判断。<br />　　幸运的是，Scala中没有这些问题。<br />　　第一：在Scala中没有void，也就是说每个方法都会返回一个实实在在的对象（Java中的void在Scala中有一个对应的类Unit）。<br />　　第二：对于标准的Scala程序，null不应该出现。相对应的Scala中有个Option类来处理这种返回结果为“空”的情形。<br />　　这里我也不细说了，有兴趣的可以参看opensdp同学的 <a href="http://www.javaeye.com/topic/72517" target="_blank">用Scala语言中的 Option 对象来处理 null-like 返回值</a>。<br /><br /><br /><br /><span style="font-size: large"><span style="color: blue">6.Extension methods</span></span><br />　　这个有点像Ruby中的“open class”，就是允许在不修改原有代码的情况下给已有的类添加新的方法。<br />　　由于JAVA是静态类型语言，并且不允许两个名字完全一样的类的存在，所以在这一点的实现肯定会有很多限制，不可能做到像Ruby那样。目前有两种解决方案：<br /><div class="quote_title">Neal Gafter的提议 写道</div><div class="quote_div"><br />example:<br /><br />import static java.util.Collections.sort;<br />…<br />List&lt;String> list = …;<br />list.sort();</div><br /><div class="quote_title">Peter Ahé's 的提议 写道</div><div class="quote_div"><br />"Declaration-Site Extension Methods"<br /><br />example:<br /><br />package java.util;<br />interface List&lt;E> … {  <br />…  <br />void sort() import static java.util.Collections.sort;  <br />…<br />}</div><br />　　第一种实现可以看成是static import的一种扩展；第二种实现同样用到了static import，并且需要修改已有代码。<br />　　总之，这两种方案看起来都不甚优雅，甚至可以说丑陋。其意义也不大，并且对代码的可读性会造成一定的影响。<br />　　那么我们来看看Scala中能够如何解决这个问题。Scala中有一个功能很强大的机制：隐式类型转换。这个机制威力巨大，用处远不止Extension methods，这里我只举个例子说明如何解决Extension methods，有兴趣的可以参看fakechris同学写的<a href="http://www.javaeye.com/topic/107445" target="_blank">scala学习笔记(5) -- implicit type</a><br /><br />　　在Ruby中，我们可以通过如下方式向String类中添加print_self方法：<br /><br /><pre name="code" class="ruby">class String
  def print_self
    puts self
  end
end</pre><br />　　然后我们就可以对普通的String调用print_self方法：<br /><br /><pre name="code" class="ruby">"Daniel Spiewak".print_self    # prints my name</pre><br />　　那么Scala中怎末实现这个呢？很简单：<br /><br /><pre name="code" class="java">object StringTest extends Application{
    
    "Eastsun".printSelf         //对String调用printSelf方法
    
    implicit def stringWrapper(s:String) =new {
        def printSelf = println(s)
    }
}</pre><br />　　并且在类StringTest可见的范围内，这个方法都是有效的。（参考资料：<a href="http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6" target="_blank">Getting Over Java</a>）<br /><br /><br /><br /><span style="font-size: large"><span style="color: blue">7.String switch </span></span><br />　　在Scala中没有switch关键词，但是有另一个强大得多的机制（不过，也复杂得多）：Pattern match。实现String switch功能，那只不过是小菜一根。<br /><br /><pre name="code" class="java">object MatchTest extends Application{
    
    test("hello")
    
    def test(obj:Any):Unit = obj match{
        case 1|2|3|4 => println("A integer between 1 and 4")
        case "hello" => println("Hi")
        case _       => println("something else")
    }
}</pre><br /><br /><br /><br /><span style="font-size: large"><span style="color: blue">8.Typedef </span></span><br />　　唔，对于这个功能...但是Scala中恰好就有这样一个关键词type，typedef就是这个关键词的作用之一：<br /><br /><pre name="code" class="java">import scala.collection.mutable.HashMap
object TypeTest extends Application{
    type ISMap =HashMap[Int,String]
    var map =new ISMap
    map(1) ="One"
}</pre><br /><br /><br /><br /><br /><span style="font-size: large"><span style="color: blue">9.Multi-catch </span></span><br />　　这里我们又可以来感受一下Scala中Pattern match的威力了：<br /><pre name="code" class="java">import java.io.IOException
object ExceptionCatch extends Application{
    
    exceptionCatch(ioexceptionThrow)
    
    def ioexceptionThrow():Unit = throw new IOException
    
    def exceptionCatch(func:()=>Unit) =
        try{
            func()
        }catch{
            case _:IllegalArgumentException|_:IllegalStateException => println("RuntimeException")
            case _:IOException => println("IOException")
            case _             => println("Something else")
        }
}</pre><br /><br />　　<span style="font-size: large"><span style="color: blue">结论</span>：</span>可以看到，目前在JAVA中想方设法想要加入的语言特性，在Scala中要么是根本不需要的东西，要么是以一种更加优雅的方式实现了。但同时，在学习Scala的过程中，一方面感受到Scala语法所带来的巨大便利与威力，另一方面其语法比起JAVA来复杂了许多。譬如在Java中粗略来说有interface,abstract class与普通的class。而Scala中除了普通的class与abstract class还有case class，sealed class,trait,object这些类型的类。更不用说Scala中那些函数式有关的语法了。<br />　　因此，可能有人会有疑问：有着这么复杂语法的语言有存在的必要吗？会不会成为下一个C++（恐龙）呢？Daniel Spiewak 在他的博客<a href="http://www.codecommit.com/blog/scala/is-scala-really-the-next-c" target="_blank">Is Scala Really the Next C++?</a>中也提出了这个问题，他的答案是否定的。主要的理由是：C++由于兼容的目的背上了C这个沉重的包袱，由于C的影响，很多语言特性不能很好的实现；而Scala不同，Scala与Java在源代码上是不兼容的，因此Scala可以更加自由的发挥。<br />　　我比较赞同这个观点，同时觉得Java7不应该添加太多的东西进去了。虽然现在Java代码相对其他新式语言来说显得啰嗦，但是Java简单，这就是它最大的优点。如果Java即要考虑向后兼容性，又想把新的特性一股脑加进去，到后来只可能走向C++的老路。这些新的特性应该由JVM上的其他语言来实现，比如Groovy，比如Scala。你觉得呢？<br />　　<span style="color: red">PS:</span>根据达尔文的理论，生物的进化包括<span style="color: blue">遗传</span>与<span style="color: blue">变异</span>。而目前的JAVA是只“遗传”不“变异”，这对于语言的进化也是很不好的。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190608#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 07 May 2008 15:02:14 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190608</link>
        <guid>http://www.javaeye.com/topic/190608</guid>
      </item>
          <item>
        <title>硬件越跑越快，软件越陷越慢</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://lgx522.javaeye.com">lgx522</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190302" style="color:red;">http://www.javaeye.com/topic/190302</a>&nbsp;
          发表时间: 2008年05月06日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          近日总算有点空闲，走马观花测试了一些技术，包括Grails、Seam、AOM、Python、ZendFramework、CakePHP、Flex、WPF等等，回到JE看了一些讨论，忍不住又要放点黄腔了。<br /><br />自从多核CPU成为PC标配以后，硬件又上了好大一个台阶。到朋友家看了一下“孤岛危机”，实在是超级惊艳。单位上也终于耗上了一台双核、2G内存，这下跑什么IDE和AppServer都不用去小歇片刻了，真是感谢硬件产商们的努力。<br /><br />某天看了一篇文章，地址记不清了，却道出了应用程序的本质：“不过就是在数据库里读读写写”，这下便像吃了苍蝇般不爽了起来。搞腾这个行当转眼也七、八年了，回头一想，的确是该反省反省了。<br /><br />好几年前，更换电脑似乎总是为游戏而换。越来越清晰、越来越眩目、越来越震撼，且不论游戏好不好玩，单声光效果的提高都物有所值。那时候的应用程序其实要求是不高的，VB、Delphi、ASP、PHP这些老革命的IDE和作品，至今可以在怀旧的时候，拿到奔腾166的老机器上去跑一跑，丝毫不见慢。所以那时候更换电脑是与App无关了。<br /><br />Java引领的虚拟机时代让笔者一度迷了五六年，曾经笔者一度天真地以为只要全面进入虚拟机和中间件时代就可以解决企业应用软件的种种问题，达到高度的业务逻辑重用、高度的异构集成、高度的安全性与伸缩性。这其间折腾的技术、框架加起来怎么也有几十种了，时光飞逝，转眼三十老几了，回头一想，当初的信仰很傻很天真，到头来“不过就是在数据库里读读写写”，最可笑的不过是越来越复杂、越来越慢。看来这些年是陪Sun、IBM、Microsoft以及开源领域的大牛们玩过去了。<br /><br />由于是在单位上混，出于饭碗的需要，几年来不得不参加了当初以为“不切实际”的软考，一直混到系统分析师。回头看下来，这些个“不切实际”的学究体系其实反倒有些有用处。硬着头皮大体上啃了一遍学究知识，最后才搞明白程序要快要稳定，还是要搞清楚CPU、内存和硬盘；而所谓的可靠性、重用性、扩展性、...XX性，不是靠什么具体的软件技术，而是在于规范的管理与审慎的规划。<br /><br />缘木求鱼，这就是国内软件业超级混乱的根源。根子上在于我们想偷懒的惰性，明明是我们该自己去思考、去设计、去解决的问题，我们不断地迷信可以依靠“大腕”、“大牛”们来解决。其实连伟大的党都承认了，“没有放之四海而皆准的真理”，何况是软件这种由人造、由人用的事物。结果如何，“大腕”、“大牛”们出于各种各样的目的，不断制造混乱。而我们，正是那随波逐流混水中的泥。<br /><br />虚拟机时代到来了，动态语言时代到来了，SOA时代到来了，XXX时代到来了，无数吹鼓手吹起了喇叭，震耳欲聋。大家昏头昏脑跳进大大小小的池塘，一边陷下去，一边互相嘲笑、互相鄙视、互相谩骂。好一个热闹的软件大超市。<br /><br />吹嘘有何用，迷信有何用？最终，还是要抓住硬件这根救人的稻草。
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190302#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 17:04:48 +0800</pubDate>
        <link>http://www.javaeye.com/topic/190302</link>
        <guid>http://www.javaeye.com/topic/190302</guid>
      </item>
          <item>
        <title>struts2-core-2.0.11与struts2-core-2.0.8兼容问题</title>
        <author>JavaEye网站</author>
        <description>
          <![CDATA[
          <br/>
          网站: <a href="http://www.javaeye.com">JavaEye</a>&nbsp;
          作者: <a href="http://javaflasher.javaeye.com">JavaFlasher</a>&nbsp;
                    链接：<a href="http://www.javaeye.com/topic/190015" style="color:red;">http://www.javaeye.com/topic/190015</a>&nbsp;
          发表时间: 2008年05月06日
          <br/>
          声明：本文系JavaEye网站发布的原创文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/>
          struts2-core-2.0.8升级到struts2-core-2.0.11 发现 个 问题 。<br /><br />原来这样的写法都正常<br /><br /><pre name="code" class="java">     &lt;s:if test="${not empty param.kindId}">
     document.getElementById("kindId").value =${param.kindId};
     &lt;/s:if>
</pre><br /><br /><br />现在 都抱错 ：<br /><br /><pre name="code" class="java">javax.servlet.ServletException: org.apache.jasper.JasperException: /module/basic_manage/user_show.jsp(85,5) According to TLD or attribute directive in tag file, attribute test does not accept any expressions
</pre><br /><br />查了它的 tld文件发现，居然 ：<br /><br />一个是 ：<br /><br /><pre name="code" class="java">
    &lt;attribute>
      &lt;name>test&lt;/name>
      &lt;required>true&lt;/required>
      &lt;rtexprvalue>true&lt;/rtexprvalue>
      &lt;description>&lt;![CDATA[Expression to determine if body of tag is to be displayed]]&gt;&lt;/description>
    &lt;/attribute>
</pre><br /><br />另一个是 ：<br /><pre name="code" class="java">    &lt;attribute>
      &lt;name>test&lt;/name>
      &lt;required>true&lt;/required>
      &lt;rtexprvalue>false&lt;/rtexprvalue>
      &lt;description>&lt;![CDATA[Expression to determine if body of tag is to be displayed]]&gt;&lt;/description>
    &lt;/attribute></pre><br /><br /><br />他们在搞什么啊？  不支持表达式了 。 兼容性啊！
          <br/>
          <span style="color:red;">
            <a href="http://www.javaeye.com/topic/190015#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/70' target='_blank'><span style="color:red;font-weight:bold;">第二届网络工程师侠客行大会5月24日杭州举行</span></a></li><li><a href='/adverts/41' target='_blank'><sp