2006年12月11日

一个SWT应用程序的基本组成部分为显示界面(Display)、命令界面(Shell,使命令进入并使运行初始化)和窗口部件(Widgets)。Display负责管理事件循环和控制UI线程和其他线程之间的通讯。Shell是应用程序中被操作系统窗口管理器管理的窗口。每个SWT应用程序至少需要一个Display和大于等于1个的Shell实例。


图1:从不同的角度看SWT应用程序


  图1从不同的角度展示了SWT应用程序。左侧的图是一个简化的UI对象的继承图。中间的图展示了UI对象的容器结构(containment structure)。右侧的图则是创建后的UI外观。

  如果一个应用程序使用了多个线程,那么每个线程都使用的是Display对象分配给它自己的实例。程序员可以使用静态方法Display.getCurent()来得到Display对象的当前活动的实例。

  Shell用于在特定的操作系统中表现窗口。Shell可以最大化、最小化或正常化。Shell有两种类型。第1种是高层shell,它是Display的子窗口,同时它也是一个主窗口。第2类是对话shell,这种shell要依赖于其他的shell窗口存在。shell窗口最终成为上述那种类型,要看在创建shell时传递给shell构造函数的是什么风格位(style bits)。一个shell的默认值是DialogShell。也就是说,如果不带参数,那默认就是一个对话shell。而如果给参数赋予了一个Display对象,则该shell将是一个高层shell。

  一些窗口部件的属性必须在创建它们的初期就要被设置。这些窗口部件的属性就是前面所说的风格位(style bits)。在SWT的类中,风格位被定义为常数。例如,Button button = new Button( shell, <styleBits> )。可以使用或(OR)操作符“|”来设置多个风格位。例如,如果想设置一个带边界的压下按钮,需要传递SWT.PUSH | SWT.BORDER作为风格位参数。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bnlovebn/archive/2011/06/14/6543693.aspx

posted @ 2011-06-14 14:33 重归本垒(Bing) 阅读(378) | 评论 (0)编辑 收藏
 

找到AppData\Local\Genuitec\Common\configuration\com.genuitec.pulse2.client.common.provisioning中的文件rmb-2042360.latest.snapshot,在文件rmb-2042360.latest.snapshot中找到你要删除的插件名。把这行删除即可。

posted @ 2011-06-14 11:32 重归本垒(Bing) 阅读(3668) | 评论 (1)编辑 收藏
 
最近orcale数据只有一台可以服务,导致hibernate 连接数据库每个13分钟就会报“APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks”的错误.
原因是 hibernate 使用c3p0连接orcale数据后不会释放 , c3p0的最大连接数为100,但显然c3p0有Bug,导致数据库连接池不够用,导致进程锁死。
后换Proxool后,观察正常。

下面转引其它网友文章说明c3p0 、 Proxool、 dbcp  的区别
1<!-- JDBC驱动程序 -->   
2<property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/struts?useUnicode=true&characterEncoding=GBK</property> <!-- 数据库用户名 -->   
3<property name="connection.username">root</property> <!-- 数据库密码 -->

上面的一段配置,在c3p0dbcp中,都是必需的,因为hibernate会根据上述的配置来生成connections,再交给c3p0dbcp管理.

1 C3P0

只需在hibernate.cfg.xml中加入
1<property name="c3p0.min_size">5</property>   
2<property name="c3p0.max_size">30</property>   
3<property name="c3p0.time_out">1800</property>   
4<property name="c3p0.max_statement">50</property>   
5

还有在classespath中加入c3p0-0.8.4.5.jar


2 dbcp

在hibernate.cfg.xml中加入
 1<property name="dbcp.maxActive">100</property>   
 2<property name="dbcp.whenExhaustedAction">1</property>   
 3<property name="dbcp.maxWait">60000</property>   
 4<property name="dbcp.maxIdle">10</property>   
 5   
 6<property name="dbcp.ps.maxActive">100</property>   
 7<property name="dbcp.ps.whenExhaustedAction">1</property>   
 8<property name="dbcp.ps.maxWait">60000</property>   
 9<property name="dbcp.ps.maxIdle">10</property>  
10

还有在classespath中加入commons-pool-1.2.jar 和commons-dbcp-1.2.1.jar.

3 proxool

由于数据库connection在较长时间没有访问下会自动断开连接,导致浏览出错,增加proxool作为数据库pool。它有自动连接功能。
1)、从http://proxool.sourceforge...下载proxool,释放proxool.jar到WEB-INF/lib

2)、在hibernate.cfg.xml中增加:
1<property name="hibernate.proxool.pool_alias">dbpool</property>   
2<property name="hibernate.proxool.xml">proxool.xml</property>   
3<property name="connection.provider_class">org.hibernate.connection.ProxoolConnectionProvider</property>  
4

3)、在与hibernate.cfg.xml同级目录(src根目录下)增加proxool.xml文件:
 1<?xml version="1.0" encoding="utf-8"?>   
 2<!-- the proxool configuration can be embedded within your own application's.    
 3 Anything outside the "proxool" tag is ignored. -->   
 4<something-else-entirely>   
 5 <proxool>   
 6   <alias>dbpool</alias>   
 7   <!--proxool只能管理由自己产生的连接-->   
 8   <driver-url>   
 9     jdbc:mysql://127.0.0.1:3306/wlsh?characterEncoding=GBK&useUnicode=true&autoReconnect=true     </driver-url>   
10   <driver-class>com.mysql.jdbc.Driver</driver-class>   
11   <driver-properties>   
12       <property name="user" value="root" />   
13       <property name="password" value="123456" />   
14   </driver-properties>   
15   <!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁-->   
16   <house-keeping-sleep-time>90000</house-keeping-sleep-time>   
17   <!-- 最少保持的空闲连接数-->   
18   <prototype-count>5</prototype-count>   
19   <!-- 允许最大连接数,超过了这个连接,再有请求时,就排在队列中等候,最大的等待请求数由maximum-new-connections决定-->   
20   <maximum-connection-count>100</maximum-connection-count>   
21   <!-- 最小连接数-->   
22   <minimum-connection-count>10</minimum-connection-count>   
23 </proxool>   
24</something-else-entirely>  
25

于在hibernate3.0中,已经不再支持dbcp了,hibernate的作者在hibernate.org中,明确指出在实践中发现dbcp有 BUG,在某些种情会产生很多空连接不能释放,所以抛弃了对dbcp的支持。至于c3p0,有评论说它的算法不是最优的,因为网上查资料得知:有网友做了一个实验,在同一项目中分别用了几个常用的连接池,然后测试其性能,发现c3p0占用资源比较大,效率也不高。所以,基于上述原因,proxool不少行家推荐使用,而且暂时来说,是负面评价是最少的一个。在三星中也有项目是用proxool的。从性能和出错率来说,proxool稍微比前两种好些。C3P0,稳定性似乎不错,在这方面似乎有很好的口碑。至于性能,应该不是最好的,算是中规中矩的类型。
  Proxool的口碑似乎很好,不大见到负面的评价,从官方资料上来看,有许多有用的特性和特点,也是许多人推荐的。
posted @ 2011-06-12 13:51 重归本垒(Bing) 阅读(5271) | 评论 (0)编辑 收藏
 
1、was6.1基于j2ee1.4。
2、was6.1ND版中有Edge Components产品。
3、was6.1各版本都有一些基本的功能。
posted @ 2010-04-12 10:41 重归本垒(Bing) 阅读(318) | 评论 (0)编辑 收藏
 
     摘要: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html>     <head>         ...  阅读全文
posted @ 2008-12-21 02:56 重归本垒(Bing) 阅读(3843) | 评论 (2)编辑 收藏
 
<span id="spnTime"></span><script language="javascript">
var http = new XMLHttpRequest;
http.open(
"HEAD""."false);
http.send(
null);
var curDate = new Date;
var offsetTime = curDate - Date.parse(http.getResponseHeader("Date"));
setInterval(
function()
{
    curDate.setTime(
new Date - offsetTime);
    document.getElementById(
"spnTime").innerHTML = curDate.toLocaleString();
}
1000);
</script>
posted @ 2008-09-26 08:42 重归本垒(Bing) 阅读(329) | 评论 (0)编辑 收藏
 

 

<!-- 把下列代码加入到head区内 -->
<style>




#tablist a
{
text-decoration
: none;
padding
: 2px 0.2em;
border
: 1px solid #778;
background
: white;
}


#tablist  a:link, #tablist  a:visited
{
color
: navy;
}


#tablist  a:hover
{
color
: black;
background
: lightyellow;
border-color
: navy;
}


#tablist  a.current
{
background
: lightyellow;
}

</style>


<!-- 把下列代码加入到body区内 -->
<label id="tablist">
<href="http://www.yahoo.com">Yahoo</a>
<href="http://www.google.com">Google</a>
<href="http://www.sina.com">退出</a>
</label>
posted @ 2008-09-23 11:53 重归本垒(Bing) 阅读(252) | 评论 (0)编辑 收藏
 
1、源代码包的安装    
  gzip   -d   apache_1.3.20.tar.gz   (解压)    
  tar   xvf   apache_1.3.20.tar   (解包)    
  cd   apache_1.3.20    
  ./configure   (配置)   ----./configure   --help(查看configure选项)    
  make   (编译)    
  make   install   (安装)    
  make   clean   (卸载)    
   
  注:典型的源代码包可以这样安装,但不都是这样,如webmin    
  要执行其目录下./setup.sh进入交互式配置安装    
  卸载用uninstall程序    
  具体如果不清楚看要安装的包下的README文件    
   
  2、RPM包的安装    
  RPM软件包的一个例子:    
  foo-1.0-1.i386.rpm    
  其中包括软件包的名称(foo),版本号(1.0),发行号(1),和硬件平台(i386)。    
  (1)安装    
  #   rpm   -ivh   foo-1.0-1.i386.rpm    
  foo    
  #######################    
  A.   软件包已被安装    
  #   rpm   -ivh   foo-1.0-1.i386.rpm    
  foo   package   foo-1.0-1   is   already   installed    
  error:   foo-1.0-1.i386.rpm   cannot   be   installed    
  如果你仍旧要安装该软件包,你可以在命令行上使用--replacepkgs   选项,这将忽略该错误信息。    
  B.   文件冲突    
  如果要安装的软件包中有一个文件已在安装其它软件包时安装,会出现以下错误信息:    
  #   rpm   -ivh   foo-1.0-1.i386.rpm    
  foo   /usr/bin/foo   conflicts   with   file   from   bar-1.0-1    
  error:   foo-1.0-1.i386.rpm   cannot   be   installed    
  要想让RPM   忽略该错误信息,   请使用--replacefiles   命令行选项    
  C.未解决依赖关系    
  RPM软件包可能依赖于其它软件包,   在安装了特定的软件包之后才能安装该软件包。    
  #   rpm   -ivh   bar-1.0-1.i386.rpm    
  failed   dependencies:    
  foo   is   needed   by   bar-1.0-1    
  你必须安装完所依赖的软件包,才能解决这个问题。如果想强制安装   (但是,这样安装后的软件包未必能正常运行),请使用-nodeps   命令行选项。    
   
  (2)   卸载    
  #   rpm   -e   foo    
  注意:这里使用软件包的名字foo,而不是软件包文件的名字“foo-1.0-1.i386.rpm”.    
  如果其它软件包依赖于你要卸载的软件包,卸载时则会产生错误信息。如:    
  #   rpm   -e   foo    
  removing   these   packages   would   break   dependencies:    
  foo   is   needed   by   bar-1.0-1    
  要想RPM忽略该错误信息继续卸载的话   (但是,依赖于该软件包的程序可能无法运行),   请使用-nodeps   命令行选项。    
  (3)升级    
  #   rpm   -Uvh   foo-2.0-1.i386.rpm    
  foo    
  ###############################    
  当使用旧版本的软件包来升级新版本的软件时,会产生以下错误信息:    
  #   rpm   -Uvh   foo-1.0-1.i386.rpm    
  foo   package   foo-2.0-1   (which   is   newer)   is   already   installed    
  error:   foo-1.0-1.i386.rpm   cannot   be   installed    
  要使RPM   坚持这样“升级”,可使用--oldpackage   命令行参数。    
  (4)查询    
  #   rpm   -q   foo    
  foo-2.0-1    
  软件包指定选项:    
  -a   查询所有已安装的软件包.    
  -f   <file>   将查询包含有文件<file>的软件包    
  -p   <packagefile>    
  查询软件包文件名为<packagefile>的软件包    
  信息选择选项:    
  -i   显示软件包信息,如描述,   发行号,   尺寸,   构建日期,   安装日期,   平台,   以及其它各类信息。    
  -l   显示软件包中的文件列表。    
  -s   显示软件包中所有文件的状态。    
  -d   显示被标注为文档的文件列表(man   手册,   info   手册,   README's,   etc).    
  -c   显示被标注为配置文件的文件列表。这些是要在安装完毕以后加以定制的文件(sendmail.cf,   passwd,   inittab,   etc)。    
  对于那些要显示文件列表的文件,可以增加-v   命令行选项以获得如同   ls   -l   格式的输出。    
  (5)验证    
  验证软件包是通过比较软件包中安装的文件和软件包中的原始文件信息来进行的。除了其它一些东西,验证主要是比较文件的尺寸,   MD5   校验码,   文件权限,   类型,   属主和用户组等。    
  rpm   -V命令用来验证一个软件包,如    
  rpm   -V   foo    
  验证包含特定文件的软件包:    
  rpm   -Vf   /bin/vi    
  验证所有已安装的软件包:    
  rpm   -Va    
  根据一个RPM来验证某个软件包:    
  rpm   -Vp   foo-1.0-1.i386.rpm    
  如果你担心RPM数据库已被破坏,就可以使用这种方式。如果一切校验均正常将不会产生任何输出。如果有不一致的地方,就会显示出来。    
  输出格式是8位长字符串,c   用以指配置文件,接着是文件名.   8位字符的每一个用以表示文件与RPM数据库中一种属性的比较结果。“.”   (点)表示测试通过。    
  以下字符表示某种测试的失败:    
  5   MD5   校验码    
  S   文件尺寸    
  L   符号连接    
  T   文件修改日期    
  D   设备    
  U   用户    
  G   用户组    
  M   模式e   (包括权限和文件类型)    
  如果有信息输出,应当认真加以考虑,是删除,重新安装,还是修正出现的问题。    
  (6)RPM应用的几个例子    
  A.   如你误删了一些文件,   但是不能肯定到底删除了哪些文件。如果你想验证一下整个系统看看都丢失了哪些文件的话,可以键入:    
  rpm   –Va    
  B.若是一些文件丢失了或已被损坏,   就可以重新安装或先卸载再安装该软件包。如果碰到了一个自己不认识的文件,要想查处它属于哪个软件包,可以输入以下命令:    
  rpm   -qf   /usr/X11R6/bin/xjewel    
  而输出的结果会是:    
  xjewel-1.6-1    
  C.   如果发生综合以上两个例子的情况,如文/usr/bin/paste出了问题。你想验证一下拥有该文件的软件包,可又不知道软件包的名字,这时可以简单的键入:    
  rpm   -Vf   /usr/bin/paste    
  这样相应的软件包就会被验证。    
  D.   如果你想了解一个正在使用的程序的详细信息,可以键入如下命令来获得拥有该程序的软件包中的文档信息:    
  rpm   -qdf   /usr/bin/ispell    
  输出结果为:    
  /usr/man/man4/ispell.4    
  /usr/man/man4/english.4    
  …………………………………………………………    
   
  E.   如果你发现了一个新的koules   RPM,但是不知道它是什么东西,可以键入如下命令:    
  rpm   -qip   koules-1.2-2.i386.rpm    
  F.   现在你想了解koules   RPM   所安装的文件。可以键入:    
  rpm   -qlp   koules-1.2-2.i386.rpm    
  图形管理工具:kpackage    
   
  3、shell或java脚本安装    
  基于图形界面的安装,一般基于SHELL或Java语言编写,主要应用于一些办公软件和制图软件及安装程序,如staroffice、oracle的安装,很容易,和windows一样     
   
posted @ 2008-06-13 17:47 重归本垒(Bing) 阅读(9205) | 评论 (0)编辑 收藏
 
Struts2+spring2时应注意action的单实例问题
注意要设置,action bean 的 scope 的值。因为spring的bean默认为单实例,故一定要设scope的值但不能为singleton。
posted @ 2008-06-04 15:25 重归本垒(Bing) 阅读(710) | 评论 (0)编辑 收藏
 

如何使用spring的作用域:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>

这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。

在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称prototype), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类型,满足实际应用需求。

1、singleton作用域

当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。

配置实例:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>

或者

<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>

2、prototype

prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的

getBean()

方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)

配置实例:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>

或者

<beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>

3、request

request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例:

request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:

如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可:

 

 

<web-app>



<listener>

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

</listener>



</web-app>

<!--
,如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现:
-->
<web-app>

..

<filter>

   
<filter-name>requestContextFilter</filter-name> 

    
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>

</filter> 

<filter-mapping>

    
<filter-name>requestContextFilter</filter-name> 

    
<url-pattern>/*</url-pattern>

</filter-mapping>



</web-app>

 

接着既可以配置bean的作用域了:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>

4、session

session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例:

配置实例:

和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>

5、global session

global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

配置实例:

和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>

6、自定义bean装配作用域

在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定义,自定义自己的作用域只要实现该接口即可,下面给个实例:

我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:

 

publicclass MyScope implements Scope 

    privatefinal ThreadLocal threadScope 
= new ThreadLocal() {

          
protected Object initialValue() {

            returnnew HashMap(); 

          }
 

    }


    
public Object get(String name, ObjectFactory objectFactory) 

        Map scope 
= (Map) threadScope.get(); 

        Object object 
= scope.get(name); 

        
if(object==null

          object 
= objectFactory.getObject(); 

          scope.put(name, object); 

        }
 

        
return object; 

    }
 

    
public Object remove(String name) 

        Map scope 
= (Map) threadScope.get(); 

        
return scope.remove(name); 

    }


    publicvoid registerDestructionCallback(String name, Runnable callback) 


    }


    
public String getConversationId() {

       
// TODO Auto-generated method stub

       returnnull;

    }
 

         }

posted @ 2008-06-04 15:21 重归本垒(Bing) 阅读(480) | 评论 (0)编辑 收藏
 

最近的一个项目在Hibernate使用C3P0的连接池,数据库为Mysql。开发测试没有问题,在运行中每个一段长的空闲时间就出现异常:

org.hibernate.exception.JDBCConnectionException: could not execute query 
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:
74
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:
43

Caused by: com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.Connection was implicitly closed due to underlying exception
/error: 


** BEGIN NESTED EXCEPTION ** 

com.mysql.jdbc.CommunicationsException 
MESSAGE: Communications link failure due to underlying exception: 

** BEGIN NESTED EXCEPTION ** 

java.net.SocketException 
MESSAGE: Broken pipe 

STACKTRACE: 

java.net.SocketException: Broken pipe 
at java.net.SocketOutputStream.socketWrite0(Native Method) 
 
** END NESTED EXCEPTION ** 


查看了Mysql的文档,以及Connector/J的文档以及在线说明发现,出现这种异常的原因是:

Mysql服务器默认的“wait_timeout”是8小时,也就是说一个connection空闲超过8个小时,Mysql将自动断开该connection。这就是问题的所在,在C3P0 pools中的connections如果空闲超过8小时,Mysql将其断开,而C3P0并不知道该connection已经失效,如果这时有Client请求connection,C3P0将该失效的Connection提供给Client,将会造成上面的异常。

解决的方法有3种:

  1. 增加wait_timeout的时间。
  2. 减少Connection pools中connection的lifetime。
  3. 测试Connection pools中connection的有效性。

当然最好的办法是同时综合使用上述3种方法,下面就DBCP和C3P0分别做一说明,假设wait_timeout为默认的8小时

DBCP增加以下配置信息:

//set to 'SELECT 1' 
validationQuery = "SELECT 1" 
//set to 'true' 
testWhileIdle = "true" 
//some positive integer 
timeBetweenEvictionRunsMillis = 3600000 
//set to something smaller than 'wait_timeout' 
minEvictableIdleTimeMillis = 18000000 
//if you don't mind a hit for every getConnection(), set to "true" 
testOnBorrow = "true" 

C3P0增加以下配置信息:
//获取connnection时测试是否有效 
testConnectionOnCheckin = true 
//自动测试的table名称

automaticTestTable
=C3P0TestTable

//set to something much less than wait_timeout, prevents connections from going stale 
idleConnectionTestPeriod = 18000 
//set to something slightly less than wait_timeout, preventing 'stale' connections from being handed out 
maxIdleTime = 25000 
//if you can take the performance 'hit', set to "true" 
testConnectionOnCheckout = true 

更多的配置信息大家可以查看C3P0文档,Connector/J文档,以及DBCP的文档。
posted @ 2008-06-03 08:55 重归本垒(Bing) 阅读(10613) | 评论 (0)编辑 收藏
 
public int getCount(String emailGroupId, String emailBatchId)
            
throws HibernateException {

        Session session 
= HibernateUtil.currentSession();
        Transaction tx 
= session.beginTransaction();

        String hql 
= "select count(*) from EmailSendInfo where email_group_id = :emailGroupId and batch_id = :batchId";
        Query query 
= session.createQuery(hql);

        query.setString(
"emailGroupId", emailGroupId);
        query.setString(
"batchId", emailBatchId);
        
/**//*
         * for (Iterator it = query.iterate(); it.hasNext();) { return
         * ((Integer) it.next()).intValue(); }
         
*/

        
try {
            
return ((Integer) query.iterate().next()).intValue();
        }
 catch (Exception e) {
            
throw new HibernateException("");
        }
 finally {
            tx.commit();
            HibernateUtil.closeSession();
        }

    }

spring+hibernate

//第一种方法:
  String hql = "select count(*) from User as user";
  Integer count 
= (Integer)getHibernateTemplate().find(hql).listIterator().next();
  
return count.intValue();

//第二种方法:
 String hql = "select count(*) from User as user";
  
return ((Integer)getHibernateTemplate().iterate(hql).next()).intValue();

//第三种方法:
 String hql = "select count(*) from User as user";
 Query query 
=  getHibernateTemplate().createQuery( getSession(),hql);
 
return ((Integer)query.uniqueResult()).intValue(); 

posted @ 2008-05-29 14:59 重归本垒(Bing) 阅读(9286) | 评论 (1)编辑 收藏
 

取出字符中文没有乱码,而写入确是乱码,
在java,jsp,数据库,表格都统一为、utf8或GBK等后,
最后要在,my.ini或my.cnf中加入编码
如:
[mysqld]
default-character-set=utf8
default-storage-engine=INNODB

[client]

port=3306

[mysql]

default-character-set=utf8


 

posted @ 2008-05-26 17:06 重归本垒(Bing) 阅读(258) | 评论 (0)编辑 收藏
 
下载地址为:http://dev.mysql.com/downloads/mysql/5.1.html,打开此网页,下拉网页找到“Linux x86 generic RPM (statically linked against glibc 2.2.5) downloads项,找到“Server”和“Client programs”项,下载需要的上述两个rpm文件。
2、安装
MySQL
   rpm文件是Red Hat公司开发的软件安装包,rpm可让Linux在安装软件包时免除许多复杂的手续。该命令在安装时常用的参数是 –ivh ,其中i表示将安装指定的rmp软件包,V表示安装时的详细信息,h表示在安装期间出现“#”符号来显示目前的安装过程。这个符号将持续到安装完成后才停止。

   1)安装服务器端

   在有两个rmp文件的目录下运行如下命令:

   [root@test1 local]# rpm -ivh
MySQL-server-5.1.7-0.i386.rpm MySQL-client-5.1.7-0.i386.rpm  
显示如下信息。
warning:
MySQL-server-5.1.7-0.i386.rpm

signature: NOKEY, key ID 5072e1f5
   Preparing...       ########################################### [100%]
   1:MySQL-server     ########################################### [100%]
    。。。。。。(省略显示)
   /usr/bin/mysqladmin -u root password 'new-password'
   /usr/bin/mysqladmin -u root -h test1 password 'new-password'
    。。。。。。(省略显示)
   Starting mysqld daemon with databases from /var/lib/mysql
   如出现如上信息,服务端安装完毕。测试是否成功可运行netstat看Mysql端口是否打开,如打开表示服务已经启动,安装成功。Mysql默认的端口是3306。
   [root@test1 local]# netstat -nat
   Active Internet connections (servers and established)
   Proto Recv-Q Send-Q Local Address      Foreign Address     State   
   tcp  0  0 0.0.0.0:3306     0.0.0.0:*      LISTEN   
   上面显示可以看出MySQL服务已经启动。
   2)安装客户端
   运行如下命令:
   [root@test1 local]# rpm -ivh
MySQL-client-5.1.7-0.i386.rpm

   warning: MySQL-client-5.1.7-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5
   Preparing...    ########################################### [100%]
   1:MySQL-client  ########################################### [100%]
   显示安装完毕。
   用下面的命令连接mysql,测试是否成功。
  三、登录MySQL

   登录MySQL的命令是mysql, mysql 的使用语法如下:
   mysql [-u username] [-h host] [-p[password]] [dbname]
   username 与 password 分别是 MySQL 的用户名与密码,mysql的初始管理帐号是root,没有密码,注意:这个root用户不是Linux的系统用户。MySQL默认用户是root,由于初始没有密码,第一次进时只需键入mysql即可。
   [root@test1 local]# mysql
   Welcome to the MySQL monitor. Commands end with ; or \g.
   Your MySQL connection id is 1 to server version: 4.0.16-standard
   Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
   mysql>
   出现了“mysql>”提示符,恭喜你,安装成功!
   增加了密码后的登录格式如下:
   mysql -u root -p
   Enter password: (输入密码)
   其中-u后跟的是用户名,-p要求输入密码,回车后在输入密码处输入密码。

   注意:这个mysql文件在/usr/bin目录下,与后面讲的启动文件/etc/init.d/mysql不是一个文件。

   四、MySQL的几个重要目录

   MySQL安装完成后不象SQL Server默认安装在一个目录,它的数据库文件、配置文件和命令文件分别在不同的目录,了解这些目录非常重要,尤其对于Linux的初学者,因为 Linux本身的目录结构就比较复杂,如果搞不清楚MySQL的安装目录那就无从谈起深入学习。

   下面就介绍一下这几个目录。

   1、数据库目录
   /var/lib/mysql/

   2、配置文件
   /usr/share/mysql(mysql.server命令及配置文件)

   3、相关命令
   /usr/bin(mysqladmin mysqldump等命令)

   4、启动脚本
   /etc/rc.d/init.d/(启动脚本文件mysql的目录)
  五、修改登录密码

   MySQL默认没有密码,安装完毕增加密码的重要性是不言而喻的。

   1、命令
   usr/bin/mysqladmin -u root password 'new-password'
   格式:mysqladmin -u用户名 -p旧密码 password 新密码

   2、例子
   例1:给root加个密码123456。
   键入以下命令 :
   [root@test1 local]# /usr/bin/mysqladmin -u root password 123456
   注:因为开始时root没有密码,所以-p旧密码一项就可以省略了。

   3、测试是否修改成功
   1)不用密码登录
   [root@test1 local]# mysql
   ERROR 1045: Access denied for user: 'root@localhost' (Using password: NO)
   显示错误,说明密码已经修改。
   2)用修改后的密码登录
   [root@test1 local]# mysql -u root -p
   Enter password: (输入修改后的密码123456)
   Welcome to the MySQL monitor. Commands end with ; or \g.
   Your MySQL connection id is 4 to server version: 4.0.16-standard
   Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
   mysql>
   成功!
   这是通过mysqladmin命令修改口令,也可通过修改库来更改口令。

   六、启动与停止

   1、启动
   MySQL安装完成后启动文件mysql在/etc/init.d目录下,在需要启动时运行下面命令即可。
   [root@test1 init.d]# /etc/init.d/mysql start

   2、停止
   /usr/bin/mysqladmin -u root -p shutdown

   3、自动启动
   1)察看mysql是否在自动启动列表中
   [root@test1 local]# /sbin/chkconfig --list
   2)把MySQL添加到你系统的启动服务组里面去
   [root@test1 local]# /sbin/chkconfig –- add mysql
   3)把MySQL从启动服务组里面删除。
   [root@test1 local]# /sbin/chkconfig –-del mysql
七、更改MySQL目录

   MySQL默认的数据文件存储目录为/var/lib/mysql。假如要把目录移到/home/data下需要进行下面几步:

   1、home目录下建立data目录
   cd /home
   mkdir data

   2、把MySQL服务进程停掉:
   mysqladmin -u root -p shutdown

   3、把/var/lib/mysql整个目录移到/home/data
   mv /var/lib/mysql /home/data/
   这样就把MySQL的数据文件移动到了/home/data/mysql下

   4、找到my.cnf配置文件
   如果/etc/目录下没有my.cnf配置文件,请到/usr/share/mysql/下找到*.cnf文件,拷贝其中一个到/etc/并改名为my.cnf)中。命令如下:
   [root@test1 mysql]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf

   5、编辑MySQL的配置文件/etc/my.cnf
   为保证MySQL能够正常工作,需要指明mysql.sock文件的产生位置。修改socket=/var/lib/mysql/mysql.sock一行中等号右边的值为:/home/mysql/mysql.sock 。操作如下:
   vi  my.cnf    (用vi工具编辑my.cnf文件,找到下列数据修改之)
   # The MySQL server
    [mysqld]
    port   = 3306
    #socket  = /var/lib/mysql/mysql.sock(原内容,为了更稳妥用“#”注释此行)
    socket  = /home/data/mysql/mysql.sock   (加上此行)

   6、修改MySQL启动脚本/etc/rc.d/init.d/mysql
   最后,需要修改MySQL启动脚本/etc/rc.d/init.d/mysql,把其中datadir=/var/lib/mysql一行中,等号右边的路径改成你现在的实际存放路径:home/data/mysql。
   [root@test1 etc]# vi /etc/rc.d/init.d/mysql
   #datadir=/var/lib/mysql    (注释此行)
   datadir=/home/data/mysql   (加上此行)

   7、重新启动MySQL服务
   /etc/rc.d/init.d/mysql start
   或用reboot命令重启Linux
   如果工作正常移动就成功了,否则对照前面的7步再检查一下。

   八、MySQL的常用操作

   注意:MySQL中每个命令后都要以分号;结尾。

   1、显示数据库
   mysql> show databases;
   +----------+
   | Database |
   +----------+
   | mysql  |
   | test   |
   +----------+
   2 rows in set (0.04 sec)
   Mysql刚安装完有两个数据库:mysql和test。mysql库非常重要,它里面有MySQL的系统信息,我们改密码和新增用户,实际上就是用这个库中的相关表进行操作。

   2、显示数据库中的表
   mysql> use mysql; (打开库,对每个库进行操作就要打开此库,类似于foxpro )
   Database changed

   mysql> show tables;
   +-----------------+
   | Tables_in_mysql |
   +-----------------+
   | columns_priv  |
   | db       |
   | func      |
   | host      |
   | tables_priv   |
   | user      |
   +-----------------+
   6 rows in set (0.01 sec)

   3、显示数据表的结构:
   describe 表名;

   4、显示表中的记录:
   select * from 表名;
   例如:显示mysql库中user表中的纪录。所有能对MySQL用户操作的用户都在此表中。
   Select * from user;

   5、建库:
   create database 库名;
   例如:创建一个名字位aaa的库
   mysql> create databases aaa;
6、建表:
   use 库名;
   create table 表名 (字段设定列表);
   例如:在刚创建的aaa库中建立表name,表中有id(序号,自动增长),xm(姓名),xb(性别),csny(出身年月)四个字段
   use aaa;
   mysql> create table name (id int(3) auto_increment not null primary key, xm char(8),xb char(2),csny date);
   可以用describe命令察看刚建立的表结构。
   mysql> describe name;

   +-------+---------+------+-----+---------+----------------+
   | Field | Type  | Null | Key | Default | Extra     |
   +-------+---------+------+-----+---------+----------------+
   | id  | int(3) |   | PRI | NULL  | auto_increment |
   | xm  | char(8) | YES |   | NULL  |        |
   | xb  | char(2) | YES |   | NULL  |        |
   | csny | date  | YES |   | NULL  |        |
   +-------+---------+------+-----+---------+----------------+

   7、增加记录
   例如:增加几条相关纪录。
   mysql> insert into name values('','张三','男','1971-10-01');
   mysql> insert into name values('','白云','女','1972-05-20');
   可用select命令来验证结果。
   mysql> select * from name;
   +----+------+------+------------+
   | id | xm  | xb  | csny    |
   +----+------+------+------------+
   | 1 | 张三 | 男  | 1971-10-01 |
   | 2 | 白云 | 女  | 1972-05-20 |
   +----+------+------+------------+

   8、修改纪录
   例如:将张三的出生年月改为1971-01-10
   mysql> update name set csny='1971-01-10' where xm='张三';

   9、删除纪录
   例如:删除张三的纪录。
   mysql> delete from name where xm='张三';

   10、删库和删表
   drop database 库名;
   drop table 表名;

   九、增加MySQL用户

   格式:grant select on 数据库.* to 用户名@登录主机 identified by "密码"
例1、增加一个用户user_1密码为123,让他可以在任何主机上登录,并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入MySQL,然后键入以下命令:

   mysql> grant select,insert,update,delete on *.* to user_1@"%" Identified by "123";
例1增加的用户是十分危险的,如果知道了user_1的密码,那么他就可以在网上的任何一台电脑上登录你的MySQL数据库并对你的数据为所欲为了,解决办法见例2。

  例2、增加一个用户user_2密码为123,让此用户只可以在localhost上登录,并可以对数据库aaa进行查询、插入、修改、删除的操作(localhost指本地主机,即MySQL数据库所在的那台主机),这样用户即使用知道user_2的密码,他也无法从网上直接访问数据库,只能通过 MYSQL主机来操作aaa库。

   mysql>grant select,insert,update,delete on aaa.* to user_2@localhost identified by "123";

   用新增的用户如果登录不了MySQL,在登录时用如下命令:

   mysql -u user_1 -p -h 192.168.113.50 (-h后跟的是要登录主机的ip地址)

   十、备份与恢复

   1、备份

   例如:将上例创建的aaa库备份到文件back_aaa中

   [root@test1 root]# cd /home/data/mysql (进入到库目录,本例库已由val/lib/mysql转到/home/data/mysql,见上述第七部分内容)
   [root@test1 mysql]# mysqldump -u root -p --opt aaa > back_aaa

   2、恢复

   [root@test mysql]# mysql -u root -p ccc < back_aaa
posted @ 2008-05-26 16:59 重归本垒(Bing) 阅读(415) | 评论 (0)编辑 收藏
 
1. 本文需要两个文件,httpd和subversion。
·httpd是web服务器,用来通过web访问subversion,这里是官方网站,这里是它的下载网页,
  这里可以下载到httpd-2.2.2.tar.bz2。
·subversion就是本文的主角,这里是他的官方网站,这里是它的下载网页,
  这里可以下载到subversion-1.3.1.tar.bz2
2. 新建一个用户:svnroot
最好不要让root用户参与到svn的权限管理和日常的运行和维护工作中来,但是下面的一些安装和配置操作还是 需要root用户来完成的,因为有些操作只有root才能做。
3. 编译安装httpd (root用户操作):
//解压apache2安装包
# tar xvzf httpd-2.2.2.tar.gz
//进入解压后的目录
# cd httpd-2.2.2
//配置apache安装,前两个参数是必须要加的,你还可以根据您的需要添加其他的参数。
//后面的参数制定你要把apache安装哪里
# ./configure --enable-dav --enable-so --prefix=/usr/local/apache2/
# make
//安装
# make install
# cd /usr/local/apache2/bin
//启动apache服务
# ./apachectl start
//打开浏览器http://localhost/如果有测试页"It works!"出现则证明已经安装成功。
3. 安装Subversion
//解压SubVersion安装包 (root用户进行下面的操作)
# tar xvzf Subversion-1.3.1.tar.gz
//进入解压后的目录
# cd Subversion-1.3.1
//配置subversion安装
#./configure --with-apxs=/usr/local/apache2/bin/apxs --prefix=/usr/local/subversion
--with-apr=/usr/local/apache2 --with-apr-util=/usr/local/apache2 --with-ssl --with-zlib
--enable-maintainer-mode

//提请注意的是:没有加上后面两个参数,服务器会出现500错误,apache的error_log显示如下:
//Could not fetch resource information. [500, #0]
//Could not open the root of the repository [500, #22]
//Can't set position pointer in file '/web/www_root/svn/test/db/revs/0': Invalid argument [500, #22]
# make
//安装
# make install
//创建库文件所在的目录 (svnroot用户进行下面的操作)
# mkdir /home/svnroot/repository
//进入subversion的bin目录
# cd /usr/local/subversion/bin
//创建仓库"test"
# ./svnadmin create /home/svnroot/repository/test
# cd /home/svnroot/repository/test
//看看是不是多了些文件,如果是则说明Subversion安装成功了
# ls –l
# cd /home/user/import
//这条语句将把路径/home/user/import下找到的文件导入到你创建的Subversion 仓库中去,
//提交后的修订版为1。
# ./svn import –m  /home/user/import file:///home/svnroot/repository/test
//不让其他人有该目录的权限
# chmod 700 /home/svnroot/repository

4. 修改Apache配置文件
# cd /usr/local/apadche2/bin
//启动Apache
# ./apachect1 start
# vi /usr/local/apache2/conf/httpd.conf
  
//在最下面添加
   LoadModule dav_svn_module modules/mod_dav_svn.so
   LoadModule authz_svn_module modules/mod_authz_svn.so
   <Location /svn>
   DAV svn
   SVNParentPath /home/svnroot/repository/
//svn父目录
   AuthzSVNAccessFile /home/svnroot/repository/authz.conf
//权限配置文件
   AuthType Basic
//连接类型设置
   AuthName "Subversion.zoneyump"
//连接框提示
   AuthUserFile /home/svnroot/repository/authfile
//用户配置文件
   Require valid-user
//采用何种认证
   </Location>
   //其中authfile是通过"htpasswd [–c] /home/svnroot/repository/authfile username password"来创建的
   //"Require valid-user"告诉apache在authfile中所有的用户都可以访问。如果没有它,
   //则只能第一个用户可以访问新建库

5. 重启apache
# ./usr/local/apache2/bin/apachectl restart
//打开浏览器访问http://localhost/svn/test/,如果有东西显示就说明成功。
6. 权限管理
1)增加用户
# htpasswd [-c] /home/svnroot/repository/authfile wooin
//第一次设置用户时使用-c表示新建一个用户文件。回车后输入用户密码,完成对用户的增加
# htpasswd authfile 用户名(加入新的用户)
2)权限分配
# vi /home/svnroot/repository/authz.conf
   [test:/]
//这表示,仓库test的根目录下的访问权限
   wooin = rw
//test仓库wooin用户具有读和写权限
   bao = r
//test仓库bao用户具有读权限
   [test2:/]
//test2仓库根目录下的访问权限
   wooin = r
//wooin用户在test2仓库根目录下只有读权限
   bao =
//bao用户在 test2仓库根目录下无任何权限
   [/]
//这个表示在所有仓库的根目录下
   * = r
//这个表示对所有的用户都具有读权限
   #[groups]
//这个表示群组设置
   #svn1-developers = wooin, bao
//这个表示某群组里的成员
   #svn2-developers = wooin
   #[svn1:/]
   #@svn1-developers = rw
//如果在前面加上@符号,则表示这是个群组权限设置
将这个设置完成后。重启Apache,就可以通过
http://localhost/svn/test
这个URL来访问仓库了,当然,受权限的限制,必须是合法用户才能访问且具有相应的权限
7. 一些备忘:
1. svn checkout http://localhost/svn/hello.world

2. svn commit 时的默认编辑器的环境变量$SVN_EDITOR=vi需要手动设定,用kate好像有问题

3. 如果linux的登录用户名密码都和svn的其中一个用户名密码相同时,在checkout的时候不会要求输入用户名密码直接就可以checkout出来。比如:linux有个用户wooin,svn也有一个用户wooin,并且密码都是一样的,当用wooin登录linux后,执行checkout,可以直接提取出源码文件,不用输入认证信息。

4. 在svn使用过程中牵扯到几种权限:文件系统的权限,linux系统权限,svn用户的权限,apache进程的权限。

文件系统的权限,linux系统权限:这里相同的意思,就是平时大家使用linux时文件夹和文件的访问权限。在 svn建立仓库,文件夹,配置文件的时候用svnroot用户,并将仓库权限设置为700,不允许其他用户直接通过文件系统查看,只能由svnroot进行管理。

apache进程的权限:因为所有跟仓库传输的操作都是通过apache进程进行的,所以即使你给svn用户设置了很大的权限,但是apache进程没有访问仓库或者相关文件的权限也没有用,apache进程的权限设置在 /usr/local/apache2/conf/httpd.conf 文件中配置,找到文件中的这两行:
User daemon # 将daemon改为svnroot,让apache进程以svnroot的身份运行
Group daemon

svn用户的权限:就是在repository/authz.conf文件中设置的权限信息,是svn用来管理仓库访问权限的。

5. svn服务器设置有两种方式:http 和 svnserve。这里介绍的是http方法

6. 在/etc/profile的结尾设置一些svn启动时要做的工作
# start apache server for svn
/usr/sbin/apachectl start
export SVN_EDITOR=vi

7. APR libraries 安装 SVN 的时候最好指定 --with-apr= 和 --with-apr-util= 参数到 Apache 安装的根目录
(ServerRoot)下,而不是使用缺省的 SVN 安装包中自带的 apr 。否则如果你安装的 Apache
版本不同有可能导致 APR 库不匹配,出现类似:
Can't set position pointer in file '/svn/test/db/revs/1': Invalid argument 的错误。
Updated 2006-04-20 16:30 -- 比如说如果你安装的是apache 2.2.0版本,就需要在编译安装svn的时候指定
--with-apxs和--with-apr参数到你的apache2.2.0安装目录下:
./configure --prefix=${subversionInstallFolder} /
--with-apxs=${apacheInstallFolder}/bin/apxs /
--with-apr=${apacheInstallFolder} /
--with-apr-util=${apacheInstallFolder} /
--with-ssl /
--with-zlib /
--enable-maintainer-mode
posted @ 2008-05-23 12:23 重归本垒(Bing) 阅读(1415) | 评论 (0)编辑 收藏
 
rm -rf 目录名
rmdir只能删除空目录
posted @ 2008-05-23 12:21 重归本垒(Bing) 阅读(1735) | 评论 (0)编辑 收藏
 

改变一个文件的权限: chmod mode file|dir
改变所有子目录的权限: chmod mode dir -R

mode = 777 or 752 and so on.

mode的三个数字,分别表示 owner,group,others所具有的权限。

1 = x 执行 2 = w 写 4 = r 读,比如owner具有所有权限,1+2+4=7,

又比如 group 具有 读 和 执行 权限 1+4 = 5

posted @ 2008-05-23 12:18 重归本垒(Bing) 阅读(16729) | 评论 (0)编辑 收藏
 
原因:如果上一次编译时为20071001,你把系统时间改成20070901后再编译就会报这样的错误.
解决:把时间改了或运行下来命令再make
find . -type f -exec touch {} \;
posted @ 2008-05-23 12:15 重归本垒(Bing) 阅读(13730) | 评论 (13)编辑 收藏
 

如果你从事与数据库相关的工作,有可能会涉及到将数据从外部数据文件插入倒SQL Server的操作。本文将为大家演示如何利用BULK INSERT命令来导入数据,并讲解怎样通过改变该命令的一些选项以便更方便且更有效地插入数据。


  如果你从事与数据库相关的工作,有可能会涉及到将数据从外部数据文件插入倒SQL Server的操作。本文将为大家演示如何利用BULK INSERT命令来导入数据,并讲解怎样通过改变该命令的一些选项以便更方便且更有效地插入数据。

  BULK INSERT

  在SQL Server中,BULK INSERT是用来将外部文件以一种特定的格式加载到数据库表的T-SQL命令。该命令使开发人员能够直接将数据加载到数据库表中,而不需要使用类似于Integration Services这样的外部程序。虽然BULK INSERT不允许包含任何复杂的逻辑或转换,但能够提供与格式化相关的选项,并告诉我们导入是如何实现的。BULK INSERT有一个使用限制,就是只能将数据导入SQL Server。

  插入数据

  下面的例子能让我们更好的理解如何使用BULK INSERT命令。首先,我们来创建一个名为Sales的表,我们将要把来自文本文件的数据插入到这个表中。

  CREATE TABLE [dbo].[Sales]
  (
  [SaleID] [int],
  [Product] [varchar](10) NULL,
  [SaleDate] [datetime] NULL,
  [SalePrice] [money] NULL
  )

  当我们使用BULK INSERT命令来插入数据时,不要启动目标表中的触发器,因为触发器会减缓数据导入的进程。

  在下一个例子中,我们将在Sales表上创建触发器,用来打印插入到表中的记录的数量。

  CREATE TRIGGER tr_Sales
  ON Sales
  FOR INSERT
  AS
  BEGIN
  PRINT CAST(@@ROWCOUNT AS VARCHAR(5)) + ' rows Inserted.'
  END

  这里我们选择文本文件作为源数据文件,文本文件中的值通过逗号分割开。该文件包含1000条记录,而且其字段和Sales表的字段直接关联。由于该文本文件中的值是由逗号分割开的,我们只需要指定FIELDTERMINATOR即可。注意,当下面这条语句运行时,我们刚刚创建的触发器并没有启动:

  BULK INSERT Sales FROM 'c:SalesText.txt' WITH (FIELDTERMINATOR = ',')

  当我们要的数据量非常大时,有时候就需要启动触发器。下面的脚本使用了FIRE_TRIGGERS选项来指明在目标表上的任何触发器都应当启动:

  BULK INSERT Sales FROM 'c:SalesText.txt' WITH (FIELDTERMINATOR = ',', FIRE_TRIGGERS)

  我们可以使用BATCHSIZE指令来设置在单个事务中可以插入到表中的记录的数量。在前一个例子中,所有的1000条记录都在同一个事务中被插入到目标表里。下面的例子,我们将BATCHSIZE参数设置为2,也就是说要对该表执行500次独立的插入事务。这也意味着启动500次触发器,所以将有500咯打印指令输出到屏幕上。

  如果你从事与数据库相关的工作,有可能会涉及到将数据从外部数据文件插入倒SQL Server的操作。本文将为大家演示如何利用BULK INSERT命令来导入数据,并讲解怎样通过改变该命令的一些选项以便更方便且更有效地插入数据。

 

  BULK INSERT Sales FROM 'c:SalesText.txt' WITH (FIELDTERMINATOR = ',', FIRE_TRIGGERS, BATCHSIZE = 2)

  BULK INSERT不仅仅可以应用于SQL Server 2005的本地映射驱动器。下面的语句将告诉我们如何从名为FileServer的服务器的D盘中将SalesText文件的数据导入。

  BULK INSERT Sales FROM 'FileServerD$SalesText.txt' WITH (FIELDTERMINATOR = ',')

  有时候,我们在执行导入操作以前,最好能先查看一下将要输入的数据。下面的语句在使用BULK命令时,使用了OPENROWSET函数,以便从SalesText文本文件中读取源数据。该语句同时还需要使用一个格式文件(此处没有列出文件的具体内容)来表明该文本文件中的数据格式。

  SELECT *
  FROM OPENROWSET(BULK 'c:SalesText.txt' ,
  FORMATFILE='C:SalesFormat.Xml'
  ) AS mytable;
  GO

 


 

posted @ 2008-05-14 10:00 重归本垒(Bing) 阅读(1737) | 评论 (0)编辑 收藏
 
一用我们的页面跳转都使用,window.location.reload()。
但在firefox,opera这样不行,替代使用window.location.href="";就可以了


---------------------------------------------------------------------
天行键,君子当自强不息
posted @ 2008-04-30 11:12 重归本垒(Bing) 阅读(5580) | 评论 (4)编辑 收藏
 

<select id="SelectEemployee" parameterClass="string" resultMap = "employee-result">

           select * from employee

//动态SQL语句

            <dynamic prepend="WHERE">

               <isParameterPresent>

                     emp_id = #value#

               </isParameterPresent>

            </dynamic>

       </select>

    </statements>

</sqlMap>     

/*动态SQL的写法:

开始 <dynamic

条件成立时前面要加的字符串 prepend ="字符串">

<属性关键字 (见下表)

prepend="字符串"

判断条件的对象属性名 property="字符串"

如果是属性关键字是比较条件时,字符串存放要比较的值compareValue="字符串">

要显示的条件名

</属性关键字>

结束</dynamic>

*/

/*动态SQL的参数有

属性关键字

含义

<isEqual>

如果参数相等于值则查询条件有效。

<isNotEqual>

如果参数不等于值则查询条件有效。

<isGreaterThan>

如果参数大于值则查询条件有效。

<isGreaterEqual>

如果参数等于值则查询条件有效。

<isLessEqual>

如果参数小于值则查询条件有效。如下所示:

<isLessEqual prepend = ”AND” property = ”age” compareValue = ”18” >

ADOLESCENT = ‘TRUE’

</isLessEqual>

<isPropertyAvailable>

如果参数有使用则查询条件有效。

<isNotPropertyAvailable>

如果参数没有使用则查询条件有效。

<isNull>

如果参数为NULL则查询条件有效。

<isNotNull>

如果参数不为NULL则查询条件有效。

<isEmpty>

如果参数为空则查询条件有效。

<isNotEmpty>

如果参数不为空则查询条件有效。参数的数据类型为CollectionString 时参数不为NULL或“”。如下所示:

<isNotEmpty prepend=”AND” property=”firstName” >

FIRST_NAME=#firstName#

</isNotEmpty>

<isParameterPresent>

如果参数类不为NULL则查询条件有效。

<isNotParameterPresent>

Checks to see if the parameter object is not present (null). Example Usage:

<isNotParameterPresent prepend=”AND”>

EMPLOYEE_TYPE = ‘DEFAULT’

</isNotParameterPresent>

 

posted @ 2008-04-17 11:30 重归本垒(Bing) 阅读(6410) | 评论 (4)编辑 收藏
 

JS提供两个截取字符串的方法,分别是:slice()和substring()
slice和substring都可以接受一个或两个参数,第1个参数是获取要截取的字符串的直始位置,第2个参数如果不为空则是获取要截取的字符串的结束位置的前一位(也就是说获取的终点位置不在返回值内),为空表示截取到整个字符串的最后一个字符。
我们来看下两种方法的用法
注意:字符串的位数都是从0开始
<script language="javascript">
var stmp = "rcinn.cn";
//使用一个参数
alert(stmp.slice(3));//从第4个字符开始,截取到最后个字符;返回"nn.cn"
alert(stmp.substring(3));//从第4个字符开始,截取到最后个字符;返回"nn.cn"
//使用两个参数
alert(stmp.slice(1,5))//从第2个字符开始,到第5个字符;返回"cinn"
alert(stmp.substring(1,5));//从第2个字符开始,到第5个字符;返回"cinn"
//如果只用一个参数并且为0的话,那么返回整个参数
alert(stmp.slice(0));//返回整个字符串
alert(stmp.substring(0));//返回整个字符串
//那如何只反回第一个字符呢,可以用其它的函数,那如果一定要用这两个方法的话就指定第一个参数为0,第二个参数为1,看下面的例子
alert(stmp.slice(0,1));//返回"r"
alert(stmp.substring(0,1));//返回"r"
//在上面的例子中我们可以看出slice()和substring()的用法是相同的,返回的值也是一样的,但当参数为负数时,他们的返回值却不一样,看下面的例子
alert(stmp.slice(2,-5));//返回"i"
alert(stmp.substring(2,-5));//返回"rc"
//从上面两个例子可以看出slice(2,-5)实际上是slice(2,3),负5转换成正3;而substring(2,-5)实际上是substring(2,0),负数转换为0,swubstring总是把最小的数作为起始位置。
</script>
本文转自可可在线(http://www.rcinn.cn),详细出处参考:http://www.rcinn.cn/news.asp?id=646

 

posted @ 2008-04-14 10:07 重归本垒(Bing) 阅读(19760) | 评论 (0)编辑 收藏
 
     摘要: //打开模式对话框 function doSelectUser(txtId) {       strFeatures="dialogWidth=500px;dialogHeight=360px;center=yes;middle=yes ;help=no;status=no;scroll=no";    ...  阅读全文
posted @ 2008-03-21 15:13 重归本垒(Bing) 阅读(845) | 评论 (0)编辑 收藏
 
目录:
1:js 字符串长度限制、判断字符长度 、js限制输入、限制不能输入、textarea 长度限制
2.:js判断汉字、判断是否汉字 、只能输入汉字
3:js判断是否输入英文、只能输入英文
4:js只能输入数字,判断数字、验证数字、检测数字、判断是否为数字、只能输入数字
5:只能输入英文字符和数字
6: js email验证 、js 判断email 、信箱/邮箱格式验证
7:js字符过滤,屏蔽关键字
8:js密码验证、判断密码
2.1: js 不为空、为空或不是对象 、判断为空 、判断不为空
2.2:比较两个表单项的值是否相同
2.3:表单只能为数字和"_",
2.4:表单项输入数值/长度限定
2.5:中文/英文/数字/邮件地址合法性判断
2.6:限定表单项不能输入的字符
2.7表单的自符控制
2.8:form文本域的通用校验函数

 

 

 

 

 

 

1. 长度限制
<script>
function test()
{
if(document.a.b.value.length>50)
{
alert("不能超过50个字符!");
document.a.b.focus();
return false;
}
}
</script>
<form name=a onsubmit="return test()">
<textarea name="b" cols="40" wrap="VIRTUAL" rows="6"></textarea>
<input type="submit" name="Submit" value="check">
</form>

2. 只能是汉字
<input onkeyup="value="/oblog/value.replace(/[^u4E00-u9FA5]/g,'')">

3." 只能是英文
<script language=javascript>
function onlyEng()
{
if(!(event.keyCode>=65&&event.keyCode<=90))
event.returnvalue=false;
}
</script>

<input onkeydown="onlyEng();">

4. 只能是数字
<script language=javascript>
function onlyNum()
{
if(!((event.keyCode>=48&&event.keyCode<=57)||(event.keyCode>=96&&event.keyCode<=105)))
//考虑小键盘上的数字键
event.returnvalue=false;
}
</script>

<input onkeydown="onlyNum();">

5. 只能是英文字符和数字
<input onkeyup="value="/oblog/value.replace(/[W]/g,"'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^d]/g,''))">

6. 验证油箱格式
<SCRIPT LANGUAGE=javascript RUNAT=Server>
function isEmail(strEmail) {
if (strEmail.search(/^w+((-w+)|(.w+))*@[A-Za-z0-9]+((.|-)[A-Za-z0-9]+)*.[A-Za-z0-9]+$/) != -1)
return true;
else
alert("oh");
}
</SCRIPT>
<input type=text onblur=isEmail(this.value)>

7. 屏蔽关键字(这里屏蔽***和****)
<script language="javascript1.2">
function test() {
if((a.b.value.indexOf ("***") == 0)||(a.b.value.indexOf ("****") == 0)){
alert(":)");
a.b.focus();
return false;}
}
</script>
<form name=a onsubmit="return test()">
<input type=text name=b>
<input type="submit" name="Submit" value="check">
</form>

8. 两次输入密码是否相同
<FORM METHOD=POST ACTION="">
<input type="password" id="input1">
<input type="password" id="input2">
<input type="button" value="test" onclick="check()">
</FORM>
<script>
function check()
{
with(document.all){
if(input1.value!=input2.value)
{
alert("false")
input1.value = "";
input2.value = "";
}
else document.forms[0].submit();
}
}
</script>
够了吧 :)
屏蔽右键 很酷
oncontextmenu="return false" ondragstart="return false" onselectstart="return false"
加在body中




2.1 表单项不能为空

<script language="javascript">
<!--
function CheckForm()
{
if (document.form.name.value.length == 0) {
alert("请输入您姓名!");
document.form.name.focus();
return false;
}
return true;
}
-->
</script>

2.2 比较两个表单项的值是否相同

<script language="javascript">
<!--
function CheckForm()
if (document.form.PWD.value != document.form.PWD_Again.value) {
alert("您两次输入的密码不一样!请重新输入.");
document.ADDUser.PWD.focus();
return false;
}
return true;
}
-->
</script>

2.3 表单项只能为数字和"_",用于电话/银行帐号验证上,可扩展到域名注册等

<script language="javascript">
<!--
function isNumber(String)
{
var Letters = "1234567890-"; //可以自己增加可输入值
var i;
var c;
if(String.charAt( 0 )=='-')
return false;
if( String.charAt( String.length - 1 ) == '-' )
return false;
for( i = 0; i < String.length; i ++ )
{
c = String.charAt( i );
if (Letters.indexOf( c ) < 0)
return false;
}
return true;
}
function CheckForm()
{
if(! isNumber(document.form.TEL.value)) {
alert("您的电话号码不合法!");
document.form.TEL.focus();
return false;
}
return true;
}
-->
</script>


2.4 表单项输入数值/长度限定

<script language="javascript">
<!--
function CheckForm()
{
if (document.form.count.value > 100 || document.form.count.value < 1)
{
alert("输入数值不能小于零大于100!");
document.form.count.focus();
return false;
}
if (document.form.MESSAGE.value.length<10)
{
alert("输入文字小于10!");
document.form.MESSAGE.focus();
return false;
}
return true;
}
//-->
</script>

2.5 中文/英文/数字/邮件地址合法性判断

<SCRIPT LANGUAGE="javascript">
<!--

function isEnglish(name) //英文值检测
{
if(name.length == 0)
return false;
for(i = 0; i < name.length; i++) {
if(name.charCodeAt(i) > 128)
return false;
}
return true;
}

function isChinese(name) //中文值检测
{
if(name.length == 0)
return false;
for(i = 0; i < name.length; i++) {
if(name.charCodeAt(i) > 128)
return true;
}
return false;
}

function isMail(name) // E-mail值检测
{
if(! isEnglish(name))
return false;
i = name.indexOf(" at ");
j = name dot lastIndexOf(" at ");
if(i == -1)
return false;
if(i != j)
return false;
if(i == name dot length)
return false;
return true;
}

function isNumber(name) //数值检测
{
if(name.length == 0)
return false;
for(i = 0; i < name.length; i++) {
if(name.charAt(i) < "0" || name.charAt(i) > "9")
return false;
}
return true;
}

function CheckForm()
{
if(! isMail(form.Email.value)) {
alert("您的电子邮件不合法!");
form.Email.focus();
return false;
}
if(! isEnglish(form.name.value)) {
alert("英文名不合法!");
form.name.focus();
return false;
}
if(! isChinese(form.cnname.value)) {
alert("中文名不合法!");
form.cnname.focus();
return false;
}
if(! isNumber(form.PublicZipCode.value)) {
alert("邮政编码不合法!");
form.PublicZipCode.focus();
return false;
}
return true;
}
//-->
</SCRIPT>

2.6 限定表单项不能输入的字符

<script language="javascript">
<!--

function contain(str,charset)// 字符串包含测试函数
{
var i;
for(i=0;i<charset.length;i++)
if(str.indexOf(charset.charAt(i))>=0)
return true;
return false;
}

function CheckForm()
{
if ((contain(document.form.NAME.value, "%()><")) || (contain(document.form.MESSAGE.value, "%()><")))
{
alert("输入了非法字符");
document.form.NAME.focus();
return false;
}
return true;
}
//-->
</script>

1. 检查一段字符串是否全由数字组成
---------------------------------------
<script language="Javascript"><!--
function checkNum(str){return str.match(/D/)==null}
alert(checkNum("1232142141"))
alert(checkNum("123214214a1"))
// --></script>

2. 怎么判断是否是字符
---------------------------------------
if (/[^x00-xff]/g.test(s)) alert("含有汉字");
else alert("全是字符");

3. 怎么判断是否含有汉字
---------------------------------------
if (escape(str).indexOf("%u")!=-1) alert("含有汉字");
else alert("全是字符");

4. 邮箱格式验证
---------------------------------------
//函数名:chkemail
//功能介绍:检查是否为Email Address
//参数说明:要检查的字符串
//返回值:0:不是 1:是
function chkemail(a)
{ var i=a.length;
var temp = a.indexOf('@');
var tempd = a.indexOf('.');
if (temp > 1) {
if ((i-temp) > 3){
if ((i-tempd)>0){
return 1;
}

}
}
return 0;
}

5. 数字格式验证
---------------------------------------
//函数名:fucCheckNUM
//功能介绍:检查是否为数字
//参数说明:要检查的数字
//返回值:1为是数字,0为不是数字
function fucCheckNUM(NUM)
{
var i,j,strTemp;
strTemp="0123456789";
if ( NUM.length== 0)
return 0
for (i=0;i<NUM.length;i++)
{
j=strTemp.indexOf(NUM.charAt(i));
if (j==-1)
{
//说明有字符不是数字
return 0;
}
}
//说明是数字
return 1;
}

6. 电话号码格式验证
---------------------------------------
//函数名:fucCheckTEL
//功能介绍:检查是否为电话号码
//参数说明:要检查的字符串
//返回值:1为是合法,0为不合法
function fucCheckTEL(TEL)
{
var i,j,strTemp;
strTemp="0123456789-()# ";
for (i=0;i<TEL.length;i++)
{
j=strTemp.indexOf(TEL.charAt(i));
if (j==-1)
{
//说明有字符不合法
return 0;
}
}
//说明合法
return 1;
}

7. 判断输入是否为中文的函数
---------------------------------------
function ischinese(s){
var ret=true;
for(var i=0;i<s.length;i++)
ret=ret && (s.charCodeAt(i)>=10000);
return ret;
}

8. 综合的判断用户输入的合法性的函数
---------------------------------------
<script language="javascript">
//限制输入字符的位数开始
//m是用户输入,n是要限制的位数
function issmall(m,n)
{
if ((m<n) && (m>0))
{
return(false);
}
else
{return(true);}
}

9. 判断密码是否输入一致
---------------------------------------
function issame(str1,str2)
{
if (str1==str2)
{return(true);}
else
{return(false);}
}

10. 判断用户名是否为数字字母下滑线
---------------------------------------
function notchinese(str){
var reg=/[^A-Za-z0-9_]/g
if (reg.test(str)){
return (false);
}else{
return(true); }
}

2.8. form文本域的通用校验函数
---------------------------------------
作用:检测所有必须非空的input文本,比如姓名,账号,邮件地址等等。
该校验现在只针对文本域,如果要针对form里面的其他域对象,可以改变判断条件。

使用方法:在要检测的文本域中加入title文字。文字是在提示信息,你要提示给用户的该字段的中文名。比如要检测用户名
html如下<input name="txt_1" title="姓名">,当然,最好用可视化工具比如dreamweaver什么的来编辑域。
如果要检测数字类型数据的话,再把域的id统一为sz.
javascript判断日期类型比较麻烦,所以就没有做日期类型校验的程序了.高手可以补充。

程序比较草,只是提供一个思路。抛砖引玉! :)
哦,对了,函数调用方法:< form onsubmit="return dovalidate()">

function dovalidate()
{
fm=document.forms[0] //只检测一个form,如果是多个可以改变判断条件
for(i=0;i<fm.length;i++)
{
//检测判断条件,根据类型不同可以修改
if(fm[i].tagName.toUpperCase()=="INPUT" &&fm[i].type.toUpperCase()=="TEXT" && (fm[i].title!=""))

if(fm[i].value="/blog/="")//
{
str_warn1=fm[i].title+"不能为空!";
alert(str_warn1);
fm[i].focus();
return false;
}
if(fm[i].id.toUpperCase()=="SZ")//数字校验
{
if(isNaN(fm[i].value))
{ str_warn2=fm[i].title+"格式不对";
alert(str_warn2);
fm[i].focus();
return false;
}
}
}
return true;
}

只能是汉字<input onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')">   只能是英文字母<script language=javascript>
function onlyEng()
{
if(!(event.keyCode>=65&&event.keyCode<=90))
    event.returnValue=false;
}
</script>

<input onkeydown="onlyEng();">   只能是数字 <script language=javascript>
function onlyNum()
{
if(!((event.keyCode>=48&&event.keyCode<=57)||(event.keyCode>=96&&event.keyCode<=105)))
//考虑小键盘上的数字键
    event.returnValue=false;
}
</script>

<input onkeydown="onlyNum();"> 只能是英文字母和数字<SCRIPT LANGUAGE=Javascript RUNAT=Server>
function isEmail(strEmail) {
if (strEmail.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) != -1)
return true;
else
alert("oh");
}
</SCRIPT>
<input type=text onblur=isEmail(this.value)>   验证EMAIL格式<script language="JavaScript1.2">
function test() {
if((a.b.value.indexOf ("sex") == 0)||(a.b.value.indexOf ("fuck") == 0)){
    alert("五讲四美三热爱");
    a.b.focus();
    return false;}
}
</script>
<form name=a onsubmit="return test()">
<input type=text name=b>
<input type="submit" name="Submit" value="check">
</form>

posted @ 2008-03-21 14:23 重归本垒(Bing) 阅读(2183) | 评论 (0)编辑 收藏
 
取值要通过<s:property value="" />或在任意的<s:/>标签内使用%{};

当Action的valueStack中有该属性的值时,只需直接使用该属性的名字即可;

当Action的valueStack中没有该属性的值时,比如在session,application范围中的属性值时,需要加#或者#attr.;

例子:
假设某Action中有person成员变量,在application中存在company属性
那么我们可以通过以下方法取值:
<s:property value="person.name" />
<s:property value="#person.name" />
<s:property value="company.name" /> //无法取到,因为company不在action的valueStack中
<s:property value="#company.name" />

<s:textfield name="person.name" value="person.name" /> //错误,value会直接显示person.name字样
<s:textfield name="person.name" value="%{person.name}" />
<s:textfield name="person.company.name" value="%{#company.name}" />
<s:textfield name="person.company.name" value="%{#attr.company.name}" />
posted @ 2008-03-20 18:16 重归本垒(Bing) 阅读(3668) | 评论 (0)编辑 收藏
 
Truncate是SQL中的一个删除数据表内容的语句,用法是:
TRUNCATE TABLE [Table Name]。
   下面是对Truncate语句在MSSQLServer2000中用法和原理的说明:
Truncate table 表名 速度快,而且效率高,因为:
TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。
DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
TRUNCATE TABLE 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用的计数值重置为该列的种子。如果想保留标识计数值,请改用 DELETE。如果要删除表定义及其数据,请使用 DROP TABLE 语句。
对于由 FOREIGN KEY 约束引用的表,不能使用 TRUNCATE TABLE,而应使用不带 WHERE 子句的 DELETE 语句。由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。
TRUNCATE TABLE 不能用于参与了索引视图的表。
posted @ 2008-03-11 18:16 重归本垒(Bing) 阅读(1135) | 评论 (0)编辑 收藏
 
LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE]
    INTO TABLE tbl_name
    [FIELDS
        [TERMINATED BY '\t']
        [OPTIONALLY] ENCLOSED BY '']
        [ESCAPED BY '\\' ]]
    [LINES TERMINATED BY '\n']
    [IGNORE number LINES]
    [(col_name,...)]

LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中。如果指定LOCAL关键词,从客户主机读文件。如果LOCAL没指定,文件必须位于服务器上。(LOCAL在MySQL3.22.6或以后版本中可用。)

为了安全原因,当读取位于服务器上的文本文件时,文件必须处于数据库目录或可被所有人读取。另外,为了对服务器上文件使用LOAD DATA INFILE,在服务器主机上你必须有file的权限。见6.5 由MySQL提供的权限。

如果你指定关键词LOW_PRIORITY,LOAD DATA语句的执行被推迟到没有其他客户读取表后。

使用LOCAL将比让服务器直接存取文件慢些,因为文件的内容必须从客户主机传送到服务器主机。在另一方面,你不需要file权限装载本地文件。

你也可以使用mysqlimport实用程序装载数据文件;它由发送一个LOAD DATA INFILE命令到服务器来运作。 --local选项使得mysqlimport从客户主机上读取数据。如果客户和服务器支持压缩协议,你能指定--compress在较慢的网络上获得更好的性能。

当在服务器主机上寻找文件时,服务器使用下列规则:

如果给出一个绝对路径名,服务器使用该路径名。
如果给出一个有一个或多个前置部件的相对路径名,服务器相对服务器的数据目录搜索文件。
如果给出一个没有前置部件的一个文件名,服务器在当前数据库的数据库目录寻找文件。
注意这些规则意味着一个像“./myfile.txt”给出的文件是从服务器的数据目录读取,而作为“myfile.txt”给出的一个文件是从当前数据库的数据库目录下读取。也要注意,对于下列哪些语句,对db1文件从数据库目录读取,而不是db2:

mysql> USE db1;
mysql> LOAD DATA INFILE "./data.txt" INTO TABLE db2.my_table;

REPLACE和IGNORE关键词控制对现有的唯一键记录的重复的处理。如果你指定REPLACE,新行将代替有相同的唯一键值的现有行。如果你指定IGNORE,跳过有唯一键的现有行的重复行的输入。如果你不指定任何一个选项,当找到重复键键时,出现一个错误,并且文本文件的余下部分被忽略时。

如果你使用LOCAL关键词从一个本地文件装载数据,服务器没有办法在操作的当中停止文件的传输,因此缺省的行为好像IGNORE被指定一样。

LOAD DATA INFILE是SELECT ... INTO OUTFILE的逆操作,
SELECT句法。为了将一个数据库的数据写入一个文件,使用SELECT ... INTO OUTFILE,为了将文件读回数据库,使用LOAD DATA INFILE。两个命令的FIELDS和LINES子句的语法是相同的。两个子句是可选的,但是如果指定两个,FIELDS必须在LINES之前。

如果你指定一个FIELDS子句,它的每一个子句(TERMINATED BY, [OPTIONALLY] ENCLOSED BY和ESCAPED BY)也是可选的,除了你必须至少指定他们之一。

如果你不指定一个FIELDS子句,缺省值与如果你这样写的相同:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'

如果你不指定一个LINES子句,缺省值与如果你这样写的相同:

LINES TERMINATED BY '\n'
换句话说,缺省值导致读取输入时,LOAD DATA INFILE表现如下:

在换行符处寻找行边界
在定位符处将行分进字段
不要期望字段由任何引号字符封装
将由“\”开头的定位符、换行符或“\”解释是字段值的部分字面字符
相反,缺省值导致在写入输出时,SELECT ... INTO OUTFILE表现如下:

在字段之间写定位符
不用任何引号字符封装字段
使用“\”转义出现在字段中的定位符、换行符或“\”字符
在行尾处写换行符
注意,为了写入FIELDS ESCAPED BY '\\',对作为一条单个的反斜线被读取的值,你必须指定2条反斜线值。

IGNORE number LINES选项可被用来忽略在文件开始的一个列名字的头:

mysql> LOAD DATA INFILE "/tmp/file_name" into table test IGNORE 1 LINES;

当你与LOAD DATA INFILE一起使用SELECT ... INTO OUTFILE将一个数据库的数据写进一个文件并且随后马上将文件读回数据库时,两个命令的字段和处理选项必须匹配,否则,LOAD DATA INFILE将不能正确解释文件的内容。假定你使用SELECT ... INTO OUTFILE将由逗号分隔的字段写入一个文件:

mysql> SELECT * FROM table1 INTO OUTFILE 'data.txt'
           FIELDS TERMINATED BY ','
           FROM ...

为了将由逗号分隔的文件读回来,正确的语句将是:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
           FIELDS TERMINATED BY ',';

相反,如果你试图用下面显示的语句读取文件,它不会工作,因为它命令LOAD DATA INFILE在字段之间寻找定位符:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
           FIELDS TERMINATED BY '\t';

可能的结果是每个输入行将被解释为单个的字段。

LOAD DATA INFILE能被用来读取从外部来源获得的文件。例如,以dBASE格式的文件将有由逗号分隔并用双引号包围的字段。如果文件中的行由换行符终止,下面显示的命令说明你将用来装载文件的字段和行处理选项:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
           FIELDS TERMINATED BY ',' ENCLOSED BY '"'
           LINES TERMINATED BY '\n';

任何字段或行处理选项可以指定一个空字符串('')。如果不是空,FIELDS [OPTIONALLY] ENCLOSED BY和FIELDS ESCAPED BY值必须是一个单个字符。FIELDS TERMINATED BY和LINES TERMINATED BY值可以是超过一个字符。例如,写入由回车换行符对(CR+LF)终止的行,或读取包含这样行的一个文件,指定一个LINES TERMINATED BY '\r\n'子句。

FIELDS [OPTIONALLY] ENCLOSED BY控制字段的包围字符。对于输出(SELECT ... INTO OUTFILE),如果你省略OPTIONALLY,所有的字段由ENCLOSED BY字符包围。对于这样的输出的一个例子(使用一个逗号作为字段分隔符)显示在下面:

"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"

如果你指定OPTIONALLY,ENCLOSED BY字符仅被用于包围CHAR和VARCHAR字段:

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20

注意,一个字段值中的ENCLOSED BY字符的出现通过用ESCAPED BY字符作为其前缀来转义。也要注意,如果你指定一个空ESCAPED BY值,可能产生不能被LOAD DATA INFILE正确读出的输出。例如,如果转义字符为空,上面显示的输出显示如下。注意到在第四行的第二个字段包含跟随引号的一个逗号,它(错误地)好象要终止字段:

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20

对于输入,ENCLOSED BY字符如果存在,它从字段值的尾部被剥去。(不管是否指定OPTIONALLY都是这样;OPTIONALLY对于输入解释不起作用)由ENCLOSED BY字符领先的ESCAPED BY字符出现被解释为当前字段值的一部分。另外,出现在字段中重复的ENCLOSED BY被解释为单个ENCLOSED BY字符,如果字段本身以该字符开始。例如,如果ENCLOSED BY '"'被指定,引号如下处理:

"The ""BIG"" boss"  -> The "BIG" boss
The "BIG" boss      -> The "BIG" boss
The ""BIG"" boss    -> The ""BIG"" boss

FIELDS ESCAPED BY控制如何写入或读出特殊字符。如果FIELDS ESCAPED BY字符不是空的,它被用于前缀在输出上的下列字符:

FIELDS ESCAPED BY字符
FIELDS [OPTIONALLY] ENCLOSED BY字符
FIELDS TERMINATED BY和LINES TERMINATED BY值的第一个字符
ASCII 0(实际上将后续转义字符写成 ASCII'0',而不是一个零值字节)
如果FIELDS ESCAPED BY字符是空的,没有字符被转义。指定一个空转义字符可能不是一个好主意,特别是如果在你数据中的字段值包含刚才给出的表中的任何字符。

对于输入,如果FIELDS ESCAPED BY字符不是空的,该字符的出现被剥去并且后续字符在字面上作为字段值的一个部分。例外是一个转义的“0”或“N”(即,\0或\N,如果转义字符是“\”)。这些序列被解释为ASCII 0(一个零值字节)和NULL。见下面关于NULL处理的规则。

对于更多关于“\”- 转义句法的信息,在某些情况下,字段和行处理选项相互作用:

如果LINES TERMINATED BY是一个空字符串并且FIELDS TERMINATED BY是非空的,行也用FIELDS TERMINATED BY终止。
如果FIELDS TERMINATED BY和FIELDS ENCLOSED BY值都是空的(''),一个固定行(非限定的)格式被使用。用固定行格式,在字段之间不使用分隔符。相反,列值只用列的“显示”宽度被写入和读出。例如,如果列被声明为INT(7),列的值使用7个字符的字段被写入。对于输入,列值通过读取7个字符获得。固定行格式也影响NULL值的处理;见下面。注意如果你正在使用一个多字节字符集,固定长度格式将不工作。
NULL值的处理有多种,取决于你使用的FIELDS和LINES选项:

对于缺省FIELDS和LINES值,对输出,NULL被写成\N,对输入,\N被作为NULL读入(假定ESCAPED BY字符是“\”)。
如果FIELDS ENCLOSED BY不是空的,包含以文字词的NULL作为它的值的字段作为一个NULL值被读入(这不同于包围在FIELDS ENCLOSED BY字符中的字NULL,它作为字符串'NULL'读入)。
如果FIELDS ESCAPED BY是空的,NULL作为字NULL被写入。
用固定行格式(它发生在FIELDS TERMINATED BY和FIELDS ENCLOSED BY都是空的时候),NULL作为一个空字符串被写入。注意,在写入文件时,这导致NULL和空字符串在表中不能区分,因为他们都作为空字符串被写入。如果在读回文件时需要能区分这两者,你应该不使用固定行格式。
一些不被LOAD DATA INFILE支持的情况:

固定长度的行(FIELDS TERMINATED BY和FIELDS ENCLOSED BY都为空)和BLOB或TEXT列。
如果你指定一个分隔符与另一个相同,或是另一个的前缀,LOAD DATA INFILE不能正确地解释输入。例如,下列FIELDS子句将导致问题:
FIELDS TERMINATED BY '"' ENCLOSED BY '"'

如果FIELDS ESCAPED BY是空的,一个包含跟随FIELDS TERMINATED BY值之后的FIELDS ENCLOSED BY或LINES TERMINATED BY的字段值将使得LOAD DATA INFILE过早地终止读取一个字段或行。这是因为LOAD DATA INFILE不能正确地决定字段或行值在哪儿结束。
下列例子装载所有persondata表的行:

mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;

没有指定字段表,所以LOAD DATA INFILE期望输入行对每个表列包含一个字段。使用缺省FIELDS和LINES值。

如果你希望仅仅装载一张表的某些列,指定一个字段表:

mysql> LOAD DATA INFILE 'persondata.txt'
           INTO TABLE persondata (col1,col2,...);

如果在输入文件中的字段顺序不同于表中列的顺序,你也必须指定一个字段表。否则,MySQL不能知道如何匹配输入字段和表中的列。

如果一个行有很少的字段,对于不存在输入字段的列被设置为缺省值。

如果字段值缺省,空字段值有不同的解释:

对于字符串类型,列被设置为空字符串。
对于数字类型,列被设置为0。
对于日期和时间类型,列被设置为该类型的适当“零”值。
如果列有一个NULL,或(只对第一个TIMESTAMP列)在指定一个字段表时,如果TIMESTAMP列从字段表省掉,TIMESTAMP列只被设置为当前的日期和时间。

如果输入行有太多的字段,多余的字段被忽略并且警告数字加1。

LOAD DATA INFILE认为所有的输入是字符串,因此你不能像你能用INSERT语句的ENUM或SET列的方式使用数字值。所有的ENUM和SET值必须作为字符串被指定!

如果你正在使用C API,当LOAD DATA INFILE查询完成时,你可通过调用API函数mysql_info()得到有关查询的信息。信息字符串的格式显示在下面:

Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
当值通过INSERT语句插入时,在某些情况下出现警告,除了在输入行中有太少或太多的字段时,LOAD DATA INFILE也产生警告。警告没被存储在任何地方;警告数字仅能用于表明一切是否顺利。如果你得到警告并且想要确切知道你为什么得到他们,一个方法是使用SELECT ... INTO OUTFILE到另外一个文件并且把它与你的原版输入文件比较。

 

posted @ 2008-03-11 18:12 重归本垒(Bing) 阅读(471) | 评论 (0)编辑 收藏
 

    一、SOA是指面向服务的体系结构(service-oriented architecture),他代表了包括web技术在内的软件程序甚至硬件技术的一个发展方向,相对于错综复杂、标准各异的硬件平台、操作系统和编程语言,SOA提供尽可能中立而有效的接口,以实现任务、服务之间的对话,直接降低了商业信息系统的沟通成本。

    二、SOA更加接近比尔·盖茨“信息就在你指尖”的愿景,继互联网打破信息和数据流动的壁垒之后,致力于打破软件程序在不同商业组织现有的机构系统之间进行无缝衔接的障碍,而IBM、RACLE等巨人定制的SOA国际标准SCA已经为此构造出简单性的底层技术标准基础。

    三、原则上所有异构的信息系统都存在无缝衔接的内在需求。传统的搜索引擎系统就是一种典型的封闭结构,没有真正无缝的外部接口。伯纳斯·李所推动的语义网和web化的SOA在本质上一致,很好的结合起来双方力量可以倍增,语义网属于从网络底层推动“无缝衔接”的努力, 但是在这一技术方面的努力之外,还应该涌现出更多在人性、用户方面推动SOA的努力。

    四、SOA改变了软件的概念。软件原来传统的底层部分被改造为真正工具性的事物,而广义化的软件概念中“服务和任务”成为核心;软件不再是组件、单元、数据库等的加和,而是对于任务和服务的回应,因此服务之间的松耦合异常重要和活跃。随着概念的改变,软件业将重新洗牌。竞争规则改变很大,程序、代码、结构次要化,数据、任务、外部接口更加重要,文本数据可能成为以后SOA的主要对象。 

    五、SOA侧重提供与不同任务的标准化服务接口,其水平高低应该取决于双方的可理解性、可分解性、可交互和互动性。从代码和数据,到结构的技术升级,将进行新的升级,以结构升级入手,寻找比结构更重要的,诸如函数调用、数据响应、结构自适应等。其中,最大的难点应该是互动如何改变参与者的状态,这也是最刺激的地方。

    六、SOA作为第三代软件架构标准,如果与web和3G结合,将大大拓展软件行业的空间,软件可以拥有自己的渠道了,软件加强了自身的力量。

    七、SOA真正付诸实施不是一两家商业力量的事情,他属于一项社会化的技术就年百微工程,需要整合大量的资源,需要有坚强的平台,需要建立商业力量和社会力量的共同利基,需要寻找现实和未来的平衡点。SOA的价值目前主要还是在理念方面,可以触类旁通的引用到很多其他技术领域;SOA让信息和技术更加自由、开放、共享,可以盘活更多的商业数据和技术资源,产生新的价值。同时,SOA需要做出大量的垂直标准,不同领域的差异性可能比较大,虽然他们具有共同的SCA底层。

    八、SOA是商业信息系统的现有资源为基础提供低门槛的接口升级方案,让客户之间的商业沟通更加自由灵活,同时降低面对变化的任务和服务的沟通对话成本,这一目标是通过基于服务和任务的思维和文化理念层次的结构调整实现的,超越了仅仅基于技术和运用的结构调整方案。

posted @ 2007-11-20 10:04 重归本垒(Bing) 阅读(340) | 评论 (1)编辑 收藏
 
1. 我和超人的唯一区别是:我把内裤穿在里面. 
2. 我不是随便的人, 但随便了起来就不是人了. 
3. 我身在江湖, 江湖却没有我的传说. 
4. 走别人的路, 让别人无路可走. 
5. 穿别人的鞋, 走自己的路, 让他们找去吧. 
6. 走NB的路, 让SB说去吧. 
7. 听说女人如衣服, 兄弟如手足. 回想起来, 我竟然七手八脚的裸奔了19年. 
8. 宁愿相信世间有鬼, 也不相信男人那张嘴. 
9. 水至清则无鱼, 人至贱则无敌. 
10. 树不要皮, 必死无疑. 人不要脸, 天下无敌. 
11. 一山不能容二虎, 除非一公一母. 
12. 对流血一周仍然不死的动物千万不能大意. 
13. 我, 一个大学生的人生目标:农妇, 山泉, 有点田. 
14. 女人谨记:一定要吃好玩好睡好喝好. 一旦累死了, 就别的女人花咱的钱, 住咱的房子, 睡咱的老公, 泡咱的男朋友, 还打咱的娃. 
15. 有一天, 我梦见自己的钱花光了, 醒来一看, 口袋真的空空的. 
16. 我减肥已取得了很大的成功, 你看, 我三个下巴都尖了. 
17. 千万别等到人人都说你丑的时候才发现自己真的丑. 
18. 如果朋友可以出卖, 每个值五元的话, 我也能发笔小财了. 
19. 肚子大不可怕, 可怕的是大而无料. 
20. 女人先表现自己大方, 男人就不敢小气了. 
21. 人, 生在床上, 死在床上, 欲生欲死, 也在床上. 
22. 巫师, 请转告公主, 老子还在披荆斩刺的路上, 还有雪山未翻, 大河未过, 巨龙未杀, 美女未泡. 叫她继续死睡吧. 
23. 无所为而无所谓, 无所谓而无所不为. 
24. 铁饭碗的真正含义不是在一个地方有饭吃, 而是一辈子到哪儿都有饭吃. 
25. 骚归骚, 骚有骚的贞操. 贱归贱, 贱有贱的尊严. 
26. 人生的成功不在于拿到一副好牌, 而是怎样将坏牌打好. 
27. 0岁出场亮相, 10岁天天向上, 20岁远大理想, 30岁发奋图墙, 40岁基本定向, 50岁处处吃香, 60岁打打麻将, 70岁处处闲逛, 80岁拉拉家常, 90岁挂在墙上. 
28. 再过几十年, 我们都来相会, 送到火葬场, 全部烧成灰, 你一堆, 我一堆, 谁也不认识谁, 全部送到农村做化肥. 
29. 自从我变成了狗屎, 就再也没有人踩在我头上了. 
30. 路边的野花不要, 踩. 
31. 也许似乎大概是, 然而未必不见得. 
32. 说过的话可以不算, 喜欢的人天天要换. 
33. 本人中科院高级潜水院院士, 诺贝尔长期掉线奖, 奥斯卡终身隐身奖. 
34. 你放心, 看到你我连食欲都没有了, 还谈什么性欲. 
35. 生活真他妈好玩, 因为生活老他妈玩我. 
36. 佛曰:"前世的500次回眸才换来今生的一次擦肩而过." 我宁愿用来世的一次擦肩而过换得今生的500次回眸. 
37. 黑夜给了我一双黑色的眼睛, 可我却用它来翻白眼. 
38. 我想早恋, 但是已经晚了. 
39. 天啊, 我的衣服又瘦了. 
40. 这个世界上我只相信两个人, 一个是我, 一个不是你. 
41. 思想有多远, 你就给我滚多远. 
42. 流氓不可怕, 就怕流氓有文化. 
43. 客官请自重, 小女子只卖身不卖艺. 
44. 男人的谎言可以骗女人一夜, 女人的谎言可以骗男人一辈子. 
45. 如果不能给你的女人幸福, 请停下你解开她衣扣的手. 
46. 如果不能给你的女人穿上嫁衣, 那么千万别停下你解开她衣扣的手. 
47. 水能载舟, 亦能煮粥. 
48. 开车无难事, 只怕有新人. 
49. 一见钟情, 再而衰, 三而竭. 
50. 生, 容易. 活, 容易. 生活不容易. 
51. 如果我能看到我的背影, 我想它一定很忧伤, 因为我把快乐都留在了前面. 
52. 出问题先从自己身上找原因, 别一便秘就怪地球引力不够. 
53. 给我织一条围巾, 我愿以一生关怀相报. 否则, 你就用围巾勒死我吧. 
54. 男人在不懂的时候装懂, 女人则恰好相反. 
55. 春色满园关不住, 我拉红杏出墙来. 
56. 你以为我会眼睁睁看着你去送死吗? 我会闭上眼睛的. -_-
57. 我以为我很颓废, 今天我才知道, 原来我早报废了. 
58. 我视金钱如粪土, 我爸视我为粪池. 
59. 我喝酒想把痛苦溺死, 但这该死的痛苦却学会了游泳. 
60. 我是你的风筝, 线在你手上, 可陪伴我的只有风. 
61. 别人都在假装正经, 那我就只有假装不正经了.
posted @ 2007-11-05 10:54 重归本垒(Bing) 阅读(509) | 评论 (0)编辑 收藏
 

1:人的一生有三情:亲情、友情、爱情,缺其一者,是为遗憾;失其二者,是为可怜;失其三者,枉活一生。

2:来如流水兮逝如风,飘飘入世,如水之不得不流,不知何故来也不知何所终。

3:水至清则无鱼,人至察则无徒。

4:难得糊涂。

5:存在的就是合理的。

6朋友是历史性、阶段性的。而唯有知己,是一辈子的

posted @ 2007-11-05 10:41 重归本垒(Bing) 阅读(310) | 评论 (0)编辑 收藏
 

1、彼得原理
   每个组织都是由各种不同的职位、等级或阶层的排列所组成,每个人都隶属于其中的某个等级。彼得原理是美国学者劳伦斯·彼得在对组织中人员晋升的相关现象研究后,得出一个结论:在各种组织中,雇员总是趋向于晋升到其不称职的地位。彼得原理有时也被称为向上爬的原理。 这种现象在现实生活中无处不在:一名称职的教授被提升为大学校长后,却无法胜任;一个优秀的运动员被提升为主管体育的官员,而无所作为。对一个组织而言,一旦相当部分人员被推到其不称职的级别,就会造成组织的人浮于事,效率低下,导致平庸者出人头地,发展停滞。
2、酒与污水定律
   酒与污水定律是指把一匙酒倒进一桶污水,得到的是一桶污水;如果把一匙污水倒进一桶酒,得到的还是一桶污水。在任何组织里,几乎都存在几个难弄的人物,他们存在的目的似乎就是为了把事情搞糟。最糟糕的是,他们像果箱里的烂苹果,如果不及时处理,它会迅速传染,把果箱里其他苹果也弄烂。 烂苹果的可怕之处,在于它那惊人的破坏力。一个正直能干的人进入一个混乱的部门可能会被吞没,而一个无德无才者能很快将一个高效的部门变成一盘散沙。组织系统往往是脆弱的,是建立在相互理解、妥协和容忍的基础上的,很容易被侵害、被毒化。破坏者能力非凡的另一个重要原因在于,破坏总比建设容易。一个能工巧匠花费时日精心制作的陶瓷器,一头驴子一秒钟就能毁坏掉。如果一个组织里有这样的一头驴子,即使拥有再多的能工巧匠,也不会有多少像样的工作成果。如果你的组织里有这样的一头驴子,你应该马上把它清除掉,如果你无力这样做,就应该把它拴起来。
3、木桶定律
   水桶定律是讲一只水桶能装多少水,这完全取决于它最短的那块木板。这就是说任何一个组织,可能面临的一个共同问题,即构成组织的各个部分往往是优劣不齐的,而劣势部分往往决定整个组织的水平。水桶定律与酒与污水定律不同,后者讨论的是组织中的破坏力量,最短的木板却是组织中有用的一个部分,只不过比其他部分差一些,你不能把它们当成烂苹果扔掉。强弱只是相对而言的,无法消除,问题在于你容忍这种弱点到什么程度,如果严重到成为阻碍工作的瓶颈,你就不得不有所动作。
4、马太效应
   《新约·马太福音》中有这样一个故事:一个国王远行前,交给3个仆人每人一锭银子,吩咐道:你们去做生意,等我回来时,再来见我。国王回来时,第一个仆人说:主人,你交给我的一锭银子,我已赚了10锭。于是,国王奖励他10座城邑。第二个仆人报告:主人,你给我的一锭银子,我已赚了5锭。于是,国王奖励他5座城邑。第三仆人报告说:主人,你给我的1锭银子,我一直包在手帕里,怕丢失,一直没有拿出来。于是,国王命令将第三个仆人的1锭银子赏给第一个仆人,说:凡是少的,就连他所有的,也要夺过来。凡是多的,还要给他,叫他多多益善,这就是马太效应,反应当今社会中存在的一个普遍现象,即赢家通吃。对企业经营发展而言,马太效应告诉我们,要想在某一个领域保持优势,就必须在此领域迅速做大。当你成为某个领域的领头羊时,即便投资回报率相同,你也能更轻易地获得比弱小的同行更大的收益。而若没有实力迅速在某个领域做大,就要不停地寻找新的发展领域,才能保证获得较好的回报。
5、零和游戏原理
   零和游戏是指一项游戏中,游戏者有输有赢,一方所赢正是另一方所输,游戏的总成绩永远为零,零和游戏原理之所以广受关注,主要是因为人们在社会的方方面面都能发现与零和游戏类似的局面,胜利者的光荣后面往往隐藏着失败者的辛酸和苦涩。 20世纪,人类经历两次世界大战、经济高速增长,科技进步、全球一体化以及日益严重的环境污染,零和游戏观念正逐渐被双赢观念所取代。人们开始认识到利已不一定要建立在损人的基础上。通过有效合作皆大欢喜的结局是可能出现的。但从零和游戏走向双赢,要求各方面要有真诚合作的精神和勇气,在合作中不要小聪明,不要总想占别人的小便宜,要遵守游戏规则,否则双赢的局面就不可能出现,最终吃亏的还是合作者自己。
6、华盛顿合作规律
   华盛顿合作规律说的是一个人敷衍了事,两个人互相推诿,三个人则永无成事之日。多少有点类似于我们三个和尚的故事。人与人的合作,不是人力的简单相加,而是要复杂和微妙得多。在这种合作中,假定每个人的能力都为1,那么,10个人的合作结果有时比10大得多,有时,甚至比1还要小。因为人不是静止物,而更像方向各异的能量,相互推动时,自然事半功倍,相互抵触时,则一事无成。 我们传统的管理理论中,对合作研究得并不多,最直观的反映就是,目前的大多数管理制度和行为都是致力于减少人力的无谓消耗,而非利用组织提高人的效能。换言之,不妨说管理的主要目的不是让每个人做得更好,而是避免内耗过多。
7、手表定理 
    手表定理是指一个人有一只表时,可以知道现在是几点钟,当他同时拥有两只表时,却无法确定。两只手表并不能告诉一个人更准确的时间,反而会让看表的人失去对准确时间的信心。手表定理在企业经营管理方面,给我们一种非常直观的启发,就是对同一个人或同一个组织的管理,不能同时采用两种不同的方法,不能同时设置两个不同的目标,甚至每一个人不能由两个人同时指挥,否则将使这个企业或这个人无所适从。手表定理所指的另一层含义在于,每个人都不能同时选择两种不同的价值观,否则,你的行为将陷于混乱。
8、不值得定律
    不值得定律最直观的表述是:不值得做的的事情,就不值得做好。这个定律再简单不过了,重要性却时时被人们忽视遗忘。不值得定律反映人们的一种心理,一个人如果从事的是一份自认为不值得做的事情,往往会保持冷嘲热讽,敷衍了事的态度,不仅成功率低,而且即使成功,也不觉得有多大的成就感。 因此,对个人来说,应在多种可供选择的奋斗目标及价值观中挑选一种,然后为之奋斗。选择你所爱的,爱你所选择的,才可能激发我们的斗志,也可以心安理得。而对一个企业或组织来说,则要很好地分析员工的性格特性,合理分配工作,如让成就欲较强的职工单独或牵头完成具有一定风险和难度的工作,并在其完成时,给予及时的肯定和赞扬;让依附欲较强的职工,更多地参加到某个团体共同工作;让权力欲较强的职工,担任一个与之能力相适应的主管。同时要加强员工对企业目标的认同感,让员工感觉到自己所做的工作是值得的,这样才能激发职工的热情。
9 、蘑菇管理
    蘑菇管理是许多组织对待初出茅庐者的一种管理方法,初学者被置于阴暗的角落(不受重视的部门,或打杂跑腿的工作),浇上一头大粪(无端的批评、指责、代人受过),任其自生自灭(得不到必要的指导和提携)。相信很多人都有过这样一段蘑菇的经历,这不一定是什么坏事,尤其是当一切刚刚开始的时候,当几天蘑菇,能够消除我们很多不切实际的幻想,让我们更加接近现实,看问题也更加实际。一个组织,一般对新进的人员都是一视同仁,从起薪到工作都不会有大的差别。无论你是多么优秀的人才,在刚开始的时候,都只能从最简单的事情做起,蘑菇的经历,对于成长中的年轻人来说,就象蚕茧,是羽化前必须经历的一步。所以,如何高效率地走过生命的这一段,从中尽可能汲取经验,成熟起来,并树立良好的值得信赖的个人形象,是每个刚入社会的年轻人必须面对的课题。
10、奥卡姆剃刀定律
     12世纪,英国奥卡姆的威廉主张唯名论,只承认确实存在的东西,认为那些空洞无物的普遍性概念都是无用的累赘,应当被无情地剃除。他主张如无必要,勿增实体。这就是常说的奥卡姆剃刀。这把剃刀曾使很多人感到威胁,被认为是异端邪说,威廉本人也因此受到迫害。然而,并未损害这把刀的锋利,相反,经过数百年的岁月,奥卡姆剃刀已被历史磨得越来越快,并早已超载原来狭窄的领域,而具有广泛、丰富、深刻的意义。 奥卡姆剃刀定律在企业管理中可进一步演化为简单与复杂定律:把事情变复杂很简单,把事情变简单很复杂。这个定律要求,我们在处理事情时,要把握事情的主要实质,把握主流,解决最根本的问题,尤其要顺应自然,不要把事情人为地复杂化,这样才能把事情处理好
posted @ 2007-11-05 10:40 重归本垒(Bing) 阅读(1785) | 评论 (0)编辑 收藏
 

1. 服务器负载均衡市场需求
  随着Internet的普及以及电子商务、电子政务的发展,越来越多的应用系统需要面对更高的访问量和数据量。同时,企业对在线系统的依赖也越来越高,大量的关键应用需要系统有足够的在线率及高效率。这些要求使得单一的网络服务设备已经不能满足这些需要,由此需要引入服务器的负载均衡,实现客户端同时访问多台同时工作的服务器,一则避免服务器的单点故障,再则提高在线系统的服务处理能力。从业界环境来说,如下的应用需求更是负载均衡发展的推动力:

  •   业务系统从Client-Server转向采用Browser-Server 系统结构,关键系统需要高可用性
  •   电子商务系统的高可用性和高可靠性需要
  •   IT应用系统大集中的需要 (税务大集中,证券大集中,银行大集中)
  •   数据中心降低成本,提高效率

  负载均衡技术在现有网络结构之上提供了一种廉价、有效、透明的方法,来扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。它有两方面的含义:首先,大量的并发访问或数据流量分担到多台节点设备上分别处理,减少用户等待响应的时间;其次,单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高。

  BIG/IP利用定义在其上面的虚拟IP地址来为用户的一个或多个应用服务器提供服务。因此,它能够为大量的基于TCP/IP的网络应用提供服务器负载均衡服务。BIG/IP连续地对目标服务器进行L4到L7合理性检查,当用户通过VIP请求目标服务器服务时,BIG/IP根椐目标服务器之间性能和网络健康情况,选择性能最佳的服务器响应用户的请求。

下图描述了一个负载均衡发生的流程:
 


    
  1. 客户发出服务请求到VIP
  2. BIGIP接收到请求,将数据包中目的IP地址改为选中的后台服务器IP地址,然后将数据包发出到后台选定的服务器
  3. 后台服务器收到后,将应答包按照其路由发回到BIGIP
  4. BIGIP收到应答包后将其中的源地址改回成VIP的地址,发回客户端,由此就完成了一个标准的服务器负载均衡的流程。

2.负载均衡典型流程

  •   通过VIP来截获合适的需要负载均衡的流量
  •   服务器监控和健康检查,随时了解服务器群的可用性状态
  •   负载均衡和应用交换功能,通过各种策略导向到合适的服务器
      

2.1 通过VIP来截获合适的需要负载均衡的流量
   在BIGIP上通过设置VIP来截获需要进行负载均衡的流量,这个VIP地址可以是一个独立的主机地址和端口的组合(例如:202.101.112.115:80)也可以是一个网络地址和端口的组合(例如:202.101.112.0:80),当流量经过BIGIP的时候,凡是命中VIP的流量都将被截获并按照规则进行负载均衡。

2.2 服务器的健康监控和检查

   服务器 (Node) - Ping (ICMP)

      BIGIP可以定期的通过ICMP包对后台服务器的IP地址进行检测,如果在设定的时间内能收到该地址的ICMP的回应,则认为该服务器能提供服务

   服务 (Port) – Connect
      BIGIP可以定期的通过TCP包对后台服务器的服务端口进行检测,如果在设定的时间内能收到该服务器端口的回应,则认为该服务器能提供服务


   扩展内容查证(ECV: Extended Content Verification)—ECV

     ECV是一种非常复杂的服务检查,主要用于确认应用程序能否对请求返回对应的数据。如果一个应用对该服务检查作出响应并返回对应的数据,则BIG/IP控制器将该服务器标识为工作良好。如果服务器不能返回相应的数据,则将该服务器标识为宕机。宕机一旦修复,BIG/IP就会自动查证应用已能对客户请求作出正确响应并恢复向该服务器传送。该功能使BIG/IP可以将保护延伸到后端应用如Web内容及数据库。BIG/ip的ECV功能允许您向Web服务器、防火墙、缓存服务器、代理服务器和其它透明设备发送查询,然后检查返回的响应。这将有助于确认您为客户提供的内容正是其所需要的。

   扩展应用查证(EAV: Extended Application Verification)

     EAV是另一种服务检查,用于确认运行在某个服务器上的应用能否对客户请求作出响应。为完成这种检查,BIG/IP控制器使用一个被称作外部服务检查者的客户程序,该程序为BIG/IP提供完全客户化的服务检查功能,但它位于BIG/IP控制器的外部。例如,该外部服务检查者可以查证一个Internet或Intranet上的从后台数据库中取出数据并在HTML网页上显示的应用能否正常工作。EAV是BIG/IP提供的非常独特的功能,它提供管理者将BIG/IP客户化后访问各种各样应用的能力,该功能使BIG/IP在提供标准的可用性查证之外能获得服务器、应用及内容可用性等最重要的反馈。
     该功能对于电子商务和其它应用至关重要,它用于从客户的角度测试您的站点。例如,您可以模拟客户完成交易所需的所有步骤-连接到站点、从目录中选择项目以及验证交易使用的信用卡。一旦BIG/ip掌握了该“可用性”信息,即可利用负载均衡使资源达到最高的可用性。

  BIG/ip已经为测试Internet服务的健康情况和状态,预定义的扩展应用验证(EAV),它有二种用户界面:浏览器和CLI配置。BIG/IP预定义的应用检查:FTP、NNTP、SMTP、POP3和MSSQL。


2.3 负载均衡和应用交换功能,通过各种策略导向到合适的服务器

  BIGIP是一台对流量和内容进行管理分配的设备。它提供12种灵活的算法将数据流有效地转发到它所连接的服务器群。而面对用户,只是一台虚拟服务器。用户此时只须记住一台服务器,即虚拟服务器。但他们的数据流却被BIGIP灵活地均衡到所有的服务器。这12种算法包括:

轮询(Round Robin):顺序循环将请求一次顺序循环地连接每个服务器。当其中某个服务器发生第二到第7层的故障,BIG/IP就把其从顺序循环队列中拿出,不参加下一次的轮询,直到其恢复正常。
比率(Ratio):给每个服务器分配一个加权值为比例,根椐这个比例,把用户的请求分配到每个服务器。当其中某个服务器发生第二到第7层的故障,BIG/IP就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
优先权(Priority):给所有服务器分组,给每个组定义优先权,BIG/IP用户的请求,分配给优先级最高的服务器组(在同一组内,采用轮询或比率算法,分配用户的请求);当最高优先级中所有服务器出现故障,BIG/IP才将请求送给次优先级的服务器组。这种方式,实际为用户提供一种热备份的方式。
最少的连接方式(Least Connection):传递新的连接给那些进行最少连接处理的服务器。当其中某个服务器发生第二到第7层的故障,BIG/IP就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
最快模式(Fastest):传递连接给那些响应最快的服务器。当其中某个服务器发生第二到第7层的故障,BIG/IP就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
观察模式(Observed):连接数目和响应时间以这两项的最佳均衡为依据为新的请求选择服务器。当其中某个服务器发生第二到第7层的故障,BIG/IP就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
预测模式(Predictive):BIG/IP利用收集到的服务器当前的性能指标,进行预测分析,选择一台服务器在下一个时间片内,其性能将达到最佳的服务器相应用户的请求。(被bigip进行检测)
动态性能分配(Dynamic Ratio-APM):BIG/IP收集到的应用程序和应用服务器的各项性能参数,动态调整流量分配。
动态服务器补充(Dynamic Server Act.):当主服务器群中因故障导致数量减少时,动态地将备份服务器补充至主服务器群。
服务质量(QoS):按不同的优先级对数据流进行分配。
服务类型(ToS):按不同的服务类型(在Type of Field中标识)对数据流进行分配。
规则模式:针对不同的数据流设置导向规则,用户可自行编辑流量分配规则,BIG/IP利用这些规则对通过的数据流实施导向控制。

posted @ 2007-11-05 09:37 重归本垒(Bing) 阅读(1426) | 评论 (0)编辑 收藏
 
WML
     摘要:   ·                               ...  阅读全文
posted @ 2007-10-10 17:17 重归本垒(Bing) 阅读(1624) | 评论 (0)编辑 收藏
 
XML
     摘要:   什么是XML     XML即可扩展标记语言(eXtensible Markup Language)。标记是指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。     1.XML并不是标记语言。它只是用来创造标记语言(比如HTML)的元语言。     2...  阅读全文
posted @ 2007-10-10 17:08 重归本垒(Bing) 阅读(752) | 评论 (1)编辑 收藏
 
java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource
很显然这是一个没有找到对应的类文件的异常。
还有两个包commons-pool.jar和commons-dbcp-1.2.1.jar需要引入到工程中。
posted @ 2007-09-12 15:16 重归本垒(Bing) 阅读(3896) | 评论 (1)编辑 收藏
 
        本文将介绍在JSP页面中包含一些JavaScript这样一个简单而有效的方法来结合AJAX和Struts。在此我们介绍如何重新使用已经存在的Struts actions,但此技术同样可用于你选择的其他Java-Web 框架。本方法同样可平移到Struts或者JSF的下一个版本。

        AJAX是“异步的JavaScript和XML”的缩写。这是一项技术,而不是一个如Struts一样的框架。为什么在AJAX周围会有这么多的关注呢?这是因为AJAX使web页面看起来并不像一个平面的文档,而更像用户所期望的如桌面应用的动态GUI应用程序。AJAX技术能在很多的浏览器上使用(包括IE和Netscape/Mozilla)。它已经为Microsoft(用于Outlook的web客户端)和Google(用户Google Maps和Gmail)所使用。

  未使用AJAX之前

  目前大多数的Struts应用都是标准的“如同一个平面文档的web页面”的结构。如果你想模仿一些桌面应用程序(比如那些使用Java Swing,Visual Basic,或者Delphi建立的应用程序),那么你有两个选择:你可以发送所有的可能作为页面的一部分被请求的信息,使用大量的JavaScript来操作其动态的显示(一个很慢并且非企业级Java的方法);或者你可以不改变形式地提交到后台服务器(一种有效的方法) 。AJAX提高给你了融合前面的最佳解决方案:动态的页面,但是大多数的应用是在你的web服务器的Java程序来处理的。

  AJAX 101

  AJAX和现有的动态HTML技术非常相似,并在其上增加了一个发送到“后台”服务器的请求来获取需要的新的或者更新的信息。AJAX的机制在其他地方已经有详细的说明――请查看本文后的Resources来获取更多。但是你至少需要知道:

  •   1. XMLHttpRequest (如果你使用的是IE浏览器的话,则是Microsoft.XMLHTTP的ActiveX的对象)。这些对象,你可以在web页面中使用JavaScript调用。他们允许你作为后台的调用方式来请求web服务器的内容(例如,在表单提交后,屏幕并不像平时一样显示“空白”)。
  •   2. XMLHttpRequest 和Microsoft.XMLHTTP 返回的内容可以作为XML或者文本来处理。JavaScript(在你页面上的)可以使用请求的新内容来更新页面。
  •   3. 整个处理过程可以由普通的JavaScript事件来触发:onclick,onchange,onblur,等。

  在你的Struts应用中使用AJAX

  你阅读了本文,然后你会对使用AJAX来创建动态的web页面感兴趣,并且想知道如何将它加入到你的Struts应用中。这只是选择之一。那么你会如何选择呢?

  •   · 等待,知道Struts的下一个版本融合了AJAX技术。如果Struts开发者准备开发一个新的应用,这或许会是一个好的选择。再后面,可能会是要求JSF也这样做――对其本身并不一件坏事,但是对于已经存在的系统这将会带来最根本的改变。
  •   · 你也可以直接采用新的方法,比如Direct Web Remoting (DWR) 和Ruby on Rails,这些都是专为建立AJAX应用的。如果你考虑不使用Struts来开发web的话,那么这些都是很又用的框架,并且值得一试。但是,这也同时意味着你必须要重写你的应用。
  •   · 在你已经存在的Struts应用中增加AJAX。既然AJAX只是一项技术而并非框架,那么它就很容易融入到Struts中。作为现有的系统,其稳定性(如,保持现有的库文件)是相当重要的。所以这个方法被推荐,并且我们将在后面详细介绍。

  我们选择在Struts应用中增加AJAX的优势是:

  •   1. 它并不需要任何新的库文件或者服务器代码;只需要使用现有的Struts库文件和action。
  •   2. 解决方案中所有部分――JavaScript,XML,Java和Struts――早已为广泛所知。
  •   3. 此应用可以一块一块地移植到AJAX;我们可以确定哪些部分对用户有益,并首先将它们更新到动态AJAX显示。

  实现方案

  我们如何真正的贯彻我们的选择呢?我们首先应该注意一个“标准的”(没有AJAX)Struts应用是如何工作的。在此应用中,一个一般的事件流程如下:

  •   1. 使用点击超链接或者表单的提交按钮,用户发送请求。
  •   2. web服务器运行处理请求的Struts Action来生成一个web页面。
  •   3. 浏览器显示web页面。
  •   4. 当用户点击保存的时候,信息由Struts框架中一个ActionForm类来转换并发送到服务器。
  •   5. 然后,Struts框架调用Struts Action来出来请求(如,保存数据到数据库中)。
  •   6. 页面再一次回传,处理流程继续。

  现有的Struts应用

  一个演示事件流程的简单Struts应用可以在以下地址下载: struts-non-ajax.zip。此基于Struts的应用,是基于用户的输入显示或者隐藏蓝色和绿色的表格。图1显示了载入初始页面的画面。图2显示了用户输入值并点击了提交后的画面。虽然简单,但它已经足以表示一个Struts的工作流程。

  图 1. 没有AJAX的例子:初始屏幕

  图 2. 没有AJAX的例子:输入值并点击了提交

服务器端的代码是:一个Struts Action使用struts-config.xml 中定义的值转发到(相同的)JSP。这个例子代码中一些需要注意的地方是:
  •   ·struts-config.xml文件将所有的请求重定向到http://localhost:8080/struts-non-ajax/(或者和你自己的服务器相同)的index.jsp。
  •   · index.jsp 包含了一个两个文本框的Struts form(showBlue和showGreen)。该页面同样包含了标签,但是如同两个文本框被初始化为空,标签之间的内容并不显示。
  •   · 用户输入值(true或者false)并点击提交按钮,处理控制(经过Struts框架,读取struts-config.xml)提交到SampleAction类中。
  •   ·SampleAction记录下值,然后转发到index.jsp。一个成熟的Struts应用可能会处理更多的事情,不如保存或者查询数据库等。
  •   · index.jsp 现在重新处理请求;如果ShowBlue或者ShowGreen的值是true,这些表格就显示出来。

  该应用并没有任何“错误”。类似的Struts项目好多年都是这样做的。但是,我们如何在不添加复杂的JavaScript或者频繁的表单提交的前提下,为此应用增加动态的元素呢?

  我们的第一个Struts AJAX应用

  观察下下面的图3和图4。第一眼看上去,它们和前面的例子没有说明区别。它们的不同之处在于,页面载入后(图3)然后文本框中的值改变了,窗体自动提交而不显示空白的,然后在图4中显示结果。普通的提交按钮仍然在,你也可以选择使用它。

  图 3. 页面载入后的AJAX例子

  图 4. AJAX调用后的AJAX例子

  添加AJAX是出奇的容易。服务器端的代码和前面的例子是一样的: 一个Struts的ActionForm来后去数据,一个Struts的Action来执行需要的任务(例如,存储数据库)然后转发到适当的JSP页面来显示结果。

  继续

  如果你希望就此停止阅读(跳过这个例子的工作说明),但是这里的是和你需要转换你的Struts应用到一个Struts-AJAX应用同样的风格:

  •   1. 在你的web页面中引入一个Ajax.js (该文件是struts-ajax.zip 例文件中的一部分)。Ajax.js 包含了所有需要发送和接收AJAX调用的JavaScript方法。
  •   2. 确保你希望在AJAX调用中更新的web页面的部分包含在标签中,并且给每个标签一个id。
  •   3. 当一些事件触发的时候就更新页面(例如,文本框的the onchange()方法),调用retrieveURL()方法,通过URL传递到需要执行服务器端处理的Struts Action。
  •   4. 为了页面的显示/更新,最简单的方法是Struts Action转发回同样的页面。在本例中,showGreen/showBlue 文本框中的onchange()方法来触发AJAX调用。

  JavaScript方法retrieveURL()调用服务器的Struts(通过URL),获取JSP响应,然后更新显示页面中的 标签中的部分。就是这么简单!

  AJAX解决方案的细节

  我们将例子变为AJAX-Struts应用的时候,需要三个变化:

  •   1. 增加一个JavaScript方法来完成到服务器的“背后的”AJAX调用。
  •   2. 增加JavaScript代码来接收服务器的响应并更新页面。
  •   3. 在JSP页面增加标签标签,这个标签中内容将在AJAX调用中更新。

  我们将详细的说明上面的每一步。

发送AJAX请求到服务器

  有两个方法(在下面列出)用于发送请求到服务器。

  · retrieveURL()方法获得服务器的URL和Struts form。URL用于使用AJAX,form的值用于传递到服务器。

  · getFormAsString()方法用于将retrieveURL()中form命名的值组装成查询字符串,并发送到服务器。

  使用方法很简单,使用onclick()/onChange()事件来触发retrieveURL()更新显示。

  在这两个方法中有一些有趣的东西。

  在retrieveURL()方法中,req.onreadystatechange = processStateChange (注意,没有括号)这一行来告诉浏览器在服务器响应到达的时候调用processStateChange()方法(该方法将在后面介绍)。retrieveURL()方法中(现在已经是AJAX的标准了)同样决定是使用IE浏览器(ActiveX)还是使用Netscape/Mozilla (XmlHttpRequest) 来实现跨浏览器兼容。

  getFormAsString()方法将HTML form转换成字符串连接在URL后面(这样就允许我们发送HTTP GET请求)。这个字符串是经过转换的(比如,空格转换成%20等),并且是一个Struts能将其组装成ActionForm的格式(并不需要Struts清楚的明白这个是来之AJAX的请求)。注意,在本例中我们使用HTTP GET,使用HTTP POST的方法也是类似的。

function retrieveURL(url,nameOfFormToPost) {

//将url转换成字符串
url=url+getFormAsString(nameOfFormToPost);

//调用AJAX
if (window.XMLHttpRequest) {

// 非IE浏览器
req = new XMLHttpRequest();
req.onreadystatechange = processStateChange;
try {
req.open("GET", url, true);
} catch (e) {
alert("Server Communication Problem\n"+e);
}
req.send(null);
} else if (window.ActiveXObject) {
// IE

req = new ActiveXObject("Microsoft.XMLHTTP");
if (req) {
req.onreadystatechange=processStateChange;
req.open("GET", url, true);
req.send();
}
}
}

getFormAsString() 是一个“私有” 方法,在retrieveURL()中使用。

function getFormAsString(formName){

//设置返回字符串
returnString ="";

//取得表单的值
formElements=document.forms[formName].elements;

//循环数组,组装url
//像'/strutsaction.do&name=value'这样的格式

for(var i=formElements.length-1;i>=0; --i ){
//转化每一个值
returnString+="&"
+escape(formElements[i].name)+"="
+escape(formElements[i].value);
}

//返回字符串
return returnString;
}

根据AJAX的响应更新web页面

  到现在为止,我们学习过了使用JavaScript来完成AJAX调用(前面列出),Struts Action,ActionForm以及JSP(基本没有变化,只是增加了标签)。为了完善我们对Struts-AJAX项目的了解,我们需要了解三个用于根据服务器返回的结果而更新页面的JavaScript方法。

  •   · processStateChange(): 该方法在AJAX调用前设定。它在服务器响应到达后由XMLHttpRequest/Microsoft.XMLHTTP 对象调用。
  •   ·splitTextIntoSpan(): 根据响应,循环取出数组中的元素组装成NewContent。
  •   ·replaceExistingWithNewHtml(): 根据span元素数组,循环搜索,将里面的元素调换掉页面中和它的'someName'相同的中的内容。注意,我们使用的是req.responseText 方法来获得返回的内容(它允许我们操作任何文本的响应)。与此相对于的是req.responseXml (它的作用更大,但是要求服务器返回是XHTML或者XML)。

function processStateChange() {

if (req.readyState == 4) { // 完成
if (req.status == 200) { // 响应正常

//将响应的文本分割成Span元素
spanElements =
splitTextIntoSpan(req.responseText);

//使用这些Span元素更新页面
replaceExistingWithNewHtml(spanElements);

} else {
alert("Problem with server response:\n "
+ req.statusText);
}
}
}
replaceExistingWithNewHtml() 是为processStateChange()使用的“私有”方法。

function replaceExistingWithNewHtml
(newTextElements){

//循环newTextElements
for(var i=newTextElements.length-1;i>=0;--i){

//判断是否以 if(newTextElements[i].
indexOf("-1){

//获得span的名字- 设置在第一和第二个引号之间
//确认span元素是以下的格式
//NewContent
startNamePos=newTextElements[i].
indexOf('"')+1;
endNamePos=newTextElements[i].
indexOf('"',startNamePos);
name=newTextElements[i].
substring(startNamePos,endNamePos);

//获得内容-在第一个>标记后的所有内容
startContentPos=newTextElements[i].
indexOf('>')+1;
content=newTextElements[i].
substring(startContentPos);

//现在更新现有的Document中的元素,
// 确保文档存在该元素
if(document.getElementById(name)){
document.getElementById(name).
innerHTML = content;
}
}
}
splitTextIntoSpan() 是为processStateChange() 使用的“私有”方法。
function splitTextIntoSpan(textToSplit){

//分割文档
returnElements=textToSplit.
split("")

//处理每个元素
for(var i=returnElements.length-1;i>=0;--i){

//删除掉第一个span后面的元素
spanPos = returnElements[i].
indexOf("

//如果找到匹配的,获得span前的内容
if(spanPos>0){
subString=returnElements[i].
substring(spanPos);
returnElements[i]=subString;
}
}
return returnElements;
}

  新的控制流

  添加以下的JavaScript代码到我们的应用中,以下的步骤将在服务器和浏览器中执行。

  •   1. 如同一个普通Struts应用装载页面。
  •   2. 用户改变文本框的值,触发一个onChange() 事件,调用retrieveURL() 方法。
  •   3. 该JavaScript方法通过发送Struts明白的表单变量(后台)请求到服务器的Struts Action。
  •   4. 该JavaScript方法同样设定了第二个JavaScript方法的名字,此方法将到服务器响应完毕后调用。本例子中,设定为processStateChange() 方法。
  •   5. 如我们所预期的,服务器响应完毕,调用processStateChange() 方法。
  •   6. JavaScript在(新的)服务器响应中循环取出所有元素。将页面上存在与获得元素名字相同的 中的元素替换掉。

  在你的应用中设计AJAX

  以上描述的JavaScript方法能在大多数的应用中使用,包括比我们的例子复杂得多的。但是,在使用之前,你需要注意以下几点:

  · 避免复制代码,最好在初始化请求(如,显示完整的页面)和AJAX(更新部分页面)请求中使用相同的Struts Action和JSP。

  ·在公共的Action(控制器)中,决定JSP页面(所有的JSP页面或者其中的一部分)中的一个区域需要传送到浏览器。通过在web服务器的session或者ActionForm中设定标记来让JSP页面知道哪些部分需要提交。

  · 在JSP中,使用Struts 或者JSTL标签来决定提交的HTML区域。

  使用AJAX的本例子,可以在以下下载: struts-Ajax.zip

  结语

  AJAX技术允许我们在创建和使用web应用的时候完全的改变。本文介绍了一个简单的技术,在现有的Struts应用中增加Struts的处理。它允许我们利用我们已有的东西,不仅仅是代码,还包括了开发的技能。作为一个好的产品,它同样允许我们写出更清晰,更具移植性的Java Struts应用。

版权声明:Techtarget获Matrix授权发布,如需转载请联系Matrix
作者:作者:Paul Browne;pawenwen(作者的blog:http://blog.matrix.org.cn/page/pawenwen)
译文:点击

posted @ 2007-07-31 16:33 重归本垒(Bing) 阅读(683) | 评论 (1)编辑 收藏
 

随着企业intranet和国际internet的迅速发展,越来越多的工作流程,商务交易,教育、培训、会议和讲座,以及个人消费娱乐都被转移到所谓的万维网(World Wide Web,以下简称WEB)上来了。与此相对应的是交互操作的复杂性越来越高。

随着Browser/Server模式的日渐流行,很多操作都是在浏览器环境下的网页上完成的,并不是只有失效的链接和意外的出错才会使操作者感到烦恼,即便是一次完整的成功操作过程,也可能因为操作的繁复性过高或者使用上的不方便而给操作者带来不愉快的体验。

本文试图阐述WEB交互页面设计的一些指导性原则,这些原则有利于避免发生不愉快的操作体验。这些原则是用户友好性的,是在完成同一种操作要求下,使用户最感到轻松、简单、舒适的WEB交互界面设计原则。我们假定我们讨论的WEB页面都是功能正常的,符合美学观点的。需要说明我们讨论的原则可能会和设计上的美学观点以及既有的功能设计有所冲突。如果发生这种情况,基于“实用的就是美的”观点,我们会建议您酌情放弃原先的美学观点与功能设计。

 

 

1. 输入控件的自动聚焦和可用键盘切换输入焦点

 

 

使用JavaScript实现页面加载完成后立即自动聚焦(focus)到第一个输入控件。可用TAB键(IE缺省实现)或方向键切换聚焦到下一个输入控件。

 

 

输入控件指WEB页面表单(<form>)中显式的,需要用户进行修改、编辑操作的表单元素。对于这些控件,如果没有自动聚焦操作,不可避免的出现一次用户鼠标定位操作(如果用户此前处于键盘输入操作状态或鼠标定位后需要进行键盘输入操作,实际上是键盘鼠标切换操作)。如果鼠标定位后需要进行键盘输入操作,如果不能键盘切换输入焦点,那么不可避免的在切换输入焦点时需要反复的键盘鼠标切换操作,这是很繁琐的。

如果实现了页面加载完成即自动聚焦到第一个输入控件,并且可以键盘切换输入焦点标定位操作,那么对于用户来说整个页面的输入操作可能都不需要鼠标操作,或次数较少,这是一种便利。毕竟频繁的键盘鼠标切换操作是比较累人的。

对于有输入栏的对话框或网页,在不干预的情况下就应将当前控制焦点定位在待输入的输入栏上;如果输入栏在一般情况下不需要更改其中的内容,则应直接将焦点定在“确定”按钮上;在几个输入栏之间应支持tabshift+tab切换操作,“确定”和“取消”应该是切换操作的终点,与具体所在位置无关。

 

 

2.   可用Enter(或CtrlEnter)键提交,确保和点击提交按钮的效果是相同的

 

 

不要在提交按钮上加入onClick=”…”这样的JavaScript代码。

 

 

Enter键提交页面是原则1的自然延伸,而且这也是浏览器所缺省支持的。只所以单独列出来是因为实际上有些设计者设计的页面不能达到这种效果,结果导致使用Enter键提交和点击“确定”按钮提交带来的效果不一样。大部分情况下是设计者在“确定”按钮上加入了onClik=”…”这样的代码,通过点击“确定”按钮后,会执行一段JavaScript代码,比如对某些hidden类型的input元素设值。而使用Enter键提交时就不会执行这段代码。

正确的做法是把这段代码移到表单标签<form>中,以onSubmit=”…”属性引入。

对于<textarea>表单元素,它会消耗Enter键,因此会使得Enter键提交失效。可以引入JavaScript代码捕捉Ctrl+Enter复合键,一旦捕捉到即执行表单的submit()方法。对于需要频繁提交的场合,比如BBS上,这种代码是很有必要的。

      

3. 鼠标动作提示和回应

 

 

对用户的鼠标定位操作,当移动到可响应的位置上时,应给予视觉或听觉的提示。

 

 

动作回应的最简单形式就是鼠标ICON变成手状。浏览器只对具有href属性的HTML标签会自动进行这种变换ICON的行为。对于没有href属性(或没有设置href属性)的标签,可以通过JavaScript设置style属性的cursorhand

目标区域发生变化是更为主动的响应形式。当鼠标指针移到目标区域,此时指针图形改变或文字颜色发生改变均能较大的减轻用户搜索定位目标区域的注意力负担。在按钮上增添直观的图形,尽可能的增大按钮面积;按钮间保持适当的距离,太近增加了用户区别它们之间界限以防误操作的负担,太远增加了用户搜索定位按钮的负担。

 

 

4.尽可能早的在客户端完成输入数据合法性验证

 

 

输入数据的合法性检验应该在客户端使用JavaScript进行验证。除非验证只能在服务器端完成,否则验证工作应在最早能完成的情况下进行。

 

 

在客户端完成数据合法性验证,可以避免一次服务器请求和回复通讯,这种通讯是需要用户等待的,如果用户等待很长时间后从服务器返回的结果提示出现的错误是在输入时即可发现的,那么这种设计就是不友好的。诸如密码长度限制,用户名允许字符限制等等,显然应该在客户端提交前就应该进行验证。

 

 

5. 根据应用场景决定在表单页面和提交后返回页面间是否使用中间过渡页面

 

 

根据应用场景,决定是否显示接收表单页面(表单页面和提交后返回页面间的中间过渡页面),以及使用何种方式显示接收表单页面。

 

 

表单页面和接收表单页面是大部分WEB交互操作赖以实现的配合模式。关于表单页面和接收表单页面的相互关系的设计,要做如下几个方面的考虑。

一,对于需要频繁操作的场合,从操作便利和快捷性出发,尽可能的减少服务器和客户端交互次数,应该避免使用中间过渡页面。提交完毕直接返回原来的表单页面或默认页面。在这种情况下要考虑到数据安全和可恢复性。

如果因为用户输入的数据不合格,需要重新输入,那么,去除中间页面,把错误信息直接显示在原表单页面上的设计方式,将是最简洁的处理方式。用户只需要根据错误提示进行更正即可。当然这样做稍微增加了编程负担。在表单接收页面上需要包含原表单页面的内容,而且输入数据项都必须用服务器端代码或客户端JavaScript设置成用户输入的值。为了开发快捷,可以这样做:表单页面和接收表单页面用同一个服务器端脚本页面实现。这个页面按如下流程完成原来两个页面的工作:

页面脚本初始化

检查“提交”变量是否设置

已设置,做数据验证

   ┠验证通过->业务逻辑处理->使用包含页面方式或重定向方式返回到特定页面

 

 

   验证不通过->保存用户输入的数据->退出表单提交处理到表单页面流程中

┗未设置,做表单页面流程,如有来自提交流程中产生的用户输入数据,则显示出来

 

 

其中,使用包含页面方式返回到特定页面可以避免一次客户端重定向过程,比客户端重定向过程还要快捷和稳定一些。但是有些情况下因为代码变量冲突或其他原因,使用包含页面方式可能并不方便,这时候可以使用服务器端重定向技术,在ASP里是Server.Transfer方法,在Java Servlet里是RequestDispatcher.forward()方法。不要使用Response.Redirect或者HttpServletResponse.sendRedirect()这种客户端HTTP重定向方法。不使用中间过渡页面也就意味着用户不能后退浏览原先已经填好的表单页面,因为使用的是同一个URL。所以在验证不通过情况下保存用户输入的数据就是必不可少的。

 

 

不使用中间过渡页面带来的另一个问题就是使用包含页面方式或服务器端重定向方式返回会使得URL和页面内容不能一一对应。对于用户可能会直接用这个URL(会收藏这个URL)访问返回页面的情况,他会发现实际上到达的是表单页面,不是他想要的那个返回结果页面。所以,去除中间过渡页面,确实会带来URL和内容含混不清的情况,因而不适合需要URL和页面内容一一对应的场合。

 

 

二,从技术角度考虑,使用中间过渡页面能保证URL和页面内容一一对应,简化页面开发工作。

 

 

为了保证页面内容总是和固定的URL联系起来,必须使用客户端重定向:

 

 

           提交                   业务逻辑处理  (中间过渡页面)

 

 

表单页面――――->接收表单页面―――――――――>显示处理结果―――>客户端重定向到特定页面

 

 

客户端重定向分几种情况:1,使用HTTP Header重定向,Location:http://www.netall.com.cn,这种定向是最快的,在窗口一片空白的情况下就迅速访问(GET)另一个页面。这种方式实际上不能显示处理结果,只能说是向第一种快速重定向方式的一种折衷处理;2,HTML标签刷新,<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://www.netall.com.cn">,这种定向比较友好,在这个页面加载完毕后访问另一个页面。很多设计者把这个作为一个技巧使用,在载入一个大页面前放置一个缓冲页面以避免用户乏味的等待;3JavaScript重定向。由于是用代码控制重定向,可以做的更灵活。比如根据用户习惯,控制操作完毕后的转向流程。4,被动式的重定向。在页面上放置按钮或链接,由用户手动决定返回到特定页面。这种情况适合于处理结果的显示页面包含相当多的信息,需要用户仔细浏览,而决定下一步的操作。

 

 

在使用中间过渡页面的情况下,不能再使用页面过期失效了。否则一旦出现错误,需要用户重新输入表单数据,用户就不能用后退按钮恢复此前填写的表单数据了。除非设计者有意禁止这种恢复。

 

 

 

 

6. 防止表单重复提交处理

 

 

对提交按钮点击后做变灰处理避免在网络响应较慢情况下用户重复提交同一个表单。使用页面过期失效避免用户后退浏览重复提交表单。

 

 

有些复杂的应用会导致需要较长时间的等待才会返回处理结果。而在较慢的网络环境中,这种情况更是频繁发生。焦急等待的用户往往会重复点击提交按钮。这种情况是设计者所不希望看到的。

使用JavaScript在点击提交按钮后使按钮失效变灰是一个最直接的办法(根据原则2这段代码应该放在<form>标签里onSubmit=”…”做)。此外,在表单页面上,用服务器端脚本设置HTTP HeaderExpires为立即过期可以保证用户没办法使用后退浏览恢复表单页面。注意这样做的代价可能是用户辛辛苦苦填写很长的内容,结果一旦操作失误就没法恢复。所以应该避免在包含<textarea>表单元素的页面上使用页面过期失效。

应该说,更严格的方法是,服务器端脚本就应该具备抵抗重复提交的能力。例如,为这个表单分配一个唯一ID或一个使用一次即失效的验证码。此外,这个表单处理还应具有事务性质,如果表单不被接受,所做的改变还是能恢复的。在金融应用场合,重复提交同一笔交易是肯定不被允许的。能在重复提交中获利的一方总是会想办法绕过浏览器的限制,所以不能依赖于客户端的技术。

      

7. 页面链接是打开新窗口、使用原窗口还是弹出窗口的原则

 

 

一般而言,首页上链接可以使用target=”_blank”属性打开新窗口,而其他页面上的链接都应使用原窗口或弹出窗口。如果链接页面内容相对原页面来说不重要,是附属性质的,可以使用弹出窗口方式。

 

 

一般情况下应该使用原窗口,把是否保留原窗口内容的权利留给用户。除非设计者相信原页面是如此重要,在用户发出点击指令后还有使用上的价值,以至于不能被随便更新或覆盖。一般来说,只有首页才会处于这样一个地位,用户在首页上打开一个链接后,一般还会在这个首页上去打开另一个链接。比如首页包含极多链接的门户网站,或者搜索引擎的搜索结果页面。Google.com以前的搜索结果页面上的链接是使用原窗口的,后来他们意识到用户会反复使用这个页面,而改成打开新窗口了。一般的网站如果首页链接不多,就不必使用新窗口,这是用户友好的设计原则。

上述情形的一个极端情况就是新页面内容比起原页面内容的重要性差很多,以至于都未必需要打开一个新页面。这时候使用弹出窗口比较合适。用JavaScript弹出窗口有好几种:一个是window.open()函数。这里有个技巧。应该使用window.open()先打开一个空白窗口,再使用location.replace()用目标页面替换。这样做可以避免在打开新页面的过程中导致原页面失去响应。Window.open()将打开一个新的浏览器窗口进程,因此资源消耗比较大。另一个是由微软DynamicHTML规范中扩充的方法createPopup()createPopup()可以创建无边框的弹出窗口,消耗系统资源较小。还有一个就是用页面中隐藏的层<div>来模拟一个弹出页面。后两种可以使用JavaScript代码填充弹出窗口内容。如果需要下载网页作为其内容的话,需要微软DynamicHTML规范中的<download>标签。

 

 

8. 尽可能少的排列可选项,尽可能少的安排操作步骤

 

 

根据用户操作习惯安排尽可能少的操作菜单选项,同时要保证尽可能少的操作步骤。

 

 

在不降低功能多样性的前提下减少菜单项和操作步骤是用户友好的设计。要做到这一点很不容易。要从用户出发考虑他们最频繁的操作是什么。正常情况下一个用户需要的操作总可以归类为5个以下的种类,如果出现更多的种类,那一定是没有针对用户兴趣去区分主次。一个用户同时有5个以上的强烈兴趣中心是难以想像的,走马观花似的随意点击浏览的用户,是不大可能在某个种类上进行深入的交互操作的。在这5个种类中,每个种类都可能有若干个可操作的二级种类。如果这些二级操作项是不可见的,那么意味着要做两次选择才能进入可操作页面。这就违背了“尽可能少的安排操作步骤”这一原则。如果使用JavaScript制作二级菜单,避免请求服务器,会好一些。如果二级菜单项总共不超过20个左右,不妨将二级菜单直接显示出来,比如放在左列一字向下排开,这样只需要一次选择到可操作项,更加明了方便。

 

 

9. 操作逻辑无漏洞,保证数据是操作安全的

 

 

多个页面间的操作和同个页面上的多个操作间的逻辑关系在设计上是安全和严谨的。保证不会出现不被允许的用户操作组合,至少不会因为用户的不适当的操作导致出错。

 

 

这最典型的表现则是在页面上广泛采用的所谓联动下拉框设计。一个下拉框中允许的选项受另一个下拉框中的选择而变。另外一个例子是根据选择使表单元素有效或者失效。如果在多个页面间也要维持某种合法性逻辑,那么就需要服务器端脚本的参与。这样会使表单设计跟操作有关,应该说这不是一个好的设计。可以通过变更操作步骤顺序、组合方式来尽可能避免这种情况出现。

操作逻辑的设计既要保证用户任意的输入不会导致错误,也要保证是用户输入的数据能购被安全处理。在Session控制下的表单中输入大幅文字可能会导致超时出错,这时候往往还伴随重定向过程,导致用户的长篇输入荡然无存。用JavaScript提醒用户已超时,请保存输入后重新提交,是一个好办法。某些表单元素如<input type=”text”>接受ESC键清除数据,并且无法撤销,这也是很危险的。在中文输入法中常常使用ESC键清楚输入的码位,一旦不小心多按一下ESC就会使得输入数据消失。因此有必要用JavaScript禁用<input><textarea>ESC键处理过程。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=413028

posted @ 2007-07-31 14:12 重归本垒(Bing) 阅读(379) | 评论 (0)编辑 收藏
 

 

System.out.println("根目录所对应的绝对路径:" + request.getServletPath() + ""); 
String strPathFile 
= request.getSession().getServletContext().getRealPath(request.getRequestURI()); 
System.out.println(
"文件的绝对路径:" + strPathFile + ""); 
String strDirPath 
= new File(request.getSession().getServletContext().getRealPath(request.getRequestURI())).getParent(); 
System.out.println(
"目录的绝对路径:" + strDirPath + ""); 
    this.getServlet().getServletContext().getRealPath("/");//在struts的action中取得当前系统的根目录

 举例:http://localhost:7001/myservlet/somepath/test?someparam=somevalue
request.getPathInfo():返回
/somepath/test
request.getRequestURL():返回http:
//localhost:7001/myservlet/somepath/test
request.getRequestURI():返回/myservlet/somepath/test
request.getServletPath():返回
/myservlet
request.getQueryString():返回someparam
=somevalue
    request.getContextPath();  返回项目名/myservlet
posted @ 2007-07-27 12:23 重归本垒(Bing) 阅读(1008) | 评论 (0)编辑 收藏
 
因为<bean:write 默认的filter是true。表示把html敏感标签转换成转换成它们实体的等价物。如<转换成&lt。设为false则不转换。
         <FCK:editor id="classContent" basePath="/ECR_WWW/FCKeditor/"
         width
="500"
         height
="500"
         skinPath
="/ECR_WWW/FCKeditor/editor/skins/silver/"
         
>
         
         
<bean:write name="articleAdminForm" property="classContent" filter="false"/>
        
</FCK:editor>
posted @ 2007-07-25 10:06 重归本垒(Bing) 阅读(1437) | 评论 (0)编辑 收藏
 

1.下载
FCKeditor2.3 (FCKeditot for java)
FCKeditor2.4 (FCKeditor基本文件)
以下是下载地址:
http://www.fckeditor.net/download/default.html

2.建立项目:
建立项目tomcat/webapps/TestFCKeditor.

3.将FCKeditor2.4解压缩
将FCKeditor2.4解压缩,将整个目录FCKeditor复制到项目的根目录下,并将解压缩出来的文件夹fckeditor重命名为FCKeditor
目录结构为:tomcat/webapps/TestFCKeditor/FCKeditor
然后将FCKeditor-2.3.zip(java)压缩包中\web\WEB-INF\lib\目录下的两个jar文件拷到项目的\WEB-INF\ lib\目录下。把其中的src目录下的FCKeditor.tld文件copy到TestFCKedit/WEB-INF/下

4.合并web.xml:
将FCKeditor-2.3.zip压缩包中\web\WEB-INF\目录下的web.xml文件合并到项目的\WEB-INF\目录下的web.xml文件中。


5. 修改合并后的web.xml文件
修改合并后的web.xml文件,将名为SimpleUploader的Servlet的enabled参数值改为true,
以允许上传功能,Connector Servlet的baseDir参数值用于设置上传文件存放的位置。
在web.xml最后添加标签定义:

<taglib>
    <taglib-uri>/TestFCKeditor</taglib-uri>
    <taglib-location>/WEB-INF/FCKeditor.tld</taglib-location>
 </taglib>

现在的web.xml文件没有<taglib>标签了,应该直接在jsp文件中使用:<%@ taglib uri="http://fckeditor.net/tags-fckeditor" prefix="FCK" %>

 

6. 映射:
上面文件中两个servlet的映射分别为:/editor/filemanager/browser/default/connectors/jsp/connector
和/editor/filemanager/upload/simpleuploader,需要在两个映射前面加上/FCKeditor,
即改为/FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector和
/FCKeditor/editor/filemanager/upload/simpleuploader。
这两个名字根据你放在工程中的FCKeditor文件夹名称而定。。


7.修改skin文件夹
进入skin文件夹,如果你想使用fckeditor默认的这种奶黄色,
那就把除了default文件夹外的另两个文件夹直接删除.(建议不删除,以后要用到其中的一个文件夹)

8.删除无用文件
删除/FCKeditor/目录下除fckconfig.js, fckeditor.js, fckstyles.xml, fcktemplates.xml四个文件以外的所有文件,保留文件夹editor
删除目录/editor/_source,
删除/editor/filemanager/browser/default/connectors/下的所有文件
删除/editor/filemanager/upload/下的所有文件
删除/editor/lang/下的除了fcklanguagemanager.js(我下载的没有这个文件), en.js, zh.js, zh-cn.js四个文件的所有文件

9.修改配置:
打开/FCKeditor/fckconfig.js
修改 FCKConfig.DefaultLanguage = 'zh-cn' ;
把FCKConfig.LinkBrowserURL等的值替换成以下内容:
FCKConfig.LinkBrowserURL
= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Connector=connectors/jsp/connector" ;

FCKConfig.ImageBrowserURL
= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector" ;

FCKConfig.FlashBrowserURL
= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/jsp/connector" ;

FCKConfig.LinkUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=File' ;
FCKConfig.FlashUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Flash' ;
FCKConfig.ImageUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Image' ;

10.其它
fckconfig.js总配置文件,可用记录本打开,修改后将文件存为utf-8 编码格式。找到:

FCKConfig.TabSpaces = 0 ; 改为FCKConfig.TabSpaces = 1 ; 即在编辑器域内可以使用Tab键。

如果你的编辑器还用在网站前台的话,比如说用于留言本或是日记回复时,那就不得不考虑安全了,
在前台千万不要使用Default的toolbar,要么自定义一下功能,要么就用系统已经定义好的Basic,
也就是基本的toolbar,找到:
FCKConfig.ToolbarSets["Basic"] = [
['Bold','Italic','-','OrderedList','UnorderedList','-',/*'Link',*/'Unlink','-','Style','FontSize','TextColor','BGColor','-',
'Smiley','SpecialChar','Replace','Preview'] ] ;
这是改过的Basic,把图像功能去掉,把添加链接功能去掉,因为图像和链接和flash和图像按钮添加功能都能让前台
页直接访问和上传文件, fckeditor还支持编辑域内的鼠标右键功能。

FCKConfig.ContextMenu = ['Generic',/*'Link',*/'Anchor',/*'Image',*/'Flash','Select','Textarea','Checkbox','Radio','TextField','HiddenField',
/*'ImageButton',*/'Button','BulletedList','NumberedList','TableCell','Table','Form'] ;

这也是改过的把鼠标右键的“链接、图像,FLASH,图像按钮”功能都去掉。

  找到: FCKConfig.FontNames = 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;
加上几种我们常用的字体
FCKConfig.FontNames
= '宋体;黑体;隶书;楷体_GB2312;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;


11.添加文件
添加文件 /TestFCKeditor/test.jsp:
<%@ page language="java" import="com.fredck.FCKeditor.*" %>
<%@ taglib uri="/TestFCKeditor" prefix="FCK" %>
<script type="text/javascript" src="/TestFCKeditor/FCKeditor/fckeditor.js"></script>

<%--
三种方法调用FCKeditor
1.FCKeditor自定义标签 (必须加头文件 <%@ taglib uri="/TestFCKeditor" prefix="FCK" %> )
2.script脚本语言调用 (必须引用 脚本文件 <script type="text/javascript" src="/TestFCKeditor/FCKeditor/fckeditor.js"></script> )
3.FCKeditor API 调用 (必须加头文件 <%@ page language="java" import="com.fredck.FCKeditor.*" %> )
--%>


//标签调用方式
<%--
<form action="show.jsp" method="post" target="_blank">
<FCK:editor id="content" basePath="/TestFCKeditor/FCKeditor/"
width="700"
height="500"
skinPath="/TestFCKeditor/FCKeditor/editor/skins/silver/"
toolbarSet = "Default"
>
input
</FCK:editor>
<input type="submit" value="Submit">
</form>
--%>


//JS调用方式
<form action="show.jsp" method="post" target="_blank">
<table border="0" width="700"><tr><td>
<textarea id="content" name="content" style="WIDTH: 100%; HEIGHT: 400px">input</textarea>
<script type="text/javascript">
var oFCKeditor = new FCKeditor('content') ;
oFCKeditor.BasePath = "/TestFCKeditor/FCKeditor/" ;
oFCKeditor.Height = 400;
oFCKeditor.ToolbarSet = "Default" ;
oFCKeditor.ReplaceTextarea();
</script>
<input type="submit" value="Submit">
</td></tr></table>
</form>


//FCKeditor API 调用
<%--
<form action="show.jsp" method="post" target="_blank">
<%
FCKeditor oFCKeditor ;
oFCKeditor = new FCKeditor( request, "content" ) ;
oFCKeditor.setBasePath( "/TestFCKeditor/FCKeditor/" ) ;
oFCKeditor.setValue( "input" );
out.println( oFCKeditor.create() ) ;
%>
<br>
<input type="submit" value="Submit">
</form>
--%>

添加文件/TestFCKeditor/show.jsp:
<%
String content = request.getParameter("content");
out.print(content);
%>

 


12.测试
浏览http://localhost:8080/TestFCKeditor/test.jsp


最后注意。。不同的版本 变量名称可能不一样。请参考你使用的API文档

配置选项:

AutoDetectLanguage=true/false 自动检测语言
BaseHref="" 相对链接的基地址
ContentLangDirection="ltr/rtl" 默认文字方向
ContextMenu=字符串数组,右键菜单的内容
CustomConfigurationsPath="" 自定义配置文件路径和名称
Debug=true/false 是否开启调试功能,这样,当调用FCKDebug.Output()时,会在调试窗中输出内容
DefaultLanguage="" 缺省语言
EditorAreaCss="" 编辑区的样式表文件
EnableSourceXHTML=true/false 为TRUE时,当由可视化界面切换到代码页时,把HTML处理成XHTML
EnableXHTML=true/false 是否允许使用XHTML取代HTML
FillEmptyBlocks=true/false 使用这个功能,可以将空的块级元素用空格来替代
FontColors="" 设置显示颜色拾取器时文字颜色列表
FontFormats="" 设置显示在文字格式列表中的命名
FontNames="" 字体列表中的字体名
FontSizes="" 字体大小中的字号列表
ForcePasteAsPlainText=true/false 强制粘贴为纯文本
ForceSimpleAmpersand=true/false 是否不把&符号转换为XML实体
FormatIndentator="" 当在源码格式下缩进代码使用的字符
FormatOutput=true/false 当输出内容时是否自动格式化代码
FormatSource=true/false 在切换到代码视图时是否自动格式化代码
FullPage=true/false 是否允许编辑整个HTML文件,还是仅允许编辑BODY间的内容
GeckoUseSPAN=true/false 是否允许SPAN标记代替B,I,U标记
IeSpellDownloadUrl=""下载拼写检查器的网址
ImageBrowser=true/false 是否允许浏览服务器功能
ImageBrowserURL="" 浏览服务器时运行的URL
ImageBrowserWindowHeight="" 图像浏览器窗口高度
ImageBrowserWindowWidth="" 图像浏览器窗口宽度
LinkBrowser=true/false 是否允许在插入链接时浏览服务器
LinkBrowserURL="" 插入链接时浏览服务器的URL
LinkBrowserWindowHeight=""链接目标浏览器窗口高度
LinkBrowserWindowWidth=""链接目标浏览器窗口宽度
Plugins=object 注册插件
PluginsPath="" 插件文件夹
ShowBorders=true/false 合并边框
SkinPath="" 皮肤文件夹位置
SmileyColumns=12 图符窗列数
SmileyImages=字符数组 图符窗中图片文件名数组
SmileyPath="" 图符文件夹路径
SmileyWindowHeight 图符窗口高度
SmileyWindowWidth 图符窗口宽度
SpellChecker="ieSpell/Spellerpages" 设置拼写检查器
StartupFocus=true/false 开启时FOCUS到编辑器
StylesXmlPath="" 设置定义CSS样式列表的XML文件的位置
TabSpaces=4 TAB键产生的空格字符数
ToolBarCanCollapse=true/false 是否允许展开/折叠工具栏
ToolbarSets=object 允许使用TOOLBAR集合
ToolbarStartExpanded=true/false 开启是TOOLBAR是否展开
UseBROnCarriageReturn=true/false 当回车时是产生BR标记还是P或者DIV标记

解决上传乱码:
在SimpleUploaderServlet.java和ConnectorServlet.java两个文件里找到
DiskFileUpload upload = new DiskFileUpload();
分别在其后加入 upload.setHeaderEncoding("utf-8");
这样解决了文件上传的中文乱码问题.
但是在控制台显示的中文内容还是乱码,但是没关系,我们没必要去看控制台下的中文

----------------------------------------------------------------another
FCKeditor2.4.2 Java版使用说明
下载地址以及基本配置请参考:http://hi.baidu.com/wain19/blog/item/c33fb0fab74f24dfb48f312d.html

我的开发环境是ubuntu7.04, 系统默认编码是utf-8,
期间,本人遇到了下面这些问题:

问题一:XML request error: Internel Server Error(500)

出现错误的地方是在:点插入图片,点Browse按钮的时候:
XML request error: Internel Server Error(500)

找资料:http://lamono.javaeye.com/blog/49135
拷贝xalan.jar和serialize.jar到/WEB-INF/lib,问题解决。

FCKeditor-java没有很好的解决中文问题。需要我们修改它的源代码后重新编译打包。打包过程如下:
1。 新建一个web工程名字为FCKeditor-java-2.3,然后把FCKeditor-2.3-java.zip解压缩后的代码拷贝到工程目录下。
2。如果是用的Eclipse,使用快捷键Ctrl+Shift+R
在SimpleUploaderServlet.java和ConnectorServlet.java两个文件里找到
DiskFileUpload upload = new DiskFileUpload();
分别在其后加入 upload.setHeaderEncoding("utf-8");
现在如果直接运行ant任务,会报下面的错误:
taskdef class org.apache.catalina.ant.DeployTask cannot be found

3。 把tomcat安装目录下/server/lib中的catalina-ant.jar拷贝到/WEB-INF/lib目录 下。
4。 打开build.xml
找到
<property name="catalina.home"
修改成你自己的tomcat安装目录
<property name="catalina.home"         value="/home/uniquejava/tool/tomcat5028/"/>
找到
<taskdef name="deploy"
修改成如下内容
     <taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask">
        <classpath refid="compile.classpath">
        </classpath>
    </taskdef>
    <taskdef name="list" classname="org.apache.catalina.ant.ListTask">
        <classpath refid="compile.classpath">
        </classpath>
    </taskdef>
    <taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
        <classpath refid="compile.classpath">
        </classpath>
    </taskdef>
    <taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask">
        <classpath refid="compile.classpath">
        </classpath>
    </taskdef>

运行ant任务dist, 就可以生成新的FCKeditor-2.3.jar包

问题三: 上传时新建的中文目录全部乱码。 虽然上传到服务器上的文件名正常,但在JSP页面点下载链接时文件名乱码导致不能正常下载。

查找资料:TOMCAT 链接参数有中文时,乱码解决方法
http://hi.baidu.com/jadestone/blog/item/7564deefc9192d36acafd5be.html
修改tomcat-home/conf/server.xml
方法一:
在两处地方加上URIEncoding="utf-8":
    <Connector port="8080"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               debug="0" connectionTimeout="20000"
               disableUploadTimeout="true" URIEncoding="utf-8" />
              
    <Connector port="8009"
               enableLookups="false" redirectPort="8443" debug="0"
               protocol="AJP/1.3" URIEncoding="utf-8" />
              
方法二:
使用useBodyEncodingForURI="true". 这个方法适合你的TOMCAT实例下需要跑多个不同Encoding的程序时。(有点怀疑?!)
<... maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
       enableLookups="false" redirectPort="8443" acceptCount="100"
      connectionTimeout="20000" disableUploadTimeout="true" useBodyEncodingForURI="true" />

     enableLookups="false" redirectPort="8443" protocol="AJP/1.3" useBodyEncodingForURI="true" /

我只试了方法一,问题解决!

这样, FCKeditor终于可以正常使用了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
=================================================================
以下为个人原创 http://blog.csdn.net/nickshen3/
怎么将FCKeditor2.4使用在自己的web中。
1. 在webapps创建test文件夹。webapps\test
2. 将下载的FCKeditor2.3的Java包FCKeditor-2.3.zip解压缩,并将web文件夹下的两个文件夹_samples,WEB-INF拷贝到刚才建立的webapps\test下。再将src文件夹下的FCKeditor.tld拷贝到WEB-INF下。
3. 在webapps\test\下建立文件夹FCKeditor 。
4. 将刚才下载的 FCKeditor_2.4.3.zip 解压缩,然后将fckeditor文件夹下的 editor(文件夹),fckconfig.js,fckeditor.js,fckstyles.xml,fcktemplates.xml。四个文件拷贝到刚才建立的文件夹FCKeditor下。
5.修改test\_samples\jsp\sample02.jsp文件,将原来的
       <FCK:editor id="EditorDefault" basePath="/FCKeditor/"
改为<FCK:editor id="EditorDefault" basePath="/test/FCKeditor/"。以后使用的时候只需将test换成项目的名称即可。
6.打开tomcat。测试Http://localhost:8080/test/_samples/jsp/sample02.jsp
ok。

另外 :  http://www.blogjava.net/youxia/archive/2007/03/15/104077.html 

posted @ 2007-07-24 17:58 重归本垒(Bing) 阅读(1746) | 评论 (1)编辑 收藏
 
  这需要导入java.io类
import java.io.*;

public class FileOperate {
  public FileOperate() {
  }

  /**
   * 新建目录
   * @param folderPath String 如 c:/fqf
   * @return boolean
   */
  public void newFolder(String folderPath) {
    try {
      String filePath = folderPath;
      filePath = filePath.toString();
      java.io.File myFilePath = new java.io.File(filePath);
      if (!myFilePath.exists()) {
        myFilePath.mkdir();
      }
    }
    catch (Exception e) {
      System.out.println("新建目录操作出错");
      e.printStackTrace();
    }
  }

  /**
   * 新建文件
   * @param filePathAndName String 文件路径及名称 如c:/fqf.txt
   * @param fileContent String 文件内容
   * @return boolean
   */
  public void newFile(String filePathAndName, String fileContent) {

    try {
      String filePath = filePathAndName;
      filePath = filePath.toString();
      File myFilePath = new File(filePath);
      if (!myFilePath.exists()) {
        myFilePath.createNewFile();
      }
      FileWriter resultFile = new FileWriter(myFilePath);
      PrintWriter myFile = new PrintWriter(resultFile);
      String strContent = fileContent;
      myFile.println(strContent);
      resultFile.close();

    }
    catch (Exception e) {
      System.out.println("新建目录操作出错");
      e.printStackTrace();

    }

  }

  /**
   * 删除文件
   * @param filePathAndName String 文件路径及名称 如c:/fqf.txt
   * @param fileContent String
   * @return boolean
   */
  public void delFile(String filePathAndName) {
    try {
      String filePath = filePathAndName;
      filePath = filePath.toString();
      java.io.File myDelFile = new java.io.File(filePath);
      myDelFile.delete();

    }
    catch (Exception e) {
      System.out.println("删除文件操作出错");
      e.printStackTrace();

    }

  }

  /**
   * 删除文件夹
   * @param filePathAndName String 文件夹路径及名称 如c:/fqf
   * @param fileContent String
   * @return boolean
   */
  public void delFolder(String folderPath) {
    try {
      delAllFile(folderPath); //删除完里面所有内容
      String filePath = folderPath;
      filePath = filePath.toString();
      java.io.File myFilePath = new java.io.File(filePath);
      myFilePath.delete(); //删除空文件夹

    }
    catch (Exception e) {
      System.out.println("删除文件夹操作出错");
      e.printStackTrace();

    }

  }

  /**
   * 删除文件夹里面的所有文件
   * @param path String 文件夹路径 如 c:/fqf
   */
  public void delAllFile(String path) {
    File file = new File(path);
    if (!file.exists()) {
      return;
    }
    if (!file.isDirectory()) {
      return;
    }
    String[] tempList = file.list();
    File temp = null;
    for (int i = 0; i < tempList.length; i++) {
      if (path.endsWith(File.separator)) {
        temp = new File(path + tempList[i]);
      }
      else {
        temp = new File(path + File.separator + tempList[i]);
      }
      if (temp.isFile()) {
        temp.delete();
      }
      if (temp.isDirectory()) {
        delAllFile(path+"/"+ tempList[i]);//先删除文件夹里面的文件
        delFolder(path+"/"+ tempList[i]);//再删除空文件夹
      }
    }
  }

  /**
   * 复制单个文件
   * @param oldPath String 原文件路径 如:c:/fqf.txt
   * @param newPath String 复制后路径 如:f:/fqf.txt
   * @return boolean
   */
  public void copyFile(String oldPath, String newPath) {
    try {
      int bytesum = 0;
      int byteread = 0;
      File oldfile = new File(oldPath);
      if (oldfile.exists()) { //文件存在时
        InputStream inStream = new FileInputStream(oldPath); //读入原文件
        FileOutputStream fs = new FileOutputStream(newPath);
        byte[] buffer = new byte[1444];
        int length;
        while ( (byteread = inStream.read(buffer)) != -1) {
          bytesum += byteread; //字节数 文件大小
          System.out.println(bytesum);
          fs.write(buffer, 0, byteread);
        }
        inStream.close();
      }
    }
    catch (Exception e) {
      System.out.println("复制单个文件操作出错");
      e.printStackTrace();

    }

  }

  /**
   * 复制整个文件夹内容
   * @param oldPath String 原文件路径 如:c:/fqf
   * @param newPath String 复制后路径 如:f:/fqf/ff
   * @return boolean
   */
  public void copyFolder(String oldPath, String newPath) {

    try {
      (new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
      File a=new File(oldPath);
      String[] file=a.list();
      File temp=null;
      for (int i = 0; i < file.length; i++) {
        if(oldPath.endsWith(File.separator)){
          temp=new File(oldPath+file[i]);
        }
        else{
          temp=new File(oldPath+File.separator+file[i]);
        }

        if(temp.isFile()){
          FileInputStream input = new FileInputStream(temp);
          FileOutputStream output = new FileOutputStream(newPath + "/" +
              (temp.getName()).toString());
          byte[] b = new byte[1024 * 5];
          int len;
          while ( (len = input.read(b)) != -1) {
            output.write(b, 0, len);
          }
          output.flush();
          output.close();
          input.close();
        }
        if(temp.isDirectory()){//如果是子文件夹
          copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
        }
      }
    }
    catch (Exception e) {
      System.out.println("复制整个文件夹内容操作出错");
      e.printStackTrace();

    }

  }

  /**
   * 移动文件到指定目录
   * @param oldPath String 如:c:/fqf.txt
   * @param newPath String 如:d:/fqf.txt
   */
  public void moveFile(String oldPath, String newPath) {
    copyFile(oldPath, newPath);
    delFile(oldPath);

  }

  /**
   * 移动文件到指定目录
   * @param oldPath String 如:c:/fqf.txt
   * @param newPath String 如:d:/fqf.txt
   */
  public void moveFolder(String oldPath, String newPath) {
    copyFolder(oldPath, newPath);
    delFolder(oldPath);

  }
}



java中删除目录事先要删除目录下的文件或子目录。用递归就可以实现。这是我第一个用到算法作的程序,哎看来没白学。
public void del(String filepath) throws IOException{
File f = new File(filepath);//定义文件路径       
if(f.exists() && f.isDirectory()){//判断是文件还是目录
    if(f.listFiles().length==0){//若目录下没有文件则直接删除
        f.delete();
    }else{//若有则把文件放进数组,并判断是否有下级目录
        File delFile[]=f.listFiles();
        int i =f.listFiles().length;
        for(int j=0;j<i;j++){
            if (delFile[j].isDirectory()){                                                del (delFile[j].getAbsolutePath());//递归调用del方法并取得子目录路径
            }
            delFile[j].delete();//删除文件
        }
    }
    del(filepath);//递归调用
}

}    


删除一个非空目录并不是简单地创建一个文件对象,然后再调用delete()就可以完成的。要在平台无关的方式下安全地删除一个非空目录,你还需要一个算法。该算法首先删除文件,然后再从目录树的底部由下至上地删除其中所有的目录。

只要简单地在目录中循环查找文件,再调用delete就可以清除目录中的所有文件:

static public void emptyDirectory(File directory) {
   File[ ] entries = directory.listFiles( );
   for(int i=0; i<entries.length; i++) {
       entries[i].delete( );
   }
}
这个简单的方法也可以用来删除整个目录结构。当在循环中遇到一个目录时它就递归调用deleteDirectory,而且它也会检查传入的参数是否是一个真正的目录。最后,它将删除作为参数传入的整个目录。
static public void deleteDirectory(File dir) throws IOException {
   if( (dir == null) || !dir.isDirectory) {
       throw new IllegalArgumentException(

                 "Argument "+dir+" is not a directory. "
             );
   }

   File[ ] entries = dir.listFiles( );
   int sz = entries.length;

   for(int i=0; i<sz; i++) {
       if(entries[i].isDirectory( )) {
           deleteDirectory(entries[i]);
       } else {
           entries[i].delete( );
       }
   }

  dir.delete();
}
在Java 1.1以及一些J2ME/PersonalJava的变种中没有File.listFiles方法。所以只能用File.list,它的返回值一个字符串数组,你要为每个字符串构造一个新的文件对象。
posted @ 2007-07-24 13:25 重归本垒(Bing) 阅读(1441) | 评论 (0)编辑 收藏
 
1。试图在Struts的form标记外使用form的子元素。在后面使用Struts的html标记等

2。不经意使用的无主体的标记,如web 服务器解析时当作一个无主体的标记,随后使用的标记都被认为是在这个标记之外的
3。还有就是在使用taglib引入HTML标记库时,你使用的prefix的值不是html

4。property必须和所要提交的action对应的formbean中的某个属性相匹配(必须有一个formbean)
5。要使用标签,外层必须使用标签,不能使用html的

posted @ 2007-07-19 17:22 重归本垒(Bing) 阅读(7194) | 评论 (7)编辑 收藏
 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactoryId' defined in ServletContext resource [/WEB-INF/classes/applicationContext.xml]: Initialization of bean failed; nested exception is org.hibernate.cache.CacheException: net.sf.ehcache.CacheException: Cannot configure CacheManager: 文件过早结束。

昨天rebase后出现了这个问题,费了我一个下午的时间,多方查找资料都没有办法,到今天早上后看到
http://forum.springframework.org/showthread.php?t=25528上说的。才知道大概是ehcache配制不当造成的,于是从同事那里拷贝ehcache.xml过来,解决了!血的教训!

ehcache是一个很不错的轻量级缓存实现,速度快,功能全面(一般的应用完全足够了),从1.2版后可以支持分布式缓存,可以用在集群环境中。除了可以缓存普通的对象,还可以用来作为Web页面的缓存。缓存静态HTML、JSP、Velocity、FreeMarker等等的页面。Hibernate选择ehcache作为默认的缓存实现的。






posted @ 2007-07-19 09:45 重归本垒(Bing) 阅读(2403) | 评论 (0)编辑 收藏
 
     摘要: Hibernate的透明持久化用起来非常舒服,有时甚至忘记了数据库的存在。我身边的朋友经常会分不清save、saveOrUpdate、update的区别,lock、merge、replicate、refresh、evict甚至不知道是干什么用的。而且关于实体对象的生命周期也有很多概念不清,分不清transient、persistent、detached的区别,只是知道PO、VO这样的通俗叫法。其实...  阅读全文
posted @ 2007-07-13 13:02 重归本垒(Bing) 阅读(366) | 评论 (0)编辑 收藏
 
一、数组转成字符串:
1、 将数组中的字符转换为一个字符串
将数组中的字符转换为一个字符串

@param strToConv 要转换的字符串 ,默认以逗号分隔
@return 返回一个字符串
String[3] s={"a","b","c"}
StringUtil.convString(s)="a,b,c"
2、 static public String converString(String strToConv)
@param strToConv 要转换的字符串 ,
@param conv 分隔符,默认以逗号分隔
@return 同样返回一个字符串

String[3] s={"a","b","c"}
StringUtil.convString(s,"@")="a@b@c"
static public String converString(String strToConv, String conv)


二、空值检测:
3、

Checks if a String is empty ("") or null.


判断一个字符串是否为空,空格作非空处理。 StringUtils.isEmpty(null) = true StringUtils.isEmpty("") = true StringUtils.isEmpty(" ") = false StringUtils.isEmpty("bob") = false StringUtils.isEmpty(" bob ") = false

NOTE: This method changed in Lang version 2.0.

It no longer trims the String.
That functionality is available in isBlank().


@param str the String to check, may be null
@return true if the String is empty or null
public static boolean isEmpty(String str)


三、非空处理:
4、
Checks if a String is not empty ("") and not null.


判断一个字符串是否非空,空格作非空处理. StringUtils.isNotEmpty(null) = false StringUtils.isNotEmpty("") = false StringUtils.isNotEmpty(" ") = true StringUtils.isNotEmpty("bob") = true StringUtils.isNotEmpty(" bob ") = true

@param str the String to check, may be null
@return true if the String is not empty and not null
public static boolean isNotEmpty(String str)

5、

Checks if a String is not empty (""), not null and not whitespace only.


判断一个字符串是否非空,空格作空处理. StringUtils.isNotBlank(null) = false StringUtils.isNotBlank("") = false StringUtils.isNotBlank(" ") = false StringUtils.isNotBlank("bob") = true StringUtils.isNotBlank(" bob ") = true

@param str the String to check, may be null
@return true if the String is
not empty and not null and not whitespace
@since 2.0
public static boolean isNotBlank(String str)


四、 空格处理
6、
Removes control characters (char <= 32) from both

ends of this String, handling null by returning
null.


The String is trimmed using {@link String#trim()}.

Trim removes start and end characters <= 32.
To strip whitespace use {@link //strip(String)}.


To trim your choice of characters, use the

{@link //strip(String, String)} methods.


格式化一个字符串中的空格,有非空判断处理; StringUtils.trim(null) = null StringUtils.trim("") = "" StringUtils.trim(" ") = "" StringUtils.trim("abc") = "abc" StringUtils.trim(" abc ") = "abc"

@param str the String to be trimmed, may be null
@return the trimmed string, null if null String input
public static String trim(String str)

7、


Removes control characters (char <= 32) from both

ends of this String returning null if the String is
empty ("") after the trim or if it is null.

The String is trimmed using {@link String#trim()}.

Trim removes start and end characters <= 32.
To strip whitespace use {@link /stripToNull(String)}.


格式化一个字符串中的空格,有非空判断处理,如果为空返回null; StringUtils.trimToNull(null) = null StringUtils.trimToNull("") = null StringUtils.trimToNull(" ") = null StringUtils.trimToNull("abc") = "abc" StringUtils.trimToNull(" abc ") = "abc"

@param str the String to be trimmed, may be null
@return the trimmed String,
null if only chars <= 32, empty or null String input
@since 2.0
public static String trimToNull(String str)

8、


Removes control characters (char <= 32) from both

ends of this String returning an empty String ("") if the String
is empty ("") after the trim or if it is null.

The String is trimmed using {@link String#trim()}.

Trim removes start and end characters <= 32.
To strip whitespace use {@link /stripToEmpty(String)}.


格式化一个字符串中的空格,有非空判断处理,如果为空返回""; StringUtils.trimToEmpty(null) = "" StringUtils.trimToEmpty("") = "" StringUtils.trimToEmpty(" ") = "" StringUtils.trimToEmpty("abc") = "abc" StringUtils.trimToEmpty(" abc ") = "abc"

@param str the String to be trimmed, may be null
@return the trimmed String, or an empty String if null input
@since 2.0
public static String trimToEmpty(String str)


五、 字符串比较:
9、
Compares two Strings, returning true if they are equal.


nulls are handled without exceptions. Two null

references are considered to be equal. The comparison is case sensitive.


判断两个字符串是否相等,有非空处理。 StringUtils.equals(null, null) = true StringUtils.equals(null, "abc") = false StringUtils.equals("abc", null) = false StringUtils.equals("abc", "abc") = true StringUtils.equals("abc", "ABC") = false

@param str1 the first String, may be null
@param str2 the second String, may be null
@return true if the Strings are equal, case sensitive, or
both null
@see java.lang.String#equals(Object)
public static boolean equals(String str1, String str2)


10、

Compares two Strings, returning true if they are equal ignoring

the case.


nulls are handled without exceptions. Two null

references are considered equal. Comparison is case insensitive.


判断两个字符串是否相等,有非空处理。忽略大小写 StringUtils.equalsIgnoreCase(null, null) = true StringUtils.equalsIgnoreCase(null, "abc") = false StringUtils.equalsIgnoreCase("abc", null) = false StringUtils.equalsIgnoreCase("abc", "abc") = true StringUtils.equalsIgnoreCase("abc", "ABC") = true

@param str1 the first String, may be null
@param str2 the second String, may be null
@return true if the Strings are equal, case insensitive, or
both null
@see java.lang.String#equalsIgnoreCase(String)
public static boolean equalsIgnoreCase(String str1, String str2)


六、 IndexOf 处理
11、


Finds the first index within a String, handling null.

This method uses {@link String#indexOf(String)}.


A null String will return -1.


返回要查找的字符串所在位置,有非空处理 StringUtils.indexOf(null, *) = -1 StringUtils.indexOf(*, null) = -1 StringUtils.indexOf("", "") = 0 StringUtils.indexOf("aabaabaa", "a") = 0 StringUtils.indexOf("aabaabaa", "b") = 2 StringUtils.indexOf("aabaabaa", "ab") = 1 StringUtils.indexOf("aabaabaa", "") = 0

@param str the String to check, may be null
@param searchStr the String to find, may be null
@return the first index of the search String,
-1 if no match or null string input
@since 2.0
public static int indexOf(String str, String searchStr)

12、

Finds the first index within a String, handling null.

This method uses {@link String#indexOf(String, int)}.


A null String will return -1.

A negative start position is treated as zero.
An empty ("") search String always matches.
A start position greater than the string length only matches
an empty search String.


返回要由指定位置开始查找的字符串所在位置,有非空处理 StringUtils.indexOf(null, *, *) = -1 StringUtils.indexOf(*, null, *) = -1 StringUtils.indexOf("", "", 0) = 0 StringUtils.indexOf("aabaabaa", "a", 0) = 0 StringUtils.indexOf("aabaabaa", "b", 0) = 2 StringUtils.indexOf("aabaabaa", "ab", 0) = 1 StringUtils.indexOf("aabaabaa", "b", 3) = 5 StringUtils.indexOf("aabaabaa", "b", 9) = -1 StringUtils.indexOf("aabaabaa", "b", -1) = 2 StringUtils.indexOf("aabaabaa", "", 2) = 2 StringUtils.indexOf("abc", "", 9) = 3

@param str the String to check, may be null
@param searchStr the String to find, may be null
@param startPos the start position, negative treated as zero
@return the first index of the search String,
-1 if no match or null string input
@since 2.0
public static int indexOf(String str, String searchStr, int startPos)


七、 子字符串处理:
13、
Gets a substring from the specified String avoiding exceptions.


A negative start position can be used to start n

characters from the end of the String.


A null String will return null.

An empty ("") String will return "".


返回指定位置开始的字符串中的所有字符 StringUtils.substring(null, *) = null StringUtils.substring("", *) = "" StringUtils.substring("abc", 0) = "abc" StringUtils.substring("abc", 2) = "c" StringUtils.substring("abc", 4) = "" StringUtils.substring("abc", -2) = "bc" StringUtils.substring("abc", -4) = "abc"

@param str the String to get the substring from, may be null
@param start the position to start from, negative means
count back from the end of the String by this many characters
@return substring from start position, null if null String input
public static String substring(String str, int start)

14、

Gets a substring from the specified String avoiding exceptions.


A negative start position can be used to start/end n

characters from the end of the String.


The returned substring starts with the character in the start

position and ends before the end position. All postion counting is
zero-based -- i.e., to start at the beginning of the string use
start = 0. Negative start and end positions can be used to
specify offsets relative to the end of the String.


If start is not strictly to the left of end, ""

is returned.


返回由开始位置到结束位置之间的子字符串 StringUtils.substring(null, *, *) = null StringUtils.substring("", * , *) = ""; StringUtils.substring("abc", 0, 2) = "ab" StringUtils.substring("abc", 2, 0) = "" StringUtils.substring("abc", 2, 4) = "c" StringUtils.substring("abc", 4, 6) = "" StringUtils.substring("abc", 2, 2) = "" StringUtils.substring("abc", -2, -1) = "b" StringUtils.substring("abc", -4, 2) = "ab"

@param str the String to get the substring from, may be null
@param start the position to start from, negative means
count back from the end of the String by this many characters
@param end the position to end at (exclusive), negative means
count back from the end of the String by this many characters
@return substring from start position to end positon,
null if null String input
public static String substring(String str, int start, int end)


15、 SubStringAfter/SubStringBefore(前后子字符串处理:


Gets the substring before the first occurance of a separator.

The separator is not returned.


A null string input will return null.

An empty ("") string input will return the empty string.
A null separator will return the input string.


返回指定字符串之前的所有字符 StringUtils.substringBefore(null, *) = null StringUtils.substringBefore("", *) = "" StringUtils.substringBefore("abc", "a") = "" StringUtils.substringBefore("abcba", "b") = "a" StringUtils.substringBefore("abc", "c") = "ab" StringUtils.substringBefore("abc", "d") = "abc" StringUtils.substringBefore("abc", "") = "" StringUtils.substringBefore("abc", null) = "abc"

@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring before the first occurance of the separator,
null if null String input
@since 2.0
public static String substringBefore(String str, String separator)

16、

Gets the substring after the first occurance of a separator.

The separator is not returned.


A null string input will return null.

An empty ("") string input will return the empty string.
A null separator will return the empty string if the
input string is not null.


返回指定字符串之后的所有字符 StringUtils.substringAfter(null, *) = null StringUtils.substringAfter("", *) = "" StringUtils.substringAfter(*, null) = "" StringUtils.substringAfter("abc", "a") = "bc" StringUtils.substringAfter("abcba", "b") = "cba" StringUtils.substringAfter("abc", "c") = "" StringUtils.substringAfter("abc", "d") = "" StringUtils.substringAfter("abc", "") = "abc"

@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring after the first occurance of the separator,
null if null String input
@since 2.0
public static String substringAfter(String str, String separator)

17、

Gets the substring before the last occurance of a separator.

The separator is not returned.


A null string input will return null.

An empty ("") string input will return the empty string.
An empty or null separator will return the input string.


返回最后一个指定字符串之前的所有字符 StringUtils.substringBeforeLast(null, *) = null StringUtils.substringBeforeLast("", *) = "" StringUtils.substringBeforeLast("abcba", "b") = "abc" StringUtils.substringBeforeLast("abc", "c") = "ab" StringUtils.substringBeforeLast("a", "a") = "" StringUtils.substringBeforeLast("a", "z") = "a" StringUtils.substringBeforeLast("a", null) = "a" StringUtils.substringBeforeLast("a", "") = "a"

@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring before the last occurance of the separator,
null if null String input
@since 2.0
public static String substringBeforeLast(String str, String separator)

18、

Gets the substring after the last occurance of a separator.

The separator is not returned.


A null string input will return null.

An empty ("") string input will return the empty string.
An empty or null separator will return the empty string if
the input string is not null.


返回最后一个指定字符串之后的所有字符 StringUtils.substringAfterLast(null, *) = null StringUtils.substringAfterLast("", *) = "" StringUtils.substringAfterLast(*, "") = "" StringUtils.substringAfterLast(*, null) = "" StringUtils.substringAfterLast("abc", "a") = "bc" StringUtils.substringAfterLast("abcba", "b") = "a" StringUtils.substringAfterLast("abc", "c") = "" StringUtils.substringAfterLast("a", "a") = "" StringUtils.substringAfterLast("a", "z") = ""

@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring after the last occurance of the separator,
null if null String input
@since 2.0
public static String substringAfterLast(String str, String separator)


八、 Replacing(字符串替换)
19、
Replaces all occurances of a String within another String.


A null reference passed to this method is a no-op.


以指定字符串替换原来字符串的的指定字符串 StringUtils.replace(null, *, *) = null StringUtils.replace("", *, *) = "" StringUtils.replace("aba", null, null) = "aba" StringUtils.replace("aba", null, null) = "aba" StringUtils.replace("aba", "a", null) = "aba" StringUtils.replace("aba", "a", "") = "aba" StringUtils.replace("aba", "a", "z") = "zbz"

@param text text to search and replace in, may be null
@param repl the String to search for, may be null
@param with the String to replace with, may be null
@return the text with any replacements processed,
null if null String input
@see #replace(String text, String repl, String with, int max)
public static String replace(String text, String repl, String with)

20、

Replaces a String with another String inside a larger String,

for the first max values of the search String.


A null reference passed to this method is a no-op.


以指定字符串最大替换原来字符串的的指定字符串 StringUtils.replace(null, *, *, *) = null StringUtils.replace("", *, *, *) = "" StringUtils.replace("abaa", null, null, 1) = "abaa" StringUtils.replace("abaa", null, null, 1) = "abaa" StringUtils.replace("abaa", "a", null, 1) = "abaa" StringUtils.replace("abaa", "a", "", 1) = "abaa" StringUtils.replace("abaa", "a", "z", 0) = "abaa" StringUtils.replace("abaa", "a", "z", 1) = "zbaa" StringUtils.replace("abaa", "a", "z", 2) = "zbza" StringUtils.replace("abaa", "a", "z", -1) = "zbzz"

@param text text to search and replace in, may be null
@param repl the String to search for, may be null
@param with the String to replace with, may be null
@param max maximum number of values to replace, or -1 if no maximum
@return the text with any replacements processed,
null if null String input
public static String replace(String text, String repl, String with, int max)


九、 Case conversion(大小写转换)
21、

Converts a String to upper case as per {@link String#toUpperCase()}.


A null input String returns null.


将一个字符串变为大写 StringUtils.upperCase(null) = null StringUtils.upperCase("") = "" StringUtils.upperCase("aBc") = "ABC"

@param str the String to upper case, may be null
@return the upper cased String, null if null String input
public static String upperCase(String str) 22、

Converts a String to lower case as per {@link String#toLowerCase()}.


A null input String returns null.


将一个字符串转换为小写 StringUtils.lowerCase(null) = null StringUtils.lowerCase("") = "" StringUtils.lowerCase("aBc") = "abc"

@param str the String to lower case, may be null
@return the lower cased String, null if null String input
public static String lowerCase(String str) 23、

Capitalizes a String changing the first letter to title case as

per {@link Character#toTitleCase(char)}. No other letters are changed.


For a word based alorithm, see {@link /WordUtils#capitalize(String)}.

A null input String returns null.


StringUtils.capitalize(null) = null StringUtils.capitalize("") = "" StringUtils.capitalize("cat") = "Cat" StringUtils.capitalize("cAt") = "CAt"

@param str the String to capitalize, may be null
@return the capitalized String, null if null String input
@see /WordUtils#capitalize(String)
@see /uncapitalize(String)
@since 2.0
将字符串中的首字母大写
public static String capitalize(String str)
posted @ 2007-07-13 12:57 重归本垒(Bing) 阅读(743) | 评论 (0)编辑 收藏
 

一、load,get
(1)当记录不存在时候,get方法返回null,load方法产生异常

(2)load方法可以返回实体的代理类,get方法则返回真是的实体类

(3)load方法可以充分利用hibernate的内部缓存和二级缓存中的现有数据,而get方法仅仅在内部缓存中进行数据查找,如果没有发现数据則将越过二级缓存,直接调用SQL查询数据库。
   (4) 也许别人把数据库中的数据修改了,load如何在缓存中找到了数据,则不会再访问数据库,而get则会返回最新数据。
 
二、find,iterator
     (1) iterator首先会获取符合条件的记录的id,再跟据id在本地缓存中查找数据,查找不到的再在数据库中查找,结果再存在缓存中。N+1条SQL。
 (2)find跟据生成的sql语句,直接访问数据库,查到的数据存在缓存中,一条sql。

三、Hibernate生成的DAO类中函数功能说明(merge,saveOrUpdate,lock)

/**
      * 将传入的detached状态的对象的属性复制到持久化对象中,并返回该持久化对象。
      * 如果该session中没有关联的持久化对象,加载一个。
      * 如果传入对象未保存,保存一个副本并作为持久对象返回,传入对象依然保持detached状态。
      */

public Sysuser merge(Sysuser detachedInstance) {
      log.debug("merging Sysuser instance");
      try {
       Sysuser result = (Sysuser) getHibernateTemplate().merge(
         detachedInstance);
       log.debug("merge successful");
       return result;
      } catch (RuntimeException re) {
       log.error("merge failed", re);
       throw re;
      }
}

/**
      * 将传入的对象持久化并保存。 如果对象未保存(Transient状态),调用save方法保存。
      * 如果对象已保存(Detached状态),调用update方法将对象与Session重新关联。
      */
public void attachDirty(Sysuser instance) {
      log.debug("attaching dirty Sysuser instance");
      try {
       getHibernateTemplate().saveOrUpdate(instance);
       log.debug("attach successful");
      } catch (RuntimeException re) {
       log.error("attach failed", re);
       throw re;
      }
}

/**
      * 将传入的对象状态设置为Transient状态
      */

public void attachClean(Sysuser instance) {
      log.debug("attaching clean Sysuser instance");
      try {
       getHibernateTemplate().lock(instance, LockMode.NONE);
       log.debug("attach successful");
      } catch (RuntimeException re) {
       log.error("attach failed", re);
       throw re;
      }
}

posted @ 2007-07-13 11:18 重归本垒(Bing) 阅读(2800) | 评论 (0)编辑 收藏
 

错误 :javax.servlet.ServletException: DispatchMapping[/configaction] does not define a handler property

 原因: action参数配置不全
解决方法:在 config文件中 添加 parameter="method"等

错误: 表单数据验证失败时发生错误,“No input attribute for mapping path”


原因:action中表单验证 validate="true" ,如果validate()返回非空的ActionErrors,将会被转到input属性指定的URI,而action中未指定input时会报此错
解决方法:添加 input="url" 或者 validate="false"

posted @ 2007-07-09 16:32 重归本垒(Bing) 阅读(311) | 评论 (0)编辑 收藏
 
     摘要: Filter有要实现的三方法:void init(FilterConfig config) throws ServletExceptionvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletExceptionvoid destroy...  阅读全文
posted @ 2007-07-04 09:31 重归本垒(Bing) 阅读(1360) | 评论 (0)编辑 收藏
 

要有这么一个监听器,当加入session时就可以触发一个加入session事件,在session过期时就可以触发一个删除事件,那么我们的把要处理的东西加入到这两个事件中就可以做很多于SESSION相关连的事。如在线用户的管理,单点登陆等等。
在J2EE中可以实现HttpSessionBindingListener接口,此接口有两要实现的方法。
 void valueBound(HttpSessionBindingEvent event) 当实现此接口的监听类和session绑定时触发此事件。
void valueUnbound(HttpSessionBindingEvent event) 当session过期或实现此接口的监听类卸裁时触发此事件。

下面是一个示例解决方案:可以把登陆用户的信息记录在缓冲池中,当SESSION过期时,用户信息自动删除。
一个用户信息接口。一个用户缓冲池。一个HttpSessionBindingListener接口的监听类。

public interface LoginUserMessage {}

 

public class LoginUserPool {
    
private Map map = new HashMap();
    
private static LoginUserPool loginUserPool = new LoginUserPool();
    
private LoginUserPool(){}
    
public static LoginUserPool getInstance() {
        
return loginUserPool;
    }

    
public void addLoginUserMessage(String sessionId,LoginUserMessage loginUserMessage){
       map.remove(sessionId);
       map.put(sessionId,loginUserMessage);
    }

    
public LoginUserMessage removeLoginUserMessage(String sessionId){
        
return  (LoginUserMessage) map.remove(sessionId);
    }

    
public LoginUserMessage getLoginUserMessage(String sessionId){
        
return (LoginUserMessage) map.get(sessionId);
    }

    
public Map getLoginUserMessages(){
        
return map;
    }

    
public boolean isEmpty(){
        
return  map.isEmpty();
    }

}

 

public class UserLoginListener implements HttpSessionBindingListener{
    
private final Log logger = LogFactory.getLog(getClass());
    
private String sessionId = null;
    
private LoginUserMessage loginUserMessage = null;
    
private LoginUserPool loginUserPool = LoginUserPool.getInstance();

    
public LoginUserMessage getLoginUserMessage() {
        
return loginUserMessage;
    }

    
public void setLoginUserMessage(LoginUserMessage loginUserMessage) {
        
this.loginUserMessage = loginUserMessage;
    }

    
public String getSessionId() {
        
return sessionId;
    }

    
public void setSessionId(String sessionId) {
        
this.sessionId = sessionId;
    }

    
/* (non-Javadoc)
     * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
     
*/

    
public void valueBound(HttpSessionBindingEvent event) {
        
// TODO Auto-generated method stub
        if(this.getLoginUserMessage() != null){
            loginUserPool.addLoginUserMessage(
this.getSessionId(),this.getLoginUserMessage());
            logger.info(
"用户信息加入缓存池成功");
        }

        
this.setLoginUserMessage(null);
    }


    
/* (non-Javadoc)
     * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
     
*/

    
public void valueUnbound(HttpSessionBindingEvent event) {
        
// TODO Auto-generated method stub
        if(!loginUserPool.isEmpty()){
            loginUserPool.removeLoginUserMessage(sessionId);
            logger.info(
"用户信息从缓存池中移除成功");
        }

    }


}


这样子的话,当在应用中把userLoginListener加入到session中时,就会自动把用户信息加入到缓冲池中了。
如:
 session.setAttribute("userLoginListener",userLoginListener);



(原创,转载请保留文章出处http://www.blogjava.net/bnlovebn/archive/2007/07/04/128006.html


posted @ 2007-07-04 08:59 重归本垒(Bing) 阅读(1879) | 评论 (1)编辑 收藏
 
最近好久没有看书了,是不是又要开始堕落了,上学时是三点一线,现在上班了,就是两点一线,更没劲。有时候真的不知道人活着是为了什么,挣钱吗?挣钱又是为了什么,为是家庭?为了房子?为了生活……
毕业了,家里人就整天嚷嚷——结婚,等结婚后又嚷嚷着——生孩子吧,生孩子了,又要抚养他,上学,长大,成年了,如果他还是不能自立,他又只能是吃你的,这时,他又找个女的一起吃你的,如果是生的是个女孩,那么她找个男的一起吃你的,还要给他们带孩子,等他们自立了,可能你也就安度晚年了,这时候,就是玩也玩不动,吃也吃不了了。
小时候,盼长大,读书时,盼毕业,以为毕业了就可以自己挣钱了,可以想怎么花就怎么花,可真上班了,又由不得你,可能你谈恋爱了,想买房了,想买车了。累一辈子,等什么都有的时候,老了。走不动了……
你上班,挣钱了,又用来消费了,最终这钱到哪去了,经济发达了,可生活好不上去,这是为什么,可能,不管你是老板还是工薪员工,不论你是在哪里上班,做什么职业,收入多少。最终的输家还是这些黎民百姓。赢的又会是谁呢……
不禁叹一声,唉…… 
posted @ 2007-07-02 08:39 重归本垒(Bing) 阅读(321) | 评论 (0)编辑 收藏
 
1、断箭

   不相信自己的意志,永远也做不成将军。

   春秋战国时代,一位父亲和他的儿子出征打战。父亲已做了将军,儿子还只是马前卒。又一阵号角吹响,战鼓雷鸣了,父亲庄严地托起一个箭囊,其中插着一只箭。父亲郑重对儿子说:“这是家袭宝箭,配带身边,力量无穷,但千万不可抽出来。”

   那是一个极其精美的箭囊,厚牛皮打制,镶着幽幽泛光的铜边儿,再看露出的箭尾。一眼便能认定用上等的孔雀羽毛制作。儿子喜上眉梢,贪婪地推想箭杆、箭头的模样,耳旁仿佛嗖嗖地箭声掠过,敌方的主帅应声折马而毙.

   果然,配带宝箭的儿子英勇非凡,所向披靡。当鸣金收兵的号角吹响时,儿子再也禁不住得胜的豪气,完全背弃了父亲的叮嘱,强烈的欲望驱赶着他呼一声就拔出宝箭,试图看个究竟。骤然间他惊呆了。

   一只断箭,箭囊里装着一只折断的箭。

   我一直刳着只断箭打仗呢!儿子吓出了一身冷汗,仿佛顷刻间失去支柱的房子,轰然意志坍塌了。

   结果不言自明,儿子惨死于乱军之中。

   拂开蒙蒙的硝烟,父亲拣起那柄断箭,沉重地啐一口道:“不相信自己的意志,永远也做不成将军。”

   把胜败寄托在一只宝箭上,多么愚蠢,而当一个人把生命的核心与把柄交给别人,又多么危险!比如把希望寄托在儿女身上;把幸福寄托在丈夫身上;把生活保障寄托在单位身上……

   温馨提示:自己才是一只箭,若要它坚韧,若要它锋利,若要它百步穿杨,百发百中,磨砺它,拯救它的都只能是自己。

   2、生命的价值

   不要让昨日的沮丧令明天的梦想黯然失色!

   在一次讨论会上,一位著名的演说家没讲一句开场白,手里却高举着一张20美元的钞票。

   面对会议室里的200个人,他问:“谁要这20美元?”一只只手举了起来。他接着说:“我打算把这20美元送给你们中的一位,但在这之前,请准许我做一件事。”他说着将钞票揉成一团,然后问:“谁还要?”仍有人举起手来。

   他又说:“那么,假如我这样做又会怎么样呢?”他把钞票扔到地上,又踏上一只脚,并且用脚碾它。尔后他拾起钞票,钞票已变得又脏又皱。

   “现在谁还要?”还是有人举起手来。

   “朋友们,你们已经上了一堂很有意义的课。无论我如何对待那张钞票,你们还是想要它,因为它并没贬值,它依旧值20美元。人生路上,我们会无数次被自己的决定或碰到的逆境击倒、欺凌甚至碾得粉身碎骨。我们觉得自己似乎一文不值。但无论发生什么,或将要发生什么,在上帝

的眼中,你们永远不会丧失价值。在他看来,肮脏或洁净,衣着齐整或不齐整,你们依然是无价之宝。”

   温馨提示:生命的价值不依赖我们的所作所为,也不仰仗我们结交的人物,而是取决于我们本身!我们是独特的——永远不要忘记这一点!

   3、昂起头来真美

   别看它是一条黑母牛,牛奶一样是白的。

   珍妮是个总爱低着头的小女孩,她一直觉得自己长得不够漂亮。有一天,她到饰物店去买了只绿色蝴蝶结,店主不断赞美她戴上蝴蝶结挺漂亮,珍妮虽不信,但是挺高兴,不由昂起了头,急于让大家看看,出门与人撞了一下都没在意。

   珍妮走进教室,迎面碰上了她的老师,“珍妮,你昂起头来真美!”老师爱抚地拍拍她的肩说。

   那一天,她得到了许多人的赞美。她想一定是蝴蝶结的功劳,可往镜前一照,头上根本就没有蝴蝶结,一定是出饰物店时与人一碰弄丢了。

   自信原本就是一种美丽,而很多人却因为太在意外表而失去很多快乐。

   温馨提示:无论是贫穷还是富有,无论是貌若天仙,还是相貌平平,只要你昂起头来,快乐会使你变得可爱——人人都喜欢的那种可爱。

   4、为生命画一片树叶

   只要心存相信,总有奇迹发生,希望虽然渺茫,但它永存人世。

   美国作家欧;亨利在他的小说《最后一片叶子》里讲了个故事:病房里,一个生命垂危的病人从房间里看见窗外的一棵树,在秋风中一片片地掉落下来。病人望着眼前的萧萧落叶,身体也随之每况愈下,一天不如一天。她说:“当树叶全部掉光时,我也就要死了。”一位老画家得知后,用彩笔画了一片叶脉青翠的树叶挂在树枝上。

   最后一片叶子始终没掉下来。只因为生命中的这片绿,病人竟奇迹般地活了下来。

   温馨提示:人生可以没有很多东西,却唯独不能没有希望。希望是人类生活的一项重要的价值。有希望之处,生命就生生不息!

   5、飞翔的蜘蛛

   信念是一种无坚不催的力量,当你坚信自己能成功时,你必能成功。

   一天,我发现,一只黑蜘蛛在后院的两檐之间结了一张很大的网。难道蜘蛛会飞?要不,从这个檐头到那个檐头,中间有一丈余宽,第一根线是怎么拉过去的?后来,我发现蜘蛛走了许多弯路–从一个檐头起,打结,顺墙而下,一步一步向前爬,小心翼翼,翘起尾部,不让丝沾到地面的沙石或别的物体上,走过空地,再爬上对面的檐头,高度差不多了,再把丝收紧,以后也是如此。

   温馨提示:蜘蛛不会飞翔,但它能够把网凌结在半空中。它是勤奋、敏感、沉默而坚韧的昆虫,它的网制得精巧而规矩,八卦形地张开,仿佛得到神助。这样的成绩,使人不由想起那些沉默寡言的人和一些深藏不露的智者。于是,我记住了蜘蛛不会飞翔,但它照样把网结在空中。奇迹是执着者造成的。

6、阴影是条纸龙

   人生中,经常有无数来自外部的打击,但这些打击究竟会对你产生怎样的影响,最终决定权在你手中。

   祖父用纸给我做过一条长龙。长龙腹腔的空隙仅仅只能容纳几只蝗虫,投放进去,它们都在里面死了,无一幸免!祖父说:“蝗虫性子太躁,除了挣扎,它们没想过用嘴巴去咬破长龙,也不知道一直向前可以从另一端爬出来。因而,尽管它有铁钳般的嘴壳和锯齿一般的大腿,也无济于事。

   ”当祖父把几只同样大小的青虫从龙头放进去,然后关上龙头,奇迹出现了:仅仅几分钟,小青虫们就一一地从龙尾爬了出来。

   温馨提示:命运一直藏匿在我们的思想里。许多人走不出人生各个不同阶段或大或小的阴影,并非因为他们天生的个人条件比别人要差多远,而是因为他们没有思想要将阴影纸龙咬破,也没有耐心慢慢地找准一个方向,一步步地向前,直到眼前出现新的洞天。

   7、成功并不像你想像的那么难

   并不是因为事情难我们不敢做,而是因为我们不敢做事情才难的。

   1965年,一位韩国学生到剑桥大学主修心理学。在喝下午茶的时候,他常到学校的咖啡厅或茶座听一些成功人士聊天。这些成功人士包括诺贝尔奖获得者,某一些领域的学术权威和一些创造了经济神话的人,这些人幽默风趣,举重若轻,把自己的成功都看得非常自然和顺理成章。时间长了,他发现,在国内时,他被一些成功人士欺骗了。那些人为了让正在创业的人知难而退,普遍把自己的创业艰辛夸大了,也就是说,他们在用自己的成功经历吓唬那些还没有取得成功的人。

   作为心理系的学生,他认为很有必要对韩国成功人士的心态加以研究。1970年,他把《成功并不像你想像的那么难》作为毕业论文,提交给现代经济心理学的创始人威尔;布雷登教授。布雷登教授读后,大为惊喜,他认为这是个新发现,这种现象虽然在东方甚至在世界各地普遍存在,但此前还没有一个人大胆地提出来并加以研究。惊喜之余,他写信给他的剑桥校友–当时正坐在韩国政坛第一把交椅上的人–朴正熙。他在信中说,“我不敢说这部著作对你有多大的帮助,但我敢肯定它比你的任何一个政令都能产生震动。”

   后来这本书果然伴随着韩国的经济起飞了。这本书鼓舞了许多人,因为他们从一个新的角度告诉人们,成功与“劳其筋骨,饿其体肤”、“三更灯火五更鸡”、“头悬梁,锥刺股”没有必然的联系。只要你对某一事业感兴趣,长久地坚持下去就会成功,因为上帝赋予你的时间和智慧够你做完一件事情。后来,这位青年也获得了成功,他成了韩国泛业汽车公司的总裁。

   温馨提示:人世中的许多事,只要想做,都能做到,该克服的困难,也都能克服,用不着什么钢铁般的意志,更用不着什么技巧或谋略。只要一个人还在朴实而饶有兴趣地生活着,他终究会发现,造物主对世事的安排,都是水到渠成的。

   8、永远的坐票

   生活真是有趣:如果你只接受最好的,你经常会得到最好的。

   有一个人经常出差,经常买不到对号入坐的车票。可是无论长途短途,无论车上多挤,他总能找到座位。

   他的办法其实很简单,就是耐心地一节车厢一节车厢找过去。这个办法听上去似乎并不高明,但却很管用。每次,他都做好了从第一节车厢走到最后一节车厢的准备,可是每次他都用不着走到最后就会发现空位。他说,这是因为像他这样锲而不舍找座位的乘客实在不多。经常是在他落座的车厢里尚余若干座位,而在其他车厢的过道和车厢接头处,居然人满为患。

   他说,大多数乘客轻易就被一两节车厢拥挤的表面现象迷惑了,不大细想在数十次停靠之中,从火车十几个车门上上下下的流动中蕴藏着不少提供座位的机遇;即使想到了,他们也没有那一份寻找的耐心。眼前一方小小立足之地很容易让大多数人满足,为了一两个座位背负着行囊挤来挤去有些人也觉得不值。他们还担心万一找不到座位,回头连个好好站着的地方也没有了。与生活中一些安于现状不思进取害怕失败的人,永远只能滞留在没有成功的起点上一样,这些不愿主动找座位的乘客大多只能在上车时最初的落脚之处一直站到下车。

   温馨提示:自信、执着、富有远见、勤于实践,会让你握有一张人生之旅永远的坐票。

   9、心中的顽石

   阻碍我们去发现、去创造的,仅仅是我们心理上的障碍和思想中的顽石。

   从前有一户人家的菜园摆着一颗大石头,宽度大约有四十公分,高度有十公分。到菜园的人,不小心就会踢到那一颗大石头,不是跌倒就是擦伤。

   儿子问:“爸爸,那颗讨厌的石头,为什么不把它挖走?”

   爸爸这么回答:“你说那颗石头喔?从你爷爷时代,就一直放到现在了,它的体积那么大,不知道要挖到到什么时候,没事无聊挖石头,不如走路小心一点,还可以训练你的反应能力。”

   过了几年,这颗大石头留到下一代,当时的儿子娶了媳妇,当了爸爸。

   有一天媳妇气愤地说:“爸爸,菜园那颗大石头,我越看越不顺眼,改天请人搬走好了。”

   爸爸回答说:“算了吧!那颗大石头很重的,可以搬走的话在我小时候就搬走了,哪会让它留到现在啊?”

   媳妇心底非常不是滋味,那颗大石头不知道让她跌倒多少次了。

   有一天早上,媳妇带着锄头和一桶水,将整桶水倒在大石头的四周。

   十几分钟以后,媳妇用锄头把大石头四周的泥土搅松。

   媳妇早有心理准备,可能要挖一天吧,谁都没想到几分钟就把石头挖起来,看看大小,这颗石头没有想像的那么大,都是被那个巨大的外表蒙骗了。

   温馨提示:你抱着下坡的想法爬山,便无从爬上山去。如果你的世界沉闷而无望,那是因为你自己沉闷无望。改变你的世界,必先改变你自己的心态。

   10、追求忘我

   不要把自己当做鼠,否则肯定被猫吃。

   1858年,瑞典的一个富豪人家生下了一个女儿。然而不久,孩子染患了一种无法解释的瘫痪症,丧失了走路的能力。

   一次,女孩和家人一起乘船旅行。船长的太太给孩子讲船长有一只天堂鸟,她被这只鸟的描述迷住了,极想亲自看一看。于是保姆把孩子留在甲板上,自己去找船长。孩子耐不住性子等待,她要求船上的服务生立即带她去看天堂鸟。那服务生并不知道她的腿不能走路,而只顾带着她一道去看那只美丽的小鸟。奇迹发生了,孩子因为过度地渴望,竟忘我地拉住服务生的手,慢慢地走了起来。从此,孩子的病便痊愈了。女孩子长大后,又忘我地投入到文学创作中,最后成为第一位荣获诺贝尔文学奖的女性,也就是茜尔玛?拉格萝芙。

   温馨提示:忘我是走向成功的一条捷径,只有在这种环境中,人才会超越自身的束缚,释放出最大的能量。 
posted @ 2007-06-27 09:24 重归本垒(Bing) 阅读(188) | 评论 (0)编辑 收藏
 
如果出现如下错误,则可能是Hibernate SQL方言 (hibernate.dialect)设置不正确。
Caused by: java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]'last_insert_id' 不是可以识别的 函数名。
RDBMS 方言
DB2 org.hibernate.dialect.DB2Dialect
DB2 AS/400 org.hibernate.dialect.DB2400Dialect
DB2 OS390 org.hibernate.dialect.DB2390Dialect
PostgreSQL org.hibernate.dialect.PostgreSQLDialect
MySQL org.hibernate.dialect.MySQLDialect
MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
Oracle (any version) org.hibernate.dialect.OracleDialect
Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
Sybase org.hibernate.dialect.SybaseDialect
Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect

posted @ 2007-06-26 11:53 重归本垒(Bing) 阅读(49473) | 评论 (0)编辑 收藏
 


建好SQL数据库,设置好了用户名与密码,连接也好了,却出现了上述问题, 原困是未设置SQL SERVER登录认证模式为混合认证模式,因为SQL SERVER默认安装后认证模式为WINDOWS认证模式,从而导致出错。

解决方法:
'www.knowsky.com
启动SQLSERVER企业管理器,选择要进行认证模式设置的服务器。右击该服务器,在弹出菜单中选择属性,SQL SERVER将弹出属性对话框
 

在属性对话框中选择安全性选项,在身份验证处选择“SQL Server和Windows”,然后确定。

posted @ 2007-06-25 15:06 重归本垒(Bing) 阅读(470) | 评论 (0)编辑 收藏
 
java.sql.SQLException: ORA-06502: PL/SQL: 数字或值错误
ORA-06512: 在"SCOTT.PKG_JT_CUST_BOOKING", line 28
ORA-06512: 在line 1

经查,原来是PKG_JT_CUST_BOOKING中的变量定义的太小了!
以至溢出。
posted @ 2007-05-21 18:21 重归本垒(Bing) 阅读(483) | 评论 (0)编辑 收藏
 

 <script language="javascript">

//验证给定的日期是否合法   ,参数格式要求:yyyy-mm-dd 可以根据情况更改正则表达式
function isDate(oStartDate)
{
    //对日期格式进行验证 要求为2000-2099年  格式为 yyyy-mm-dd 并且可以正常转换成正确的日期
    var pat_hd=/^20\d{2}-((0[1-9]{1})|(1[0-2]{1}))-((0[1-9]{1})|([1-2]{1}[0-9]{1})|(3[0-1]{1}))$/;
 
 try{
     if(!pat_hd.test(oStartDate)){throw "日期非法!";}
  var arr_hd=oStartDate.split("-");
  var dateTmp;
  dateTmp= new Date(arr_hd[0],parseFloat(arr_hd[1])-1,parseFloat(arr_hd[2]));
  if(dateTmp.getFullYear()!=parseFloat(arr_hd[0]) || dateTmp.getMonth()!=parseFloat(arr_hd[1]) -1 || dateTmp.getDate()!=parseFloat(arr_hd[2]))
  {
   throw "日期非法!";
  }
 }
 catch(ex)
 {
  if(ex.description)
   {return false;}
   else
    {return false;}
 }
 return true;
}

//调用

alert(isDate("2005-4-31"));
alert(isDate("2004-13-30"));
alert(isDate("2005-12-32"));
alert(isDate("2005-02-30"));

</script>

posted @ 2007-05-18 17:10 重归本垒(Bing) 阅读(537) | 评论 (0)编辑 收藏
 
<SCRIPT LANGUAGE="JavaScript">
<!--
function strRev(str)
{
return str.split("").reverse().join("")
}

alert(strRev("赵兄托我帮你办点事"))
//-->
</SCRIPT>
posted @ 2007-05-18 15:37 重归本垒(Bing) 阅读(1169) | 评论 (0)编辑 收藏
 



 

CREATE OR REPLACE PACKAGE SCOTT.pkg_test as
/* 定义ref cursor类型
不加return类型,为弱类型,允许动态sql查询,
否则为强类型,无法使用动态sql查询;
*/

type myrctype 
is ref cursor

--函数申明
function get(intID number , bbn out numberreturn myrctype;

Procedure getstudent( 
        intID 
number,
       return_list out myrctype 
  );

function getforpage(  
    Pcount out 
number,               --返回分页总数
    Pindex in number,                --分页索引   
    Psize in number,              --页面大小
    Pordby  in varchar               --排序字段
return myrctype;

Procedure getforpagep( 
    Pcount out 
number,               --返回分页总数
    return_list out myrctype,
    Pindex 
in number,                --分页索引   
    Psize in number,               --页面大小
    Pordby   in varchar               --排序字段
  );

end pkg_test;

CREATE OR REPLACE PACKAGE BODY SCOTT.pkg_test as
--函数体
    function get(intID number ,bbn out numberreturn myrctype is
        rc myrctype; 
--定义ref cursor变量
        sqlstr varchar2(500);
        
begin
            
if intID=0 then
                
--静态测试,直接用select语句直接返回结果
                open rc for select id,name,sex,address,postcode,birthday from student;
            
else
                
--动态sql赋值,用:w_id来申明该变量从外部获得
                sqlstr :='select id,name,sex,address,postcode,birthday from student where id=:w_id';
                
--动态测试,用sqlstr字符串返回结果,用using关键词传递参数
                open rc for sqlstr using intid;
            
end if;
        bbn :
= 0;
        
return rc;
    
end get;
    
  
Procedure getstudent( 
         intID 
number,
       return_list out myrctype 
  )
as 
   
   
begin 
       
open return_list
       
for 
        
select id,name,sex,address,postcode,birthday from student;
  
end getstudent; 



function getforpage(  
    Pcount out 
number,               --返回分页总数
    Pindex in number,                --分页索引   
    Psize in number,              --页面大小
    Pordby  in varchar               --排序字段
return myrctype
    
is
          rc myrctype; 
--定义ref cursor变量
          sqlstr varchar2(500);
          v_sql 
VARCHAR2(1000);
          v_count 
number;  
          v_Plow 
number;
          v_Phei 
number;
        
begin
            sqlstr :
='select id,name,sex,address,postcode,birthday from student';
              
------------------------------------------------------------取分页总数
              v_sql := 'select count(*) from (' || sqlstr || ')';
              
execute immediate v_sql into v_count;
              Pcount :
= ceil(v_count/Psize);
              
------------------------------------------------------------显示任意页内容
              v_Phei := Pindex * Psize + Psize;
              v_Plow :
= v_Phei - Psize + 1;
              
--Psql := 'select rownum rn,t.* from cd_ssxl t' ;            --要求必须包含rownum字段
              ---select * from (select rownum rn , t.* from  (select  t.* from student t) t )where rn between '2' and '3'
              v_sql := 'select id,name,sex,address,postcode,birthday from (select rownum rn , t.* from  (' || sqlstr || ') t order by '|| Pordby ||') where rn between ' || v_Plow || ' and ' || v_Phei ;

              
open rc for v_sql;
            
return rc;
    
end getforpage;




Procedure getforpagep( 
    Pcount out 
number,               --返回分页总数
    return_list out myrctype,
    Pindex 
in number,                --分页索引   
    Psize in number,               --页面大小
    Pordby  in varchar               --排序字段
  )as 
          rc myrctype; 
--定义ref cursor变量
          sqlstr varchar2(500);
          v_sql 
VARCHAR2(1000);
          v_count 
number;  
          v_Plow 
number;
          v_Phei 
number;
   
        
begin
            sqlstr :
='select id,name,sex,address,postcode,birthday from student';
              
------------------------------------------------------------取分页总数
              v_sql := 'select count(*) from (' || sqlstr || ')';
              
execute immediate v_sql into v_count;
              Pcount :
= ceil(v_count/Psize);
              
------------------------------------------------------------显示任意页内容
              v_Phei := Pindex * Psize + Psize;
              v_Plow :
= v_Phei - Psize + 1;
              
--Psql := 'select rownum rn,t.* from cd_ssxl t' ;            --要求必须包含rownum字段
              
              v_sql :
= 'select id,name,sex,address,postcode,birthday from (select rownum rn , t.* from  (' || sqlstr || ') t order by '|| Pordby ||' ) where rn between ' || v_Plow || ' and ' || v_Phei ;

              
open return_list for v_sql;
      
end getforpagep;


end pkg_test;
/

posted @ 2007-05-17 14:43 重归本垒(Bing) 阅读(398) | 评论 (0)编辑 收藏
 

 

create or replace package DotNet is

  
-- Author  : good_hy
  -- Created : 2004-12-13 13:30:30
  -- Purpose : 
  
  TYPE type_cur 
IS REF CURSOR;     --定义游标变量用于返回记录集
    
  
PROCEDURE DotNetPagination(      
  Pindex 
in number,                --分页索引   
  Psql in varchar2,                --产生dataset的sql语句
  Psize in number,                 --页面大小
  Pcount out number,               --返回分页总数
  v_cur out type_cur               --返回当前页数据记录
  );  
  
  
procedure DotNetPageRecordsCount(
  Psqlcount 
in varchar2,           --产生dataset的sql语句                           
  Prcount   out number             --返回记录总数
  );
  
end DotNot;

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

create or replace package body DotNet is

--***************************************************************************************

PROCEDURE DotNetPagination(
  Pindex 
in number,
  Psql 
in varchar2
  Psize 
in number,  
  Pcount out 
number,
  v_cur out type_cur
)
AS

  v_sql 
VARCHAR2(1000);
  v_count 
number;  
  v_Plow 
number;
  v_Phei 
number;
Begin
  
------------------------------------------------------------取分页总数
  v_sql := 'select count(*) from (' || Psql || ')';
  
execute immediate v_sql into v_count;
  Pcount :
= ceil(v_count/Psize);
  
------------------------------------------------------------显示任意页内容
  v_Phei := Pindex * Psize + Psize;
  v_Plow :
= v_Phei - Psize + 1;
  
--Psql := 'select rownum rn,t.* from cd_ssxl t' ;            --要求必须包含rownum字段
  --v_sql := 'select  *  from (select rownum rn , t.* from  (' || sqlstr || ') t) where rn between ' || v_Plow || ' and ' || v_Phei ;
      v_sql :
= 'select * from (' || Psql || ') where rn between ' || v_Plow || ' and ' || v_Phei ;

  
open v_cur for v_sql;
  
End DotNetPagination;

--**************************************************************************************

procedure DotNetPageRecordsCount(
  Psqlcount 
in varchar2,
  Prcount   out 
number
  )
  
as
  
   v_sql 
varchar2(1000);
   v_prcount 
number;
   
  
begin
  
   v_sql :
= 'select count(*) from (' || Psqlcount || ')';
   
execute immediate v_sql into v_prcount;
   Prcount :
= v_prcount;                  --返回记录总数                                                      
   
  
end DotNetPageRecordsCount;
  
--**************************************************************************************

end DotNot;
posted @ 2007-05-17 11:58 重归本垒(Bing) 阅读(287) | 评论 (0)编辑 收藏
 

 

CREATE OR REPLACE PACKAGE SCOTT.pkg_test as
/* 定义ref cursor类型
不加return类型,为弱类型,允许动态sql查询,
否则为强类型,无法使用动态sql查询;
*/

type myrctype 
is ref cursor

--函数申明
function get(intID numberreturn myrctype;
Procedure getstudent( 
        intID 
number,
       return_list out myrctype 
  );
end pkg_test;

==============================================

CREATE OR REPLACE PACKAGE BODY SCOTT.pkg_test as
--函数体
    function get(intID numberreturn myrctype is
        rc myrctype; 
--定义ref cursor变量
        sqlstr varchar2(500);
        
begin
            
if intID=0 then
                
--静态测试,直接用select语句直接返回结果
                open rc for select id,name,sex,address,postcode,birthday from student;
            
else
                
--动态sql赋值,用:w_id来申明该变量从外部获得
                sqlstr :='select id,name,sex,address,postcode,birthday from student where id=:w_id';
                
--动态测试,用sqlstr字符串返回结果,用using关键词传递参数
                open rc for sqlstr using intid;
            
end if;

        
return rc;
    
end get;
    
  
Procedure getstudent( 
         intID 
number,
       return_list out myrctype 
  )
as 
   
   
begin 
       
open return_list
       
for 
        
select id,name,sex,address,postcode,birthday from student;
  
end getstudent; 


end pkg_test;
/


 

        try {
            conn.setAutoCommit(
false);
            CallableStatement proc 
= conn
                    .prepareCall(
"{call  pkg_test.getstudent(?,?)}");
            proc.setInt(
11);
            proc.registerOutParameter(
2, OracleTypes.CURSOR);
            proc.execute();
            ResultSet rs 
= (ResultSet) proc.getObject(2);
            
while (rs.next()) {
                System.out.println(rs.getString(
2));
            }

        }
 catch (SQLException e) {
            
// TODO 自动生成 catch 块
            e.printStackTrace();
        }

        
try {
            conn.setAutoCommit(
false);
            CallableStatement proc 
= conn
                    .prepareCall(
"{call ? := pkg_test.get(?)}");
            proc.setInt(
20);
            proc.registerOutParameter(
1, OracleTypes.CURSOR);
            proc.execute();
            ResultSet rs 
= (ResultSet) proc.getObject(1);
            
while (rs.next()) {
                System.out.println(rs.getString(
2));
            }

        }
 catch (SQLException e) {
            
// TODO 自动生成 catch 块
            e.printStackTrace();
        }


 

posted @ 2007-05-17 11:48 重归本垒(Bing) 阅读(3832) | 评论 (0)编辑 收藏
 
测试过程:
1、建立测试表
CREATE TABLE student
(
id NUMBER,
name VARCHAR2(30),
sex VARCHAR2(10),
address VARCHAR2(100),
postcode VARCHAR2(10),
birthday DATE,
photo LONG RAW
)
/

2、建立带ref cursor定义的包和包体及函数:
CREATE OR REPLACE
package pkg_test as
/* 定义ref cursor类型
不加return类型,为弱类型,允许动态sql查询,
否则为强类型,无法使用动态sql查询;
*/
type myrctype is ref cursor;

--函数申明
function get(intID number) return myrctype;
end pkg_test;
/

CREATE OR REPLACE
package body pkg_test as
--函数体
function get(intID number) return myrctype is
rc myrctype; --定义ref cursor变量
sqlstr varchar2(500);
begin
if intID=0 then
--静态测试,直接用select语句直接返回结果
open rc for select id,name,sex,address,postcode,birthday from student;
else
--动态sql赋值,用:w_id来申明该变量从外部获得
sqlstr :='select id,name,sex,address,postcode,birthday from student where id=:w_id';
--动态测试,用sqlstr字符串返回结果,用using关键词传递参数
open rc for sqlstr using intid;
end if;

return rc;
end get;

end pkg_test;
/

3、用pl/sql块进行测试:
declare
w_rc pkg_test.myrctype; --定义ref cursor型变量

--定义临时变量,用于显示结果
w_id student.id%type;
w_name student.name%type;
w_sex student.sex%type;
w_address student.address%type;
w_postcode student.postcode%type;
w_birthday student.birthday%type;

begin
--调用函数,获得记录集
w_rc := pkg_test.get(1);

--fetch结果并显示
fetch w_rc into w_id,w_name,w_sex,w_address,w_postcode,w_birthday;
dbms_output.put_line(w_name);/*此处的put_line表示输出一行在屏幕上显示,假如想输出姓名和性别等,可以这样写dbms.output.putline(w_name||w_sex||w_address),而这样写dbms.output.putline(w_name||chr(10)||w_sex)则表示可以换行。*/
end;

4、测试结果:
通过。

在上述的online document中有相当多的内容,包括怎样在pro*c传递动态参数给存储过程、ref cusor的使用限制、open cursor for的4中不同方法等等。

转:http://hetingonion.spaces.live.com/blog/cns!DA3BAE0FAC0FE44F!115.entry

posted @ 2007-05-17 09:42 重归本垒(Bing) 阅读(709) | 评论 (0)编辑 收藏
 


如何利用网页弹出各种形式的窗口,我想大家大多都是知道些的,但那种多种多样的弹出式窗口是怎么搞出来的,我们今天就来学习一下:

  1.弹启一个全屏窗口

<html>
<body onload="window.open('http://www.baidu.com','example01','fullscreen');">;
<b>www.188sky.com</b>
</body>
</html>

  2.弹启一个被F11化后的窗口

<html>
<body onload="window.open(''http://www.baidu.com','example02','channelmode');">;
<b>www.188sky.com</b>
</body>
</html>

  3.弹启一个带有收藏链接工具栏的窗口

<html>
<body onload="window.open('www.baidu.com','example03','width=400,height=300,directories');">
<b>www.baidu.com</b>
</body>
</html>

  4.网页对话框

<html>
<SCRIPT LANGUAGE="javascript">
<!--
showModalDialog('http://www.baidu.com,'example04','dialogWidth:400px;dialogHeight:300px;
dialogLeft:200px;dialogTop:150px;center:yes;help:yes;resizable:yes;status:yes')
//-->
</SCRIPT>
<b>www.188sky.com</b>
</body>
</html>

<html>
<SCRIPT LANGUAGE="javascript">
<!--
showModelessDialog('http://www.baidu.com,'example05','dialogWidth:400px;dialogHeight:300px;
dialogLeft:200px;dialogTop:150px;center:yes;help:yes;resizable:yes;status:yes')
//-->
</SCRIPT>
<b>http://www.baidu.com</b>
</body>
</html>

  showModalDialog()或是showModelessDialog() 来调用网页对话框,至于showModalDialog()与showModelessDialog()的区别,在于showModalDialog()打开的窗口(简称模式窗口),置在父窗口上,必须关闭才能访问父窗口(建议尽量少用,以免招人反感);showModelessDialog()

dialogHeight: iHeight 设置对话框窗口的高度。
dialogWidth: iWidth 设置对话框窗口的宽度。   
dialogLeft: iXPos 设置对话框窗口相对于桌面左上角的left位置。
dialogTop: iYPos 设置对话框窗口相对于桌面左上角的top位置。
center: {yes | no | 1 | 0 } 指定是否将对话框在桌面上居中,默认值是“yes”。
help: {yes | no | 1 | 0 } 指定对话框窗口中是否显示上下文敏感的帮助图标。默认值是“yes”。   
resizable: {yes | no | 1 | 0 } 指定是否对话框窗口大小可变。默认值是“no”。
status: {yes | no | 1 | 0 } 指定对话框窗口是否显示状态栏。对于非模式对话框窗口,默认值是“yes”;对于模式对话框窗口,默认值是 “no”。

5、其他弹出窗口代码

经常上网的朋友可能到过这样一些网站,一进入首页立刻会弹出一个窗口,或者按一个链接或按钮弹出,通常在这个窗口里会显示一些注意事项、版权信息、警告、欢迎光顾之类的话或者作者想要特别提示的信息。其实制作这样的页面非常容易,只要往该页面的HTML里加入几段java script代码即可实现。下面我就带你剖析它的奥秘。

【最基本的弹出窗口代码】
其实代码非常简单:
<SCRIPT LANGUAGE="java script">
<!--
window.open (’page.html’)
-->
</SCRIPT>
因为这是一段java script代码,所以它们应该放在<SCRIPT LANGUAGE ="java script">标签和</script>之间。<!--和-->是对一些版本低的浏览器起作用,在这些老浏览器中如果不支持java script,不会将标签中的代码作为文本显示出来。
Window.open (’page.html’)用于控制弹出新的窗口page.html,如果page.html不与主窗口在同一路径下,前面应写明路径,绝对路径(http://)和相对路径(../)均可。
用单引号和双引号都可以,只是不要混用。
这一段代码可以加入HTML的任意位置,加入到<head>和</head>之间也可以,位置越靠前执行越早,尤其是页面代码较长时,又想使页面早点弹出就尽量往前放。

【经过设置后的弹出窗口】
下面再说一说弹出窗口外观的设置。只要再往上面的代码中加一点东西就可以了。
我们来定制这个弹出窗口的外观、尺寸大小、弹出位置以适应该页面的具体情况。
<SCRIPT LANGUAGE="java script:>
<!--
window.open (’page.html’,’newwindow’,’height=100,width=400,top=0,left=0,toolbar=no,menubar=no,scrollbars=no,resizable=no,
location=no,status=no’)
//写成一行
-->
</SCRIPT>
参数解释:
<SCRIPT LANGUAGE="java script"> js脚本开始;
window.open 弹出新窗口的命令;
page.html 弹出新窗口的文件名;
newwindow 弹出窗口的名字(不是文件名),可用空 ″代替;
height=100 窗口高度;
top=0 窗口距离屏幕上方的像素值;
left=0 窗口距离屏幕左侧的像素值;
toolbar=no 是否显示工具栏,yes为显示;
menubar,scrollbars 表示菜单栏和滚动栏;
resizable=no 是否允许改变窗口大小,yes为允许;
location=no 是否显示地址栏,yes为允许;
status=no 是否显示状态栏内的信息(通常是文件已经打开),yes为允许;
</SCRIPT> js脚本结束。

【用函数控制弹出窗口】
下面是一个完整的代码。
<html>
<head>
<script LANGUAGE="java script">
<!--
function openwin(){
window.open("page.html","newwindow","height=100,width=400,toolbar=no,menubar=no,scrollbars=no,resizable=no,
location=no,status=no";)
//写成一行
}
-->
</script>
</head>
<body onload="openwin()">
...任意的页面内容...
</body>
</html>
这里定义了一个函数openwin(),函数内容就是打开一个窗口。在调用它之前没有任何用途。怎么调用呢?
方法一:<body onload="openwen()"> 浏览器读页面时弹出窗口;
方法二:<body onunload="openwen()"> 浏览器离开页面时弹出窗口;
方法三:用一个连接调用:<a href="#" onclick="openwin()">打开一个窗口</a>
注意:使用的"#"是虚连接。
方法四:用一个按钮调用:<input type="button" onclick="openwin()" value="打开窗口">

【主窗口打开文件1.htm,同时弹出小窗口page.html】
将如下代码加入主窗口<head>区:
<script language="java script">
<!--
function openwin(){
window.open("page.html","","width=200,height=200" ;)
}
//-->
</script>
加入<body>区:<a href="1.htm" onclick="openwin()">open</a>即可。

【弹出的窗口之定时关闭控制】
下面我们再对弹出窗口进行一些控制,效果就更好了。如果我们再将一小段代码加入弹出的页面(注意是加入到page.html的HTML中,可不是主页面中,否则…),让它在10秒钟后自动关闭是不是更酷了?
首先,将如下代码加入page.html文件的<head>区:
<script language="java script">
function closeit() {
setTimeout("self.close()",10000) //毫秒
}
</script>
然后,再用<body onload="closeit()">这一句话代替page.html中原有的<BODY>这一句就可以了。(这一句话千万不要忘记写啊!这一句的作用是调用关闭窗口的代码,10秒钟后就自行关闭该窗口。)

【在弹出窗口中加上一个关闭按钮】
<form>
<INPUT TYPE=’BUTTON’ value=’关闭’ onClick=’window.close()’>
</form>
呵呵,现在更加完美了!
【内包含的弹出窗口——一个页面两个窗口】
上面的例子都包含两个窗口,一个是主窗口,另一个是弹出的小窗口。
通过下面的例子,你可以在一个页面内完成上面的效果。
<html>
<head>
<SCRIPT LANGUAGE="java script">
function openwin()
{
OpenWindow=window.open("","newwin","height=250,width=250,toolbar=no,scrollbars="+scroll+",menubar=no";);
//写成一行
OpenWindow.document.write("<TITLE>例子</TITLE>" ;)
OpenWindow.document.write("<BODY BGCOLOR=#FFFFFF>" ;)
OpenWindow.document.write("<H1>Hello!</h1>" ;)
OpenWindow.document.write("New window opened!" ;)
OpenWindow.document.write("</BODY >" ;)
OpenWindow.document.write("</HTML>" ;)
OpenWindow.document.close()
}
</script>
</head>
<body>
<a href="#" onclick="openwin()">打开一个窗口</a>
<input type="button" onclick="openwin()" value="打开窗口">
</body>
</html>
看看OpenWindow.document.write()里面的代码不就是标准的HTML吗?只要按照格式写更多的行即可。千万注意多一个标签或少一个标签都会出现错误。记住用OpenWindow.document.close()结束啊。

【终极应用——弹出窗口的Cookie控制】
回想一下,上面的弹出窗口虽然酷,但是有一点小毛病(你沉浸在喜悦之中,一定没有发现吧?)比如你将上面的脚本放在一个需要频繁经过的页面里(例如首页),那么每次刷新这个页面,窗口都会弹出一次,是不是非常烦人?有解决的办法吗?Yes!Follow me。我们使用Cookie来控制一下就可以了。
首先,将如下代码加入主页面HTML的<HEAD>区:

<script>
function openpopup(){
window.open("hello.htm","","width=300,height=300") //自己修改弹出窗口
}

function get_cookie(Name) {
var search = Name + "="
var returnvalue = "";
if (documents.cookie.length > 0) {
offset = documents.cookie.indexOf(search)
if (offset != -1) { // if cookie exists
offset += search.length
// set index of beginning of value
end = documents.cookie.indexOf(";", offset);
// set index of end of cookie value
if (end == -1)
end = documents.cookie.length;
returnvalue=unescape(documents.cookie.substring(offset, end))
}
}
return returnvalue;
}

function loadpopup(){
if (get_cookie('popped')==''){
openpopup()
documents.cookie="popped=yes"
}
}

</script>
</head>

将如下代码键入BODY区:
<body onunload="loadpopup()"> //pop when leave page
或者:
<body onload="loadpopup()"> //pop when enter page

你可以试着刷新一下这个页面或重新进入该页面,窗口再也不会弹出了。真正的Pop-Only-Once!
写到这里,弹出窗口的制作和应用技巧基本上算是讲完了,希望对正在制作网页的朋友有所帮助我就非常欣慰了。
需要注意的是,JS脚本中的大小写最好前后保持一致。

没有菜单、工具栏、地址栏的弹出窗口:

<script language="java script">
<!--
var gt = unescape(’%3e’);
var popup = null;
var over = "Launch Pop-up Navigator";
popup = window.open(’’, ’popupnav’, ’width=500,height=500,resizable=0,scrollbars=auto’); // width=500,height=500为窗口长和宽
if (popup != null) {
if (popup.opener == null) {
popup.opener = self; }
popup.location.href = ’要打开的文件名’;
}
// -->
</script>


方法二:Cookies应用:控制弹出窗口 当我们在一个页面中设置一个POP弹出窗口后,每次只要重新浏览该页面,POP窗口就会自动弹出来,造成不必要的麻烦。那么怎么解决这个问题呢? 我在这里用一个简单的例子讲解一下如何通过操作Cookies让弹出窗口只在第一次浏览该页面时弹出,以后就不再招人烦了!
<script> function openpopwindow() { window.open("hello.htm","","width=200,height=200" //自己修改弹出窗口 } function get_cookie(Name) { var search = Name + "="; var returnvalue = ""; if (documents.cookie.length > 0) { offset = documents.cookie.indexOf(search); if (offset != -1) { // 如果以前有cookies记录 offset += search.length; // 设置cookie的起始位置 end = documents.cookie.indexOf(";", offset); // 设置cookie的结束位置 if (end == -1) end = documents.cookie.length; returnvalue=unescape(documents.cookie.substring(offset, end)) } } return returnvalue; } function loadpopup() { if (get_cookie('popped')=='') { openpopwindow(); documents.cookie="popped=yes"; } } </script>

将上面的代码键入BODY区: <body onunload="loadpopup()"> //离开页面的时候弹出
或者: <body onload="loadpopup()"> //打开页面的时候弹出
【本文版权归作者与奥索网共同拥有,如需转载,请注明作者及出处】

离开页面时弹开窗口效果:

效果:别人关闭这个页面的时候,弹出一个窗口,你可以写一些祝福的话
核心代码:
<script LANGUAGE="javascript">
<!--Begin function leave(){
window.open
('1.htm',",'toolbar=no,menubar=no,location=no,height=225,width=235');
break
}
//END-->
</script>

posted @ 2007-05-08 13:28 重归本垒(Bing) 阅读(493) | 评论 (0)编辑 收藏
 

系统是windows server 2003 pro sp2.启动时出现了问题:

应用程序-特定 权限设置未将 COM 服务器应用程序(CLSID 为 {BA126AD1-2166-11D1-B1D0-00805FC1270E})的 本地 激活 权限授予用户 NT AUTHORITYNETWORK SERVICE SID (S-1-5-20)。可以使用组件服务管理工具修改此安全权限。

看此提示,于是用Google搜,相关结果很多,但是没有一个好用的,不过最终还是找到一个:

23. 事件查看器里报DCOM出错,如何解决?

根据提示信息,实际上是说NETWORK SERVICE没权限激活CLSID为{BA126AD1-2166-11D1-B1D0-00805FC1270E}的应用程序。可以通过使用组件服务管理工具修改此安全权限。
1、如果按上面的提示去使用组件服务管理工具找CLSID为{BA126AD1-2166-11D1-B1D0-00805FC1270E}的应用程序是找不到的。
2、需要先运行regedit.exe在注册表中查找出{BA126AD1-2166-11D1-B1D0-00805FC1270E}对应的AppID值{27AF75ED-20D9-11D1-B1CE-00805FC1270E}
3、然后再打开组件服务,查看方式为详细信息,找到DCOM 配置里的netman,选中按鼠标右建选属性。
4、在netman属性里的安全 -> “启动和激活权限” -> 自定义编辑,在启动权限里加入NETWORK SERVICE用户,允许本地启动和本地激活,确定后就不会再报这个DCOM错了。

posted @ 2007-04-10 15:34 重归本垒(Bing) 阅读(3226) | 评论 (1)编辑 收藏
 

以前都是用ant来编辑和发布项目。

今天用MyEclipse来重构gzmf,并发布这个项目时,碰到了'DWRUtil'未定义的情况。

网上说,只是加入xalan.jar就可以解决问题,在我这里还不能完全解决问题。

后来才发现,在MyEclipse把加入构建路径的包全部都发布了,而有些包在tomcat的common\lib已经有了,MyEclipse又发布在应用的web-inf\lib下,于是就产生了冲突。

于是在web-inf\lib下把dfc.jar和dfcbase.jar删了后,正常了。但是每次发布后都要来重新删一下这两个包,多麻烦。要是有一个即可以在MyEclipse编辑项目,但MyEclipse又不会把它发布到应用中去的方法。心想MyEclipse应该会提供一个设置全局jar的东东的吧,可是找好久没找到。

后来发现在windows->refernce->java->以安装的jae。把dfc.jar和dfcbase.jar添加到JRE系统库当中去。
编译-发布-运行。完全正确!!

可是把包加入到这里,心里别扭的很,不知各位还有没有什么更好的解决方法!

还有一个问题就是,每次改变了一个文件都要重新发布应用,都要重新启动tomcat,这样调试应用,那不是累死人去了。有没有什么更好的办法。

posted @ 2007-04-05 17:41 重归本垒(Bing) 阅读(4732) | 评论 (7)编辑 收藏
 
如果出现“无法使用此产品的安装源,请确认安装源存在,并且您可以访问它”

打开控制面板---管理工具,双击“本地安全设置”,打开“软件限制策略”,如果是空的,新建一个策略,然后双击“强制”,将第2个勾选由“所有用户”改为“除本地管理员以外的所有用户”

再安装即可。


posted @ 2007-04-04 09:34 重归本垒(Bing) 阅读(30089) | 评论 (13)编辑 收藏
 
     摘要: 一、先看目录结构。-xfire   +src   -war      -WEB-INF         +class      &...  阅读全文
posted @ 2007-03-30 10:11 重归本垒(Bing) 阅读(3597) | 评论 (2)编辑 收藏
 

开春了,上班了,今年的天气好怪,感觉年还没有过完就又要忙了,感觉冬天还没有过完夏天就来了。热的要命,别人都穿单衣了,我还身着一件薄毛衣,外加一茄克。反应太慢了。
今天这里的最高温度比广州还要高一度,热的我够呛的。初6在火车上时,也是这样子的,又热,又臭,又累。还好只有10个小时,早上出门晚上就要贵阳了。
那天,意外的收到了大表M的短信。以前都没有打过电话,也没怎么联系过的,开始还不太相信。
长大了,表妹也长大,也要出去闯世界了,也要为了生活而努力奋斗了。表妹长的很漂亮,很清秀。记得表妹出生那年,我妈带着我去看坐月子的姨,临走时,姨妈给了我一个红包。回来的路上,另外几个姨不知道是怎么骗我,我就把红包扔了,还弄的妈折回去把它给检回来了。现在想来,好搞笑。
记忆中,我和表妹他们也怎么相处过,可能是相隔有点远,只有春节拜年时,暑假时才有机会见过面。记忆中有一次一起玩过牌吧。

posted @ 2007-02-28 15:19 重归本垒(Bing) 阅读(171) | 评论 (0)编辑 收藏
 

春节过完年回来,票不好买,不过总的来说,南飘,东飘,北飘都不好买票,西飘好买票点,不过也是无座的票,害我站了十多个小时,就算有时和人家挤一下,也是只能坐到半个屁股。腰酸背疼,腿肚子发软,最后站也不是,坐也不是。
弟也排了两天队了,汽车票买不到,火车票也买不到。说坐飞机,也没飞机做。就算有,可能也是一票难求。搞不好就叫他加入西漂一族好了,在哪不是打工呀,还能给我们国家开发西部做点贡献。
回到家那天都大年三十了,头晚在小县城的汽车站住了个晚上,睡不好,安倒是安全就是脏,还有异味,被子上还有血。一直搞到两点多才睡,不过便宜,才十五,还有一台彩电,比弟昨晚住的便宜一点,安全一点。

posted @ 2007-02-25 14:24 重归本垒(Bing) 阅读(285) | 评论 (0)编辑 收藏
 

明天回家!
年底一分钱都没有发,气人!郁闷!
她老哥和嫂子吵架,夹中间好尴尬。脾气太坏了。

posted @ 2007-02-15 11:50 重归本垒(Bing) 阅读(175) | 评论 (0)编辑 收藏
 

     情人节,又到了,跑到沃尔玛给女朋友买了一盒巧克力,德芙的,也不贵,几十块钱,两年多了,从来也没有给她买过巧克力。其实也不是给她什么惊喜的,不贵。再说了,现在是贫困时期,她嘴上说,现在没钱,什么都不要买,可是一年才一次的情人节,我还是要买的,俗是俗了点,可是在这方面的脑袋不是很灵光,俗就俗吧,管它的,今年还是有进步了,有勇气在情人节给她买礼物了。



    去年情人节,我们俩还在遵义,在街上是逛了一圈又一圈,看着街上好多女孩子都满脸幸福的捧着花,我们好羡慕哦,说实在的我也好想给她买,可是始终是鼓不起勇气,看到满大街都是卖花的,可是就是下不了决心……。结果我俩两手空空的回来了,一路上她都不说话,她是生气了,这时我想,我一个大男人,怕什么,天塌下来都不怕,还怕买这花了,算什么人嘛!于是就下定决心给她买了,一下车,我让她先回去,我跑去找花店,可这时11点多了,情人节都快过去了,哪家花店还开门啦,就算是门开着,恐怕没花了,恐怕只剩下些残花败絮了。天助我也,运气不坏,有家花店还开门,哦,还是全国联网送花的呢,大花店,碰巧还有花,老板说今天的花太好卖了,没多少了,剩下的这几束是人家订了,临时没时间,就没来拿了,虽说是剩下,可花挺好的,包装精致。太好了。让老板给我挑了最好的一捧。花了一百来块钱吧。买好了,又担心路上会碰到熟人,担惊受怕的一路小跑,还好没有碰到。只是感觉大门口那小卖部老板的眼神有点怪。

 

    情人节,只要是有感情的人都是情人,都可以过情人节,都可以送礼物,可以接受礼物。情人节快乐……

    亲爱的,祝你情人节快乐……

    祝天下有情人都快乐……

posted @ 2007-02-14 14:54 重归本垒(Bing) 阅读(273) | 评论 (0)编辑 收藏
 
采用Web自动加载TimerManager来管理Timer链,在Class更新服务器热加载后会发生异常。这要求对TimerManager进行一些特殊的处理才能保证Timer链的正确性。
  
  使用Spring framework中提供的TimerTask自动加载功能可以非常容易的实现定时器链的管理。同时,采用Spring framework的这一功能可以非常容易的对定时器进行添加、删除。
  
  1.在Web.xml中申明
  
  <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/schedulingContext-timer.xml</param-value>
  </context-param>
  <servlet>
  <servlet-name>context</servlet-name>
  <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
  <load-on-startup>3</load-on-startup>
  </servlet>
  
  2.在schedulingContext-timer.xml描述用户的定时器
  
  <bean id="timer" class="org.springframework.scheduling.timer.TimerFactoryBean">
  <property name="scheduledTimerTasks">
  <list>
  <ref local="JorwangScheduledTimerTask1"/>
  </list>
  </property>
  </bean>
  
  <bean id="JorTimeTask1" class="workflow.common.MyTimer">
  </bean>
  <bean id="JorwangScheduledTimerTask1" class="org.springframework.scheduling.timer.ScheduledTimerTask">
  <property name="timerTask"><ref bean="JorTimeTask1"/></property>
  <property name="delay"><value>10000</value></property>
  <property name="period"><value>86400000</value></property>
  </bean>
  
  3.编写workflow.common.MyTimer定时器
  
  这样就轻松完成了定时器的功能。如果需要修改、增加、删除定时器,只需要对2、3步的内容进行调整就可以实现。
 注:转自http://www.bitscn.com/java/spring/200605/23091.html
posted @ 2007-02-12 15:47 重归本垒(Bing) 阅读(282) | 评论 (0)编辑 收藏
 
1。最直接最简单的,方式是把文件地址直接放到html页面的一个链接中。这样做的缺点是把文件在服务器上的路径暴露了,并且还无法对文件下载进行其它的控制(如权限)。这个就不写示例了。
2。在服务器端把文件转换成输出流,写入到response,以response把文件带到浏览器,由浏览器来提示用户是否愿意保存文件到本地。(示例如下)
<%
 response.setContentType(fileminitype);
 response.setHeader(
"Location",filename);
 response.setHeader(
"Cache-Control""max-age=" + cacheTime);
 response.setHeader(
"Content-Disposition""attachment; filename=" + filename); //filename应该是编码后的(utf-8)
 response.setContentLength(filelength);
 OutputStream outputStream 
= response.getOutputStream();
 InputStream inputStream 
= new FileInputStream(filepath);
 
byte[] buffer = new byte[1024];
 
int i = -1;
 
while ((i = inputStream.read(buffer)) != -1) {
  outputStream.write(buffer, 
0, i);
  }
 outputStream.flush();
 outputStream.close();
 inputStream.close();
 outputStream 
= null;

%>

3。既然是JSP的话,还有一种方式就是用Applet来实现文件的下载。不过客户首先得信任你的这个Applet小程序,由这个程序来接受由servlet发送来的数据流,并写入到本地。
servlet端示例
    public void service(HttpServletRequest req, HttpServletResponse res)
            
throws ServletException, IOException {
        res.setContentType(
" text/plain ");
        OutputStream outputStream 
= null;
        
try {
            outputStream 
= res.getOutputStream();
            popFile(srcFile, outputStream)) ;
//把文件路径为srcFile的文件写入到outputStream中。
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 

JApplet端示例
   URLConnection con;
        
try {
            con 
= url.openConnection();//url是被调用的SERVLET的网址 如http://localhost:8080/sendDateSevlet.do  
            con.setUseCaches(false);
            con.setDoInput(
true);
            con.setDoOutput(
true);
            con.setRequestProperty(
"Content-Type",
                
"application/octet-stream");
            InputStream in 
= con.getInputStream();
            ProgressMonitorInputStream pmInputStream 
= new ProgressMonitorInputStream(
                    pane, 
"正在从服务器下载文件内容", in);
            ProgressMonitor pMonitor 
= pmInputStream
                    .getProgressMonitor();
            pMonitor.setMillisToDecideToPopup(
3);
            pMonitor.setMillisToPopup(
3);
            String localfilepath 
= localstr + filename ;//localfilepath本地路径,localstr文件文件夹,filename本地文件名
     if(saveFilsaveFilee(localfilepath,pmInputStream)){ //方法saveFilsaveFilee是把输入流pmInputStream写到文件localfilepath中。                    
     openLocalFile(localfilepath);
            }



4。顺便把JApplet上传文件的代码也贴上来.
JApplet端示例

URLConnection con;
        
try {
            con 
= url.openConnection();//url是被调用的SERVLET的网址 如http://localhost:8080/sendDateSevlet.do         
     con.setUseCaches(false);
            con.setDoInput(
true);
            con.setDoOutput(
true);
            con.setRequestProperty(
"Content-Type",
                
"application/octet-stream");
            
            OutputStream out 
= con.getOutputStream();
            String localfilepath 
= localstr + filename; //localfilepath本地路径,localstr文件文件夹,filename本地文件名
            getOutputStream(localfilepath,out);//文件getOutputStream是把文件localfilepath写到输出流out中。
            InputStream in = con.getInputStream();
            
return true;
        }
catch (IOException e) {
               System.out.println(
"文件上传出错!");
            e.printStackTrace();
        }

servlet端代码示例
    public void service(HttpServletRequest req, HttpServletResponse res)
            
throws ServletException, IOException {
        res.setContentType(
" text/plain ");
        InputStream inputStream 
= null;
        
try {
            inputStream 
= res.getInputStream();
            writefile(srcFile, inputStream);
//把输入流inputStream保存到文件路径为srcFile的文件中
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 
// end service

 总结:在文件的传输中是流的形式存在的,在硬盘上是文件的形式存在的。我们要做的只是通过HttpServletRequest和HttpServletResponse,或者是response和request来发送流和读取流。以及把文件转换成流或把流转换成文件的操作。
posted @ 2007-02-12 13:41 重归本垒(Bing) 阅读(2537) | 评论 (3)编辑 收藏
 

 

正则表达式语法

一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

这里有一些可能会遇到的正则表达式示例:

JScript VBScript 匹配
/^\[ \t]*$/ "^\[ \t]*$" 匹配一个空白行。
/\d{2}-\d{5}/ "\d{2}-\d{5}" 验证一个ID 号码是否由一个2位数字,一个连字符以及一个5位数字组成。
/<(.*)>.*<\/\1>/ "<(.*)>.*<\/\1>" 匹配一个 HTML 标记。

下表是元字符及其在正则表达式上下文中的行为的一个完整列表:

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} mn 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern) 匹配pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y 匹配 xy。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。 x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个后向引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为后向引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个后向引用。如果 \nm 之前至少有is preceded by at least nm 个获取得子表达式,则 nm 为后向引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的后向引用。如果前面的条件都不满足,若  nm 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm
\nml 如果 n 为八进制数字 (0-3),且 ml 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。
posted @ 2007-01-30 11:17 重归本垒(Bing) 阅读(854) | 评论 (0)编辑 收藏
 
方式一:事先写好多个input.在点击时才显示。也就是说上传的最大个数是写死了的。
 html
<p>
<href='#' onclick='javascript:viewnone(more1)'> 添加附件 </a>
<div id='more1' style='display:none'>
    
<input type="file" name="attach1" size="50"javascript:viewnone(more2)>
    
</span>
</div>
<div id='more2' style='display:none'>
    
<input type="file" name="attach2" size="50"'>
</div>
</p>
js
<SCRIPT language="javascript">
  
function viewnone(e){
    e.style.display
=(e.style.display=="none")?"":"none";
  }
</script>

方式二:这种方式的动态多文件上传是实现了的,很简单的,不说废话看code
html
<input type="button" name="button" value="添加附件" onclick="addInput()">
<input type="button" name="button" value="删除附件" onclick="deleteInput()">
<span id="upload"></span>
js
<script type="text/javascript">
        
var attachname = "attach";
        
var i=1;
          
function   addInput(){
            
if(i>0){
                  
var attach = attachname + i ;
                  
if(createInput(attach))
                      i
=i+1;
              }
              
          } 
          
function deleteInput(){
                  
if(i>1){
                    i
=i-1;
                    
if(!removeInput())
                        i
=i+1;
                }
          } 
          
          
function createInput(nm){   
              
var  aElement=document.createElement("input");   
             aElement.name
=nm;
             aElement.id
=nm;
             aElement.type
="file";
             aElement.size
="50";
              
//aElement.value="thanks";   
             //aElement.onclick=Function("asdf()");  
               if(document.getElementById("upload").appendChild(aElement) == null)
                      
return false;
               
return true;
          }  

          
function removeInput(nm){
               
var aElement = document.getElementById("upload");
                
if(aElement.removeChild(aElement.lastChild) == null)
                    
return false;
                
return true;   
          }  
          
</script>

方式三:动态多文件上传,只是在oFileInput.click();这个地方,这样做就不能上传这个文件了,因为发现它在上传之时就把这个input中的文件置空了。很可能是为了安全着想吧!
另外还有一点就是说,click()只有在ie中才能正常运行。
虽说这种方式最终没能实现上传,但还是留下来参考,看看是否有人可以真正实现上传。
 html
<href="javascript:newUpload();">添加附件</A>
<TABLE width="100%" border="0" cellpadding="0" cellspacing="1">
    
<TBODY id="fileList"></TBODY>
</TABLE>
<DIV id="uploadFiles" style="display:block"></DIV>
js
<SCRIPT language="javascript">

    
//---新建上传
    function newUpload(){
        
var oFileList = document.getElementById("fileList");
        
var fileCount = oFileList.childNodes.length + 1;
        
var oFileInput = newFileInput("upfile_" + fileCount);
        
if(selectFile(oFileInput)){
            addFile(oFileInput);
        }
    }
    
    
    
//----选择文件
    function selectFile(oFileInput){
        
var oUploadFiles = document.getElementById("uploadFiles");
        oUploadFiles.appendChild(oFileInput);
        oFileInput.focus();
        oFileInput.click();
//不能这样做,可能是为了安全着想吧!
        var fileValue = oFileInput.value;
        
if(fileValue == ""){
            oUploadFiles.removeChild(oFileInput);
            
return false;
        }
        
else
         
return true;
        
    }
    
    
//---新建一个文件显示列表
    function addFile(oFileInput){
        
var oFileList = document.getElementById("fileList");
        
var fileIndex = oFileList.childNodes.length + 1;
        
var oTR  = document.createElement("TR");
        
var oTD1 = document.createElement("TD");
        
var oTD2 = document.createElement("TD");
        
        oTR.setAttribute(
"id","file_" + fileIndex);
        oTR.setAttribute(
"bgcolor","#FFFFFF");
        oTD1.setAttribute(
"width","6%");
        oTD2.setAttribute(
"width","94%");
        oTD2.setAttribute(
"align","left");
        oTD2.innerText 
= oFileInput.value;
        oTD1.innerHTML 
= '<A href="javascript:removeFile('+ fileIndex + ');">删除</A>';
        
        oTR.appendChild(oTD1);
        oTR.appendChild(oTD2);
        oFileList.appendChild(oTR);
    }
    
    
//---移除上传的文件 
    function removeFile(fileIndex){
        
var oFileInput = document.getElementById("upfile_" + fileIndex);
        
var oTR        = document.getElementById("file_" + fileIndex);
        uploadFiles.removeChild(oFileInput);
        fileList.removeChild(oTR);
    }
    
    
//---创建一个file input对象并返回
    function newFileInput(_name){
        
var oFileInput  = document.createElement("INPUT");
        oFileInput.type 
= "file";
        oFileInput.id 
= _name;
        oFileInput.name 
= _name;
        oFileInput.size
="50";
        
//oFileInput.setAttribute("id",_name);
        //oFileInput.setAttribute("name",_name);
        //oFileInput.outerHTML = '<INPUT type=file id=' + _name + ' name=' + _name + '>';
        //alert(oFileInput.outerHTML);
        return oFileInput;
    }
    
</SCRIPT>
posted @ 2007-01-26 17:21 重归本垒(Bing) 阅读(32308) | 评论 (12)编辑 收藏
 
JavaScript中没有Trim函数,VBScript语言中才有这个函数,就是去掉字符串头和尾的空格。可以在JavaScript中这么写一个:

<script language="JavaScript"> 
//此处为string类添加三个成员 
String.prototype.Trim = function()return Trim(this);} 
String.prototype.LTrim 
= function(){return LTrim(this);} 
String.prototype.RTrim 
= function(){return RTrim(this);} 

//此处为独立函数 
function LTrim(str) 

var i; 
for(i=0;i<str.length;i++

if(str.charAt(i)!=" "&&str.charAt(i)!=" ")break
}
 
str
=str.substring(i,str.length); 
return str; 
}
 
function RTrim(str) 

var i; 
for(i=str.length-1;i>=0;i--

if(str.charAt(i)!=" "&&str.charAt(i)!=" ")break
}
 
str
=str.substring(0,i+1); 
return str; 
}
 
function Trim(str) 

return LTrim(RTrim(str)); 
}
 
</script>
posted @ 2007-01-23 14:43 重归本垒(Bing) 阅读(1657) | 评论 (2)编辑 收藏
 
     摘要: jsp文件上传大多采用采用开源项目来简化处理,这里列出常用的两个jar包的实现,并进行比较,说明他们的优缺点和应该注意的问题。 Commons FileUpload,可以在http://jakarta.apache.org/commons/fileupload/下载,这个包需要Commons IO的支持,可以在http://jakarta.apache.org/commo...  阅读全文
posted @ 2007-01-22 11:42 重归本垒(Bing) 阅读(1017) | 评论 (0)编辑 收藏
 
     摘要: DWR是一个框架,简单的说就是能够在javascript直接调用java方法,而不必去写一大堆的javascript代码。它的实现是基于ajax的,可以实现无刷新效果。     网上有不少DWR的例子,但大都只是某种方法的调用,本文只在使用层面上介绍DWR,并不涉更多的技术与设计,其目的是让初学者能够很快的学会各种java方法在javascript中是如何调用的。    本文以DWR 1.1 ...  阅读全文
posted @ 2007-01-16 10:30 重归本垒(Bing) 阅读(1017) | 评论 (0)编辑 收藏
 

怎样才能把这么多单词背下来呢?最重要的一点,就是:...如果想比别人成功,就一定要走捷径。不要期盼自己比别人幸运,也不要指望自己比别人更聪明或者更勤奋。从智力上说,从机遇上说,自己和别人都是差不了多少的,想超过和自己差不多的人,就一定要走捷径,捷径,捷径!


背单词捷径的第一条,就是:一定要每次都大量地背。因为自己不比别人聪明,所以背完单词,别人忘掉五分之一,自己决不会比别人忘得少。然而,别人每天背十个单词,自己却可以背一百个,忘掉五分之一,还剩八十个,是别人最聪明状态下的十倍。每天一百个是最低限。其实背到后来您会发现这个要求并不高,一个月后,您可能自然而然地就背到三百或者五百。 这一百个要分成四组来背,上午三十,中午十个,下午三十,晚上三十。第二天早晨复习以前没背下来的词。背的时候,要一目十词(注意,是十个而不是更多或更少),不要认认真真背,因为没有认认真真的时间。一边看一边读每个词的读音,默读也成。看完后回忆一遍,回忆不起来的再看。这次背的目的在于留下个大概印象,下次看见能知道这个词,所以背到大部分都能回忆得起来就成了,把剩下的词单独抄出来。


背单词捷径的第二条,就是:背字典!为什么要背字典呢?因为字典上每个词的解释比较全面,而且相同字母开头的单词都集中在一起。不是什么字典都可以拿来背的,一定要找只包含自己想背的词的字典。另外,最好有英文方式的解释和例句。而且,一定要有音标!如果是为了考TOFEL或者GRE,注意要选美音音标的字典。一般教材课文后面的词汇表都是为那些认认真真听课的好学生准备的,想走捷径就千万不要去背那些东西。 背字典的时候,按开头字母(Z,Y,X,Q,J,K,U)(V,W,N,O,L)(FG,IT,HM,BDE,R)(C,P,S,A)的顺序背,其中C,P,S,A每个都要分三部分背。这样背有几个好处:


(一)能增加成就感,提高兴趣。至于为什么,您翻翻字典就明白了。;)


(二)便于清楚地知道那些单词已经背过,那些还没背。(三)能先把最基本的词先掌握。 三万单词里,分为三个等级:三千到四千,八千到一万,两万二到三万。也就是说,您得分别准备三本字典。这几个等级之间各自有非常不同的特性,所以需要分别用不同方法背。俺当时没有认识到这一点,所以在从一万到三万之间走了一段弯路,浪费了一些时间,不然或许能突破到五万吧。;) 所以,背单词捷径的下面这条就有了三个分支:


背单词捷径的第三条,就是:和单词多见面。一个单词能不能记住,取决于和它在不同场合见面的频率,不在于每次看着它的时间长短(同样规律也适合于泡MM;))。一般想记住一个单词,每星期要和它在“不同场合”见三到四次面。俺在上文中提到大量背的时候,不要抠某一个字记住与否就是这个意思。因为是否一见钟情都是无所谓的,关键在于有更多不同类型的见面机会。不过,根据要背的单词的等级不同,增加见面机会的方式也有所不同。


第一个分支:瞎听!三千到四千这个等级,是非常常用的单词,而且几乎囊括了表达最基本思想所需要的一切词汇。每篇文章中百分之八十都是这些词汇,而且这些词都是最基本的语素(或称“词根”),就是分割到最小无法再分割,互相之间也没什么类似之处的东西。对付这些词的最好方法,就是进行大量的,不间断的,简单的初级听力练习。因为阅读材料中,还有百分之二十其他词汇,所以光凭这个等级的词还看不懂那些阅读材料。但是听力练习都是最基本的对话,而且发音一般很标准,多听能够增加单词的重复率,而且可以为以后背八千到一万那个等级的词打下语音基础。 听的时候,要分精听和泛听两部分。精听当然是指每个词都要弄懂,俺着重讲一下泛听(饭厅?;P)。泛听是最重要的,因为掌握语速和语调,以及总体印象都要靠泛听。而这些都是背八千到一万等级单词的基础?泛听能够让经常用到的词(也就是那些最必要掌握的词)把您的耳朵磨出茧子来,让您模模糊糊听到个音就能反应出它是什么意思。泛听中您听到的词,才是您真正应该记住的词,所以别害怕精听的时候什么都听不懂。到底什么是泛听呢?泛听,就是说您听的时候,精神要分散,要一边干着其他事(比如撮饭或和别人大声讨论撮饭;)~),一边有一搭没一搭地听着。泛听一定要见缝插针,一有机会就听着,最好耳机不离耳朵。;) 而精听的意义就在于找出您没听清的那些词。啊哈,那就是您背过但还不熟悉的词了。:)把这些词单独记在另外一个地方,别跟没背下来的词混了。泛听要听精听已经听过的内容。比如精听听到了第二盘磁带,那么泛听就听第一盘磁带,正好。提醒您一句,千万别拿英语广播当自己的听力教材!!! 顺便跟您推荐一套听力教材:武汉师范大学出的Step by Step.内容比较循序渐进,每一课开头的音乐也很好听。;) ...


第二个分支:狂看!八千到一万这个等级,基本包含了剩下的百分之二十。这些单词在听力教材里很难找到。但是,可不要停止听的练习呦,因为听能巩固您的语调感觉,而这是背这个等级单词的一个关键。不过,背这个等级的词,需要在听以外增加看的内容。 看,同样要分精读和泛读两种。就象听一样,也是泛读更重要一些。泛读要挑不太长,能有耐心看完的文章,而且看不懂的词不要太多,一篇文章有两三个不认识的就足够了。千万不要一上来就看英语报刊杂志小说,那些东西不但很难看懂,而且看懂了也对背单词没什么促进作用。:Q 泛读也需要大量练习,只要您有耐心,又有足够时间,就一直看下去吧!看的时候不要仔细阅读,扫一眼明白个大概意思就成了,然后把这一眼没看懂的词画上记号,别琢磨它是什么意思,继续扫描吧!全部看完之后,回头再看这些单词,有的可能已经想起来了,有的....还没想起来?那就查查字典,要是自己还没背过,就扔掉它,要是已经背过了,就单独抄下来吧,和听力练习中没听出来的词放在一起。 俺的经验是新概念第一二册,然后大学泛读课本前两册,然后是另外的一个泛读教程初级部分,然后新概念第三册,泛读课本第三册,某一种听力教材高级听力部分的教师用书,然后新概念第四册,泛读课本第四五册...这么个顺序进度比较合适。


第三个分支:乱说!这只适合背两万二到三万的词。因为其他的词不用说就已经背下来了。;)而这个等级的词在阅读材料里非常少,可能阅读十篇文章却一个这个等级的词也没有。所以靠阅读来增加见面机会已经不行了。这些词甚至有的老外一辈子都没见过,咋能指望他们能写出来呢?尤其是GRE词汇,什么"给马穿衣服","纽约的流氓","从非洲吹向南欧的风"....这些词都是一些精致的修辞,也就是说,如果您话里净是这些词,那您可以假冒一位学者了。;) 一般的老外都是听不懂您说的这些话的,所以不用这些词也能表达同样的含义。好了,您的机会来了,您可以跟老外讲话中带上这些单词,然后很自豪地假装谦虚地跟他们解释这些词的含义。;) 每次跟老外解释一两个词就足够了,老外会佩服您佩服得五体投地的。;)HL就向ws解释吧!要大胆而耐心,尤其是大胆。;) 这个阶段,您就别再练听力了,因为练了进步也不大。还记得开头那句话么?要想成功,得走捷径。 凡是不能在短时期内取得巨大进步的行动,都不必浪费时间去做。 不过,这时候的阅读材料成了问题:您会发现,过去看的东西觉得太浅没意思,看其他深的东西又看不懂。您还会发现一个新的有趣现象:那就是您想看的文章里,现在全是第一个等级的那些词,每个词您都确切知道它的含义,但整个文章您就是看不懂。;Q 那您该看什么呢?就看第二个等级的那些浅显文章啊。虽然浅显,但能帮助您不至于忘了过去背出来的成果。至于您看不懂的那些文章,别着急,等您和老外交流多了,您自然就懂了,那都是一些词组、俚语或文法组成的文章。:)


背单词捷径的第四条,就是:联想,联想,联想,.....背单词的第一个动作是什么?端详一下它的外貌。第二第三个动作呢?看看它的内涵和发音。而第四个动作,就应该是联想,再联想..... 联想它和其他背过的词有没有外表类似的?读音类似的?意思类似或相反的?如果有,就赶紧记在旁边,在另外那些词旁边也把这个词加上。这样,以后看见其他词,也会联想起这个词,等于又增加了一次见面机会。 而且,在第二、第三个等级的词汇里,还有许多单词是由"前缀","词根","后缀"组成的,前缀比如"re","in","pseud"...,后缀比?quot;er","a","oid"...,然后共同组成一个新词。如果掌握了这些前后缀,就可以很方便地猜出一个生词到底什么意思。另外,有很多读音相近的词也有相似的意思,这在俚语、诗歌和儿童用语中更普遍。如果每天记80个单词,一个月只能?400个单词,但掌握了这些规律后,实际上背的速度越来越快,几乎一万多单词都是不用背就会了的。不过,在GRE单词中,有很多是既没有和其他词的关系,又没有前后缀,看起来既简单又记不住的单词。这些词里边有希腊语,意大利语,德语,拉丁语,甚至还有日语译音。这就只能靠和别人解释来掌握了。(HL一定要注意!)

背单词捷径的第五条,就是:复习!记得快,忘得也就快,这是一个非常正常的规律。在背单词的过程中,复习就显得非常重要。俺总结复习的规律是:十个单词复习一遍,然后三十个单词,然后是以前所有没背下来的单词。复习的时候,同样不必细抠,粗略地扫一遍就可以了,但一定要想它的读音(因为英语是象声的)。最后背不下来的单词,一定是不常用的,因为老外一样背不下来。;) 每背完一个开头字母的单词,就要把前一个开头字母的复习一遍。然后每背完前文中括号里面的开头字母,就把上一个括号里的复习一遍。复习的时候,要先看英文翻译中文意思来一遍,然后再看着中文想它的英文单词再来一遍。 前面说过,在泛听,泛读中忘了的词要和背的时候就记不住的词分着记下来,就是为了在复习的时候区别对待。忘了的词,要每天看一遍,会了就划掉,而记不住的词则在背完了整个字母以后,单独背一下这些词,平常就不用看了。 GRE单词的复习方法非常奇怪:它需要进行填字游戏。也就是说,盖住单词的一部分,然后想整个词是怎么拼。另外,还得想它的同义词,近义词,反义词。 顺便说一句,考GRE的词和考TOFEL的词互相之间是毫不相关的,也就是说,您不会TOFEL的词,GRE也 有可能拿个高分。

posted @ 2006-12-26 09:54 重归本垒(Bing) 阅读(230) | 评论 (0)编辑 收藏
 
      在eclipse中要想正确的运行应用程序,首先要做的就是把相关的类库,类文件包含进来,以及其它配制文件link进来。

      在eclipse中可以非常方便的做到。

      在工程文件目录中点右键,打开“构建路径”——>“配制构建路径”,就可以进行相关的类库,类文件,配制文件的设置。

      在“库”中可以加入编译运行时需要的类库,在“源代码”中可以link入编译运行需要的类,同时还要吧设置源文件的位置以及输出位置。在“项目”中可以加入运行时依赖的其它project。在“排序和导出”可以对设置好的类库,类文件,配制文件进行排序,可以设定哪些文件要导出到硬盘上。
posted @ 2006-12-21 15:26 重归本垒(Bing) 阅读(764) | 评论 (0)编辑 收藏
 
方法一:

select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段

10 = 每页记录数

20 = (当前页 + 1) * 每页记录数

以上语句即可以实现分页,但是最后取出的结果排序是升序,如果需要结果集为降序(例如时间),则有两种方法可以处理

1.使用以下语句,但效率可能要降低一些

select * from 表名 b, (select top 10 主键字段,排序字段 from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a order by 排序字段 ) c where b.主键字段 = c.主键字段 order by c.排序字段 desc

2.在ado里处理,将记录集游标移到最后,然后前移

''以下为asp范例

set rsTemp = Server.CreateObject("adodb.recordset")

rsTemp.Open 语句,conn,1,1

rsTemp.MoveLast

for i = 1 to rsTemp.RecordCount

 '取值....

rsTemp.MovePrevious

next

 

经测试,以上分页方法比使用临时表分页速度还要快,并且简单易用.

方法二:

大数据量下的分页

    对于非常大的数据模型而言,分页检索时,每次都加载整个数据源非常浪费。通常的选择是检索页面大小的块区的数据,而非检索所有的数据,然后单步执行当前行。

    本文演示ASP.net的DataGrid和Sql Server 实现大数据量下的分页,为了便于实现演示,数据表采用了Northwind数据库的Orders表(830条记录)。

    如果数据表中有唯一的自增索引,并且这个字段没有出现断号现象。检索页面大小的块区数据就非常简单了。通过简单的Sql语句就可以实现这个功能:

    select * from orders where orderid between 10248 and 10253

    其中,开始编号为:(CurrentPageIndex - 1) * PageSize  结束编号为:CurrentPageIndex * PageSize

    当然,如果这个字段断号不是很严重,而且允许不是很严格的按照每页条数分页,这样的方法也是可以用的。

    如果这个字段断号,或者需要按照其他条件排序分页,就要复杂些了。首先要获得这个页面需要显示的编号,然后再按照这个编号获得需要的块区数据。根据编号获得块区数据很简单。不过用下面方式获得数据排序并不是按照指定的id列表顺序,这时候还要附加order by 命令。

select * from orders where orderid in (10248,10249,10250,10251,10252,10253) order by orderid desc

    获得这个页面需要显示的编号列表就复杂多了,而且有多种方案:

方案一:维护一个表,这个表记录需要显示的这些编号排序顺序。(这个表可以是临时表,也可以是物理表)。下面演示了利用一个全局临时表。这个全局临时表记录需要显示的编号。注意排序,这里的order by 就是需要显示的排序顺序。

create table ##temptable(iid int IDENTITY (1, 1) NOT NULL,mainid int NOT NULL)insert ##temptable(mainid) select OrderID from orders order by OrderID descselect * from ##temptabledrop table ##temptable -- 实际执行时候,删除全部临时表当然不再这里执行。

这个临时表存在,获得指定分页的分块数据就很简单了。看下面代码:

create table ##temptable(iid int IDENTITY (1, 1) NOT NULL,mainid int NOT NULL)insert ##temptable(mainid) select OrderID from orders order by OrderID descdeclare @PageSize int,@CurrPage int,@strSQL varchar(2000),@IDStr varchar(1000)select @PageSize = 30select @CurrPage = 2select @IDStr = ''select @IDStr = @IDStr + ltrim(rtrim(str(MainID))) + ',' from ##temptable where iid between ((@CurrPage-1)*@PageSize+1) and @CurrPage*@PageSizeif @IDStr <> '' begin select @IDStr = left(@IDStr,len(@IDStr)-1)endselect @strSQL = 'select * from orders where OrderID in ('+@IDStr+')  order by OrderID desc 'exec(@strSQL)drop table ##temptable

注意:实际使用这个方案的时候,还要考虑何时更新这个全局临时表,一般是放到计划任务中,定时更新这个汇总表。

方案二:每次都去查询,每次获得最新的编号顺序。由于这时候不存在这个临时表,书写获得需要显示页面的编号的字符串就需要点技巧,看下面的代码: ASP.net 的 DataGrid 提供了使用这种分区的数据的方法。 DataGrid 通过 AllowCustomPaging 和 VirtualItemCount 属性支持块区操作。如果 AllowCustomPaging 为 true,则 DataGrid 不会根据 CurrentPageIndex 计算数据模型中的起始显示位置。DataGrid 将显示数据模型中的所有数据,而页导航栏将当前位置报告为 (VirtualItemCount+PageSize-1)/PageSize 之 CurrentPageIndex 页。下面的示例说明此功能。

declare @PageSize int,@CurrPage int,@topnum int,@previous intselect @PageSize = 30select @CurrPage = 2select @topnum = @CurrPage * @PageSizeselect @previous = (@CurrPage - 1) * @PageSizedeclare @i int,@IDStr nvarchar(500),@strSQL nvarchar(1000)select @i = 0select @strSQL = N''select @strSQL = @strSQL + N' select top '+str(@topnum)+ ' @i = @i + 1 'select @strSQL = @strSQL + N',  @IdStr = 'select @strSQL = @strSQL + N'case when @i > '+str(@previous)+' then  @IdStr + ltrim(rtrim(str(OrderID))) + '','' 'select @strSQL = @strSQL + N'else N''''end 'select @strSQL = @strSQL + N'from Orders 'select @strSQL = ltrim(rtrim(@strSQL)) + N' order by OrderID desc 'Select @IdStr = N''exec sp_executesql @strSQL,N'@i int,@IdStr varchar(500) output',@i,@IdStr outputif len(rtrim(ltrim(@IdStr))) > 0begin select @IdStr = left(@IdStr,len(@IdStr)-1)endselect @strSQL = 'select * from orders where OrderID in ('+@IDStr+')'exec(@strSQL)

 

     protected void BindDataGrid(int currpage) {  string strConn = "Data Source=(local);Integrated Security=SSPI;database=Northwind";  // 请确认 机器名/ASPNET 用户可以访问Northwind数据库  SqlCommand cmd = new SqlCommand();  SqlConnection conn = new SqlConnection(strConn);  SqlParameter[]  parms = new SqlParameter[] {   new SqlParameter("@PageSize",SqlDbType.Int),   new SqlParameter("@CurrPage",SqlDbType.Int),   new SqlParameter("@SearchSql",SqlDbType.NVarChar,128),   new SqlParameter("@Count",SqlDbType.Int),  };  parms[0].Value = DataGrid1.PageSize;  parms[1].Value = (currpage+1);   //  数据库的分页算法第一页是1  DataGrid的第一页是0  parms[2].Value = DBNull.Value;  parms[3].Direction = ParameterDirection.Output;  parms[3].Value = DBNull.Value;  DataSet DS = new DataSet();  try   {   if (conn.State != ConnectionState.Open) conn.Open();   cmd.Connection = conn;   cmd.CommandText = "Selected_Page_List";   cmd.CommandType = CommandType.StoredProcedure;   if (parms != null)    {    foreach (SqlParameter parm in parms)     cmd.Parameters.Add(parm);   }   SqlDataAdapter DA = new SqlDataAdapter(cmd);   DA.Fill(DS);   int aa = Convert.ToInt32(parms[3].Value.ToString());   cmd.Parameters.Clear();   if (currpage == 0)   {    DataGrid1.VirtualItemCount = aa;   }   DataGrid1.CurrentPageIndex = currpage;   DataGrid1.DataSource = DS;   DataGrid1.DataBind();  }  catch(Exception ewx)  {   conn.Close();   Response.Write (ewx.Message.ToString());   Response.End();  } }    void Page_Load(Object sender, EventArgs E ) {  if (!IsPostBack)   {   BindDataGrid(0);   // 第一次打开这个页面,访问分页的第一页  }    }    void MyDataGrid_Page(Object sender, DataGridPageChangedEventArgs e) {  BindDataGrid(e.NewPageIndex);    }

如果你有更多数据量的表稍加修改,也可以使用本演示程序。其下是演示代码下载,演示代码使用的是方案二。使用方法看readme.txt文件。

整个演示代码 下载

http://chs.gotdotnet.com/quickstart/aspplus/samples/webforms/ctrlref/webctrl/datagrid/doc_datagrid.aspx#paging
这里演示了利用DataGrid 的这个功能(没有本文中讨论的利用存储过程获得分区数据)。如对DataGrid的这个功能不太熟悉,请先看这里。

 

方法三:

虽然 DataGrid 控件自己带了一个分页处理机制,但它是将符合查询条件的所有记录读入内存,然后进行分页显示的。随着符合条件的记录数目增多,就会出现运行效率问题,或者至少是资源的利用率下降。

下面的代码示例都以下面的表结构为准:

 

  Articles 表 SQL Server 类型 Oracle 类型
PK Id int (自增) number(9) (插入时在当前最大值上加1)
  Author nvarchar(10) nvarchar2(10)
  Title nvarchar(50) nvarchar2(50)
  PubTime datetime date

SQL Server / Access 等微软产品中,我们通常的自定义分页有两种思路:

一种是以 ASP.NET Forum 为代表的、“临时表”方法:即在存储过程中建立一个临时表,该临时表包含一个序号字段(1,2,3,....)以及表的主键(其他能够唯一确定一行记录的字段也是可以的)字段。存储过程可能如下:(编号 SS1)

CREATE Procedure GetAllArticles_Paged
(
     @PageIndex int,
     @PageSize int,
     @TotalRecords out int,
     @TotalPages out int
)
AS

DECLARE @PageLowerBound int
DECLARE @PageUpperBound int

-- Set the page bounds
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1

-- Create a temp table to store the select results
CREATE TABLE #tmp
(
     RecNo int IDENTITY (1, 1) NOT NULL,
     ArticleID int
)

INSERT INTO #tmp
     SELECT [ID]
     FROM Articles
     ORDER BY PubTime DESC

SELECT A.*
FROM Articles A (nolock), #tmp T
WHERE A.ID = T.ArticleID AND
     T.RecNo > @PageLowerBound AND
     T.RecNo < @PageUpperBound
ORDER BY T.RecNo

GO

另一种可能更适合程序中“拼凑” SQL 语句:用两次 TOP 命令取得我们所要的分页数据,例如:(编号 SS2)

SELECT * FROM
     (
     SELECT TOP(PageSize) * FROM
     (
          SELECT TOP (PageSize * PageIndex) *
          FROM Articles
          ORDER BY PubTime DESC
     )
     ORDER BY PubTime ASC
)
ORDER BY PubTime DESC

这个的想法就是“掐头去尾”,还有不少分页的方法,这里就不一一列出了。

对于 Oracle 数据库,有几处不同严重妨碍了上面几个方法的实施,比如,Oracle 不支持 TOP 关键字:不过这个好像并不十分严重,因为它提供了 rownum 这个隐式游标,可以实现与 TOP 类似的功能,如:

SELECT TOP 10 ... FROM WHERE ...

要写成

SELECT ... FROM ... WHERE ... AND rownum <= 10

rownum 是记录序号(1,2,3...),但有一个比较麻烦的事情是:如果 SQL 语句中有 ORDER BY ... 排序的时候,rownum 居然是先“标号”后排序!这样,这个序号如果不加处理是不合乎使用需求的。

至于临时表,Oracle 的临时表和 SQL Server 的有很大不同,我还没搞懂这个东西,就不妄加揣测了。

国内网站中介绍 Oracle 分页的资料很少,我找到了一个国外站点(www.faqts.com)的一篇 FAQ,根据这篇文章的介绍,可以如下分页:(编号 Ora1)

SELECT * FROM
     (
     SELECT A.*, rownum r
     FROM
          (
          SELECT *
          FROM Articles
          ORDER BY PubTime DESC

          ) A
     WHERE rownum <= PageUpperBound
     ) B
WHERE r > PageLowerBound;

其中蓝色部分可以改为任意的、需要的 SQL SELECT 语句,这点倒是挺方便的。

方法四:

今天突然发现,Oracle原来可以这样实现分页功能:

select * from (select rownum rdd,field1,field2 from t_table where rownum<=400) where  rdd>200

上述语句实现了从第201条记录开始处取200条记录

posted @ 2006-12-20 10:29 重归本垒(Bing) 阅读(513) | 评论 (0)编辑 收藏
 

李开复2005年2月


     今天,我回复了“开复学生网”开通以来的第1000个问题。关掉电脑后,始终有一封学生来信萦绕在我的脑海里,挥之不去:

      开复老师:
         就要毕业了。
         回头看自己所谓的大学生活,
         我想哭,不是因为离别,而是因为什么都没学到。
         我不知,简历该怎么写,若是以往我会让它空白。
         最大的收获也许是……对什么都没有的忍耐和适应……


     这封来信道出了不少大三、大四学生的心声。大学期间,有许多学生放任自己、虚度光阴,还有许多学生始终也找不到正确的学习方向。当他们被第一次补考通知唤醒时,当他们收到第一封来自应聘企业的婉拒信时,这些学生才惊讶地发现,自己的前途是那么渺茫,一切努力似乎都为时已晚……
这“第四封信”是写给那些希望早些从懵懂中清醒过来的大学生,那些从未贪睡并希望把握自己的前途和命运的大学生以及那些即将迈进大学门槛的未来大学生们的。在这封信中,我想对所有同学说: 

     大学是人一生中最为关键的阶段。从入学的第一天起,你就应当对大学四年有一个正确的认识和规划。为了在学习中享受到最大的快乐,为了在毕业时找到自己最喜爱的工作,每一个刚进入大学校园的人都应当掌握七项学习:学习自修之道、基础知识、实践贯通、兴趣培养、积极主动、掌控时间、为人处事。只要做好了这七点,大学生临到毕业时的最大收获就绝不会是“对什么都没有的忍耐和适应”,而应当是“对什么都可以有的自信和渴望”。只要做好了这七点,你就能成为一个有潜力、有思想、有价值、有前途的快乐的毕业生。
 

大学:人生的关键

   大学是人生的关键阶段。这是因为,进入大学是你终于放下高考的重担,第一次开始追逐自己的理想、兴趣。这是你离开家庭生活,第一次独立参与团体和社会生活。这是你不再单纯地学习或背诵书本上的理论知识,第一次有机会在学习理论的同时亲身实践。这是你第一次不再由父母安排生活和学习中的一切,而是有足够的自由处置生活和学习中遇到的各类问题,支配所有属于自己的时间。

   大学是人生的关键阶段。这是因为,这是你一生中最后一次有机会系统性地接受教育。这是你最后一次能够全心建立你的知识基础。这可能是你最后一次可以将大段时间用于学习的人生阶段,也可能是最后一次可以拥有较高的可塑性、集中精力充实自我的成长历程。这也许是你最后一次能在相对宽容的,可以置身其中学习为人处世之道的理想环境。

   大学是人生的关键阶段。在这个阶段里,所有大学生都应当认真把握每一个“第一次”,让它们成为未来人生道路的基石;在这个阶段里,所有大学生也要珍惜每一个“最后一次”,不要让自己在不远的将来追悔莫及。在大学四年里,大家应该努力为自己编织生活梦想,明确奋斗方向,奠定事业基础。

   大学四年每个人都只有一次,大学四年应这样度过……

 

自修之道:从举一反三到无师自通

   记得我在哥伦比亚大学任助教时,曾有位中国学生的家长向我抱怨说:“你们大学里到底在教些什么?我孩子读完了大二计算机系,居然连VisiCalc[1] 都不会用。”

   我当时回答道:“电脑的发展日新月异。我们不能保证大学里所教的任何一项技术在五年以后仍然管用,我们也不能保证学生可以学会每一种技术和工具。我们能保证的是,你的孩子将学会思考,并掌握学习的方法,这样,无论五年以后出现什么样的新技术或新工具,你的孩子都能游刃有余。”

   她接着问:“学最新的软件不是教育,那教育的本质究竟是什么呢?”

   我回答说:“如果我们将学过的东西忘得一干二净时,最后剩下来的东西就是教育的本质了。

   我当时说的这句话来自教育家B. F. Skinner的名言。所谓“剩下来的东西”,其实就是自学的能力,也就是举一反三或无师自通的能力。大学不是“职业培训班”,而是一个让学生适应社会,适应不同工作岗位的平台。在大学期间,学习专业知识固然重要,但更重要的还是要学习独立思考的方法,培养举一反三的能力,只有这样,大学毕业生才能适应瞬息万变的未来世界。我认识的不少在中国读完大学来美国念研究生的朋友。他们认为来美国后,不论是学习,工作还是生活他们最缺乏的是独立思考的能力因为在国内时他们很少独立思考和独立决策。

   上中学时,老师会一次又一次重复每一课里的关键内容。但进了大学以后,老师只会充当引路人的角色,学生必须自主地学习、探索和实践。走上工作岗位后,自学能力就显得更为重要了。微软公司曾做过一个统计:在每一名微软员工所掌握的知识内容里,只有大约10%是员工在过去的学习和工作中积累得到的,其他知识都是在加入微软后重新学习的。这一数据充分表明,一个缺乏自学能力的人是难以在微软这样的现代企业中立足的。

   自学能力必须在大学期间开始培养。许多同学总是抱怨老师教得不好,懂得不多,学校的课程安排也不合理。我通常会劝这些学生说:“与其诅咒黑暗,不如点亮蜡烛”。 大学生不应该只会跟在老师的身后亦步亦趋,而应当主动走在老师的前面。例如,大学老师在一个课时里通常要涵盖课本中几十页的信息内容,仅仅通过课堂听讲是无法把所有知识学通、学透的。最好的学习方法是在老师讲课之前就把课本中的相关问题琢磨清楚,然后在课堂上对照老师的讲解弥补自己在理解和认识上的不足之处。

   中学生在学习知识时更多地是追求“记住”知识,而大学生就应当要求自己“理解”知识并善于提出问题。对每一个知识点,都应当多问几个“为什么”。一旦真正理解了理论或方法的来龙去脉,大家就能举一反三地学习其他知识,解决其他问题,甚至达到无师自通的境界。

   事实上,很多问题都有不同的思路或观察角度。在学习知识或解决问题时,不要总是死守一种思维模式,不要让自己成为课本或经验的奴隶。只有在学习中敢于创新,善于从全新的角度出发思考问题,学生潜在的思考能力、创造能力和学习能力才能被真正激发出来。

   《礼记·学记》上讲:“独学而无友,则孤陋而寡闻”。也就是说,大学生应当充分利用学校里的人才资源,从各种渠道吸收知识和方法。如果遇到好的老师,你可以主动向他们请教,或者请他们推荐一些课外的参考读物。除了资深的教授以外,大学中的青年教师、博士生、硕士生乃至自己的同班同学都是最好的知识来源和学习伙伴。每个人对问题的理解和认识都不尽相同,只有互帮互学,大家才能共同进步。

   有些同学曾告诉我说,他们很羡慕我在读书时能有一位获得过图灵奖的大师传道授业。其实,虽然我非常推崇我的老师,但他在大学期间并没有教给我多少专业知识。他只是给我指明了大方向,让我分享他的经验,给我提供研究的资源,并教我做人的方法。他没有时间也没有必要指导我学习具体的专业知识。我在大学期间积累的专业知识都是通过自学获得的。刚入门时,我曾多次红着脸向我的师兄请教最基本的知识内容,开会讨论时我曾问过不少肤浅的问题,课余时间我还主动与同学探讨、切磋。“三人行必有我师”,大学生的周围到处是良师益友。只要珍惜这些难得的机会,大胆发问,经常切磋,我们就能学到最有用的知识和方法。

   大学生应该充分利用图书馆和互联网,培养独立学习和研究的本领,为适应今后的工作或进一步的深造做准备。首先,除了学习老师规定的课程以外,大学生一定要学会查找书籍和文献,以便接触更广泛的知识和研究成果。例如,当我们在一门课上发现了自己感兴趣的课题,就应当积极去图书馆查阅相关文献,了解这个课题的来龙去脉和目前的研究动态。熟练和充分地使用图书馆资源,这是大学生特别是那些有志于科学研究的大学生的必备技能之一。读书时,应尽量多读一些英文原版教材。有些原版教材写得深入浅出,附有大量实例,比中文教材还适于自学。其次,在书本之外,互联网也是一个巨大的资源库,大学生们可以借助搜索引擎在网上查找各类信息。“开复学生网”开通半年以来,我发现很多同学其实并没有很好地掌握互联网的搜索技巧,有时他们提出的问题只要在搜索引擎中简单检索一下,就能轻易找到答案。还有些同学很容易相信网上的谣言,而不会利用搜索引擎自己查考、求证。除了搜索引擎以外,网上还有许多网站和社区也是很好的学习园地。

   自学时,不要因为达到了学校的要求就沾沾自喜,也不要认为自己在大学里功课好就足够了。在二十一世纪的今天,人才已经变成了一个国际化的概念。当你对自己的成绩感到满意时,我建议你开始自学一些国际一流大学的课程。例如,美国麻省理工学院(MIT)的开放式课程已经在网上无偿发布出来,大家不妨去看看MIT的网上课程,做做MIT的网上试题。当你可以自如地掌握MIT课程时,你就可以更加自信地面对国际化的挑战了。

   总之,善于举一反三,学会无师自通,这是大学四年中你可以送给自己的最好的礼物。

 

基础知识:数学、英语、计算机、互联网

   我曾经说过,中国学生的一大优势是扎实的基础知识,如数学、物理等。但是,最近几年,同学们在目睹了很多速成的例子(如丁磊、陈天桥等)之后,也迫切希望能驶上成功的快车道。这渐渐形成了一种追求速成的浮躁风气。有许多大学生梦想在毕业后就立即能做“经理”、“老板”,还有许多大学生入学时直接选择了“管理”专业,因为他们认为从这样的专业毕业后马上就可以成为企业的管理者。可不少学生进入了管理专业后,才发现自己对本专业的学习毫无兴趣。其实,管理专业和其他专业一样,都是传授基础知识和基本方法的地方,没有哪个专业可以保证学生在毕业时就能走上领导岗位。无论同学们所学的是哪个专业,大学毕业才是个人事业的真正开始。想做企业领导或想做管理工作的同学也必须从基层做起,必须首先在人品方面学会做人,在学业方面打好基础。

   如果说大学是一个学习和进步的平台,那么,这个平台的地基就是大学里的基础课程。在大学期间,同学们一定要学好基础知识其中包括数学、英语、计算机和互联网的使用,以及本专业要求的基础课程(如商学院的财务、经济等课程)。在科技发展日新月异的今天,应用领域里很多看似高深的技术在几年后就会被新的技术或工具取代。只有对基础知识的学习才可以受用终身。另一方面,如果没有打下好的基础,大学生们也很难真正理解高深的应用技术。最后,在许多的中国大学里,教授对基础课程也比对最新技术有更丰富的教学经验。

   数学是理工科学生必备的基础。很多学生在高中时认为数学是最难学的,到了大学里,一旦发现本专业对数学的要求不高,就会彻底放松对数学知识的学习,而且他们看不出数学知识有什么现实的应用或就业前景。但大家不要忘记,绝大多数理工科专业的知识体系都建立在数学的基石之上。例如,要想学好计算机工程专业,那至少要把离散数学(包括集合论、图论、数理逻辑等)、线性代数、概率统计和数学分析学好;要想进一步攻读计算机科学专业的硕士或博士学位,可能还需要更高的数学素养。同时,数学也是人类几千年积累的智慧结晶,学习数学知识可以培养和训练人的思维能力。通过对几何的学习,我们可以学会用演绎、推理来求证和思考的方法;通过学习概率统计,我们可以知道该如何避免钻进思维的死胡同,该如何让自己面前的机会最大化。所以,大家一定要用心把数学学好,不能敷衍了事。学习数学也不能仅仅局限于选修多门数学课程,而是要知道自己为什么学习数学,要从学习数学的过程中掌握认知和思考的方法。

   二十一世纪里最重要的沟通工具就是英语。有些同学在大学里只为了考过四级、六级而学习英语,有的同学仅仅把英语当作一种求职必备的技能来学习,甚至还有人认为学习和使用英语等于崇洋媚外。其实,学习英语的根本目的是为了掌握一种重要的学习和沟通工具。在未来的几十年里,世界上最全面的新闻内容,最先进的思想和最高深的技术,以及大多数知识分子间的交流都将用英语进行。因此,除非你甘心做一个与国际脱节的人,英语学习是至关重要的。在软件行业里,不但编程语言是以英语为基础设计出来的,最重要的教材、论文、参考资料、用户手册等资源也大多是用英语写就的。学英语绝不等于崇洋媚外。中国正在走向世界,中国需要学习西方的先进思想和先进科学技术,学好英语才是真正的爱国。

   很多中国留学生的英语考试成绩不错,也高分考过四级、六级、托福,但是留学美国后上课时却很难听懂课程内容,和外国同学交流时就更加困难。我们该如何学好英语呢?既然英语是最重要的沟通工具,那么,最重要的学习方法就是尽量与实践结合起来,不能只“学”不“用”,更不能只靠背诵的方式学习英语。读书时,大家尽量阅读原版的专业教材(如果英语不够好,可以先从中英对照的教材看起),并适当地阅读一些自己感兴趣的专业论文,这可以同时提高英语和相关专业的知识水平。其次,提高英语听说能力的最好方法是直接与那些以英语为母语的外国人对话。现在有很多在中国学习和工作的外国人,他们中的不少人为了学中文,很愿意与中国学生对话、交流,这是很好的学习机会。此外,大家不要把学英语当作一件苦差事,完全可以用有趣的方法学习英语。例如,可以多看一些名人的对话或演讲,多看一些小说、戏剧甚至漫画。初学者可以找英文原版的教学节目和录像来学习,有一定基础的则应该看英文电视或电影。看一部英文电影时,最好先在有字幕的时候看一遍,同时查考生词、熟悉句式,然后在不加字幕的情况下再看一遍,仅靠耳朵去听。听英文广播也是很好的练习英文听力的方法,大家每天最好能抽出半小时到一小时的时间收听广播并尽量理解其中的内容,有必要的话还可以录下来反复收听。在互联网上也有许多互动式的英语学习网站,大家可以在网站上用游戏、自我测试、双语阅读等方式提升英语水平。总之,勇于实践、持之以恒是学习英语的必由之路。

   信息时代已经到来,大学生在信息科学与信息技术方面的素养也已成为他们进入社会的必备基础之一。虽然不是每个大学生都需要懂得计算机原理和编程知识,但所有大学生都应能熟练地使用计算机、互联网、办公软件和搜索引擎,都应能熟练地在网上浏览信息和查找专业知识。在二十一世纪里,使用计算机和网络就像使用纸和笔一样是人人必备的基本功。不学好计算机,你就无法快捷全面地获得自己需要的知识或信息。

   最后,每个特定的专业也有它自己的基础课程。以计算机专业为例,许多大学生只热衷于学习最新的语言、技术、平台、标准和工具,因为很多公司在招聘时都会要求这些方面的基础或经验。这些新技术虽然应该学习,但计算机基础课程的学习更为重要,因为语言和平台的发展日新月异,但只要学好基础课程(如数据结构、算法、编译原理、计算机原理、数据库原理等)就可以万变不离其宗。有位同学生动地把这些基础课程比拟为计算机专业的内功,而把新的语言、技术、平台、标准和工具比拟为外功。那些只懂得追求时髦的学生最终只知道些招式的皮毛,而没有内功的积累,他们是不可能成为真正的高手的。

   虽然我一向鼓励大家追寻自己的兴趣,但在这里仍需强调,生活中有些事情即便不感兴趣也是必须要做的。例如,打好基础,学好数学、英语和计算机的使用就是这一类必须做的事情。如果你对数学、英语和计算机有兴趣,那你是幸运儿,可以享受学习的乐趣;但就算你没有兴趣,你也必须把这些基础打好。打基础是苦功夫,不愿吃苦是不能修得正果的。

 

实践贯通:“做过的才真正明白”

   上高中时,许多学生会向老师提出“为什么?有什么用?”的问题,通常,老师给出的答案都是“不准问”。进入大学后,这些问题的答案应该是“不准不问”。在大学里,同学们应该懂得每一个学科的知识、理论、方法与具体的实践、应用如何结合起来,尤其是工科的学生更是如此。

   有一句关于实践的谚语是这样说的:“我听到的会忘掉,我看到的能记住,我做过的才真正明白。

   无论学习何种专业、何种课程,如果能在学习中努力实践,做到融会贯通,我们就可以更深入地理解知识体系,可以牢牢地记住学过的知识。因此,我建议同学们多选些与实践相关的专业课。实践时,最好是几个同学合作,这样,既可经过实践理解专业知识,也可以学会如何与人合作,培养团队精神。如果有机会在老师手下做些实际的项目,或者走出校门打工,只要不影响课业,这些做法都是值得鼓励的。外出打工或做项目时,不要只看重薪酬待遇(除非生活上确实有困难),有时候,即便待遇不满意,但有许多培训和实践的机会,我们也值得一试。

   以计算机专业为例,实践经验对于软件开发来说更是必不可少的。微软公司希望应聘程序员的大学毕业生最好有十万行的编程经验。理由很简单:实践性的技术要在实践中提高。计算机归根结底是一门实践的学问,不动手是永远也学不会的。因此,最重要的不是在笔试中考高分,而是实践能力。但是,在与中国学生的交流过程中,我很惊讶地发现,中国某些学校计算机系的学生到了大三还不会编程。这些大学里的教学方法和课程的确需要更新。如果你不巧是在这样的学校中就读,那你就应该从打工、自学或上网的过程中寻求学习和实践的机会。在网上可以找到许多实践项目,例如,有一批爱好编程的学生建立了一个讨论软件技术的网站(www.diyinside.com),在其中共享他们的知识和实践经验,并成功举办了很多次活动(如在各大高校举办校园技术教育会议),还出版了帮助学生提高技术、解答疑难方面的图书,该网站有多位成员获得了“微软最有价值的专家”的称号。


 

培养兴趣:开拓视野,立定志向

   孔子说:“知之者不如好之者,好之者不如乐之者。”我在“给中国学生的第三封信”中曾深入论述了快乐和兴趣是一个人成功的关键。如果你对某个领域充满激情,你就有可能在该领域中发挥自己所有的潜力,甚至为它而废寝忘食。这时候,你已经不是为了成功而学习,而是为了“享受”而学习了。在“第三封信”中,我也曾谈到我自己是如何在大学期间放弃了我不感兴趣的法律专业而进入我所热爱的计算机专业学习的。

   有些同学问我,如何像我一样能找到自己的兴趣呢?我觉得,首先要客观地评估和寻找自己的兴趣所在:不要把社会、家人或朋友认可和看重的事当作自己的爱好;不要以为有趣的事就是自己的兴趣所在,而是要亲身体验它并用自己的头脑做出判断;不要以为有兴趣的事情就可以成为自己的职业,例如,喜欢玩网络游戏并不代表你会喜欢或有能力开发网络游戏;不要以为有兴趣就意味着自己有这方面的天赋,不过,你可以尽量寻找天赋和兴趣的最佳结合点,例如,如果你对数学有天赋但又喜欢计算机专业,那么你完全可以做计算机理论方面的研究工作。

   最好的寻找兴趣点的方法是开拓自己的视野,接触众多的领域。唯有接触你才能尝试,唯有尝试你才能找到自己的最爱。而大学正是这样一个可以让你接触并尝试众多领域的独一无二的场所。因此,大学生应当更好地把握在校时间,充分利用学校的资源,通过使用图书馆资源、旁听课程、搜索网络、听讲座、打工、参加社团活动、与朋友交流、使用电子邮件和电子论坛等不同方式接触更多的领域、更多的工作类型和更多的专家学者。当年,如果我只是乖乖地到法律系上课,而不去尝试旁听计算机系的课程,我就不会去计算机中心打工,也不去找计算机系的助教切磋,就更不会发现自己对计算机的浓厚兴趣。

   通过开拓视野和接触尝试,如果你发现了自己真正的兴趣爱好,这时就可以去尝试转系的可能性、尝试课外学习、选修或旁听相关课程;你也可以去找一些打工或假期实习的机会,进一步理解相关行业的工作性质;或者,努力去考自己感兴趣专业的研究生,重新进行一次专业选择。其实,本科读什么专业并不能完全决定毕业后的工作方向,正如我所强调的那样,大学期间的学习过程培养的是你的学习能力,只要具备了这种能力,即使从事的是全新的工作,你也能在边做边学的过程中获取足够的知识和经验。

   除了“选你所爱”,大家也不妨试试“爱你所选”。有些同学后悔自己在入学时选错了专业,以至于对所学的专业缺乏兴趣,没有学习动力;有些同学则因为追寻兴趣而“走火入魔”,毕业后才发现荒废了本专业的课程;另一些同学因为在学习上遇到了困难或对本专业抱有偏见,就以兴趣为借口,不愿意面对自己的专业。这些做法都是不正确的。在大学中,转系可能并不容易,所以,大家首先应尽力试着把本专业读好,并在学习过程中逐渐培养自己对本专业的兴趣。此外,一个专业里可能有很多不同的领域,也许你对专业里的某一个领域会有兴趣。现在,有很多专业发展了交叉学科,两个专业的结合往往是新的增长点。因此,只要多接触、多尝试,你也许就会碰到自己真正感兴趣的方向。“数字笔”的发明人王坚博士在微软亚洲研究院负责用户界面的研究,可是谁又能想到他从本科到博士所学的都是心理学专业,而用户界面又正是计算机和心理学专业的最佳结合点。另一方面,就算你毕业后要从事其他的行业,你依然可以把自己的专业读好,这同样能成为你在新行业中的优势。例如,有一位同学不喜欢读工科,想毕业后进入服务业发展,我就建议他先把工科读好,将来可以在服务业中以精通技术作为自己的特长。

   人生的路很长,每个人都可以有很多不同的兴趣爱好。在追寻兴趣之外,更重要的是要找寻自己终身不变的志向。有一本书的作者曾访问了几百个成功者,问他们有哪件事是他们今天已经懂得,但在年轻时却留下了遗憾的事情。在受访者的回答中,最多的一种是:“希望在年轻时就有前辈告诉我、鼓励我去追寻自己的理想和志向。”相比之下,兴趣固然关键,但志向更为重要。例如,我的志向是“使影响力最大化”,多年以来,我有许多兴趣爱好,如语音识别、对弈软件、多媒体、研究到开发的转换、管理学、满足用户的需求、演讲和写作、帮助中国学生等等,兴趣可以改变,但我的志向是始终不渝的。因此,大家不必把某种兴趣当作自己最后的目标,也不必把任何一种兴趣的发展道路完全切断,在志向的指引下,不同的兴趣完全可以平行发展,实在必要时再做出最佳的抉择。志向就像罗盘,兴趣就像风帆,两者相辅相成、缺一不可,它们可以让你驶向理想的港湾。

 

积极主动:果断负责,创造机遇

   创立“开复学生网”时,我的初衷是“帮助学生帮助自己”。但让我很惊讶的是,更多的学生希望我直接帮他们做出决定,甚至仅在简短的几句自我介绍后就直接对我说:“只有你能告诉我,我该怎么做”。难道一个陌生人会比你更知道自己该怎么做吗?我慢慢认识到,这种被动的思维方式是从小在中国的教育环境中培养出来的。被动的人总是习惯性地认为他们现在的境况是他人和环境造成的,如果别人不指点,环境不改变,自己就只有消极地生活下去。持有这种态度的人,事业还没有开始,自己就已经被击败,我从来没见过这样消极的人可以取得持续的成功。


   从大学的第一天开始,你就必须从被动转向主动,你必须成为自己未来的主人,你必须积极地管理自己的学业和将来的事业,理由很简单:因为没有人比你更在乎你自己的工作与生活。“让大学生活对自己有价值”是你的责任。许多同学到了大四才开始做人生和职业规划,而一个主动的学生应该从进入大学时就开始规划自己的未来。

   积极主动的第一步是要有积极的态度。大家可以用我在“第三封信”里推荐的方法,积极规划自己的人生目标,追寻兴趣并尝试新的知识和领域。纳粹德国某集中营的一位幸存者维克托·弗兰克尔曾说过:“在任何特定的环境中,人们还有一种最后的自由,就是选择自己的态度。”

   积极主动的第二步是对自己的一切负责,勇敢面对人生。不要把不确定的或困难的事情一味搁置起来。比如说,有些同学认为英语重要,但学校不考试就不学英语;或者,有些同学觉得自己需要参加社团磨练人际关系,但是因为害羞就不积极报名。但是,我们必须认识到,不去解决也是一种解决,不做决定也是一个决定,这样的解决和决定将使你面前的机会丧失殆尽。对于这种消极、胆怯的作风,你终有一天会付出代价的。

   积极主动的第三步是要做好充分的准备:事事用心,事事尽力,不要等机遇上门;要把握住机遇,创造机遇。中国科技大学校长朱清时院士在大三时被分配到青海做铸造工人。但他不像其他同学那样放弃学习,整天打扑克、喝酒。他依然终日钻研数理化和英语。六年后,中国科学院要在青海做一个重要的项目,这时朱校长就脱颖而出,开始了他辉煌的事业。很多人可能说他运气好,被分配到缺乏人才的青海,才有这机会。但是,如果他没有努力学习,也无法抓住这个机遇。所以,做好充分的准备,当机遇来临时,你才能抓住它。

   积极主动的第四步是“以终为始”,积极地规划大学四年。任何规划都将成为你某个阶段的终点,也将成为你下一个阶段的起点,而你的志向和兴趣将为你提供方向和动力。如果不知道自己的志向和兴趣,你应该马上做一个发掘志向和兴趣的计划;如果不知道毕业后要做什么,你应该马上制定一个尝试新领域的计划;如果不知道自己最欠缺什么,你应该马上写一份简历,找你的老师、朋友打分,或自己审阅,看看哪里需要改进;如果毕业后想出国读博士,你应该想想如何让自己在申请出国前有具体的研究经验和学术论文;如果毕业后想进入某个公司工作,你应该收集该公司的招聘广告,以便和你自己的履历对比,看自己还欠缺哪些经验。只要认真制定、管理、评估和调整自己的人生规划,你就会离你自己的目标越来越近。

 

掌控时间:事分轻重缓急,人应自控自觉

   除了积极主动的态度,大学生还要学会安排自己的时间,管理自己的事务。一位同学是这么描述大学生活的:

“大学和高中相比似乎没有什么太大的区别,每天依旧是学习,每次考试后依旧是担心考试成绩……不同的只是大学里上网的时间和睡觉的时间多了很多,压力也小了很多。”


   这位同学并不明白,“时间多了很多”正是大学与高中之间巨大的差别。时间多了,就需要自己安排时间、计划时间、管理时间

   安排时间出了做一个时间表外,更重要的是“事分轻重缓急”。在《高效能人士的七个习惯》一书中,作者史蒂芬·柯维提出,“重要事”和“紧急事”的差别是人们浪费时间的最大理由之一。因为人的惯性是先做最紧急的事,但这么做会导致一些重要的事被荒废掉。例如,我认为这篇文章里谈到的各种学习都是“重要的”,但它们不见得都是老师布置的必修课业,采纳我的建议的同学们依然会因为考试、交作业等紧急的事情而荒废了打好基础、学习做人等重要的事情。因此,每天管理时间的一种好方法是,早上确定今天要做的紧急事和重要事,睡前回顾一下,这一天有没有做到两者的平衡。

   每个人都有许多“紧急事”和“重要事”,想把每件事都做到最好是不切实际的。我建议大家把“必须做的事”和“尽量做的事”分开。必须做的事要做到最好,但尽量做的事尽力而为即可。建议大家用良好的态度和宽广的胸怀接受那些你暂时不能改变的事情,多关注那些你能够改变的事情。此外,还要注意生物钟的运行规律,按时作息,劳逸结合,这样才能在学习时有最好的状态。

   大学四年是最容易迷失方向的时期。大学生必须有自控的能力,让自己交些好朋友,学些好习惯,不要沉迷于对自己无益的习惯(如网络游戏)里。一位积极、主动的中国学生在“开复学生网”上劝告其他同学:“不要玩游戏,至少不要玩网络游戏。我所认识的专业水平比较高的大学朋友中没有一个玩网络游戏的。沉迷于网络游戏是对于现实的逃避,是不愿面对自己不足的一面。我认为,要脱离网络游戏,就得珍惜自己宝贵的大学时间,找到自己感兴趣的方向,做一些有意义并能给自己带来满足感的事情。”
 

为人处事:培养友情,参与群体

   很多大学生入校时都是第一次离开父母,离开自己生长的环境。进入校园开始集体生活后,如何与同学、朋友以及社团的同事相处就成为了大学生学习内容的一部分。大学是大家最后一次可以在相对宽松的环境中学习、培养、训练如何与人相处的机会。在未来,人们在社会里、在工作中与人相处的能力会变得越来越重要,甚至超过了工作本身。所以,大学生要好好把握机会,培养自己的交流意识和团队精神。

   “人际交往能力不够强,人际圈子不够广,但又没有什么特长可以引起大家的注意,在社团里也不知道怎么和其他人有效地建立联系。”这是一些大学生在人际交往方面经常遇到的困惑。对于如何在大学期间提高人际交往能力,我的建议是:

   第一,以诚待人,以责人之心责己、以恕己之心恕人。对别人要抱着诚挚、宽容的胸襟,对自己要怀着自我批评、有过必改的态度。与人交往时,你怎样对待别人,别人也会怎样对待你。这就好比照镜子一样,你自己的表情和态度,可以从他人对你流露出的表情和态度中一览无遗。你若以诚待人,别人也会以诚待你。你若敌视别人,别人也会敌视你。最真挚的友情和最难解的仇恨都是由这种“反射”原理逐步造成的。因此,当你想修正别人时,你应该先修正自己。你想别人怎么对你,你就应该怎么对人。你想他人理解你,你就要首先理解他人。

   第二,培养真正的友情。如果能做到第一点,很多大学时的朋友就会成为你一辈子的知己。在一起求学和寻求自身发展的道路上,这样的友谊弥足珍贵。交朋友时,不要只去找与你性情相近或只会附和你的人做朋友。好朋友有很多种:乐观的朋友、智慧的朋友、脚踏实地的朋友、幽默风趣的朋友、激励你上进的朋友、提升你能力的朋友、帮你了解自己的朋友、对你说实话的朋友等等。此外,大学时谈恋爱也可以教你如何照顾别人,增进同理心和自控力,但恋爱这件事要随缘,不必为了谈恋爱而谈恋爱。

   第三,学习团队精神和沟通能力。社团是微观的社会,参与社团是步入社会前最好的磨练。在社团中,可以培养团队合作的能力和领导才能,也可以发挥你的专业特长。但更重要的是,你要做一个诚心诚意的服务者和志愿者,或在担任学生工作时主动扮演同学和老师之间沟通桥梁的角色,并以此锻炼自己的沟通能力,为同学和老师服务。这样的学习过程也不会很轻松,挫折是肯定有的,但是不要灰心,大学社团里的人际交往是一种不用“付学费”的学习,犯了错误也可以重头来过.

   第四,从周围的人身上学习。在班级里、社团中,多观察周围的同学,特别是那些你觉得交往能力和沟通能力特别强的同学,看他们是如何与人相处的。比如,看他们如何处理交往中的冲突、如何说服他人和影响他人、如何发挥自己的合作和协调能力、如何表达对他人的尊重和真诚、如何表示赞许或反对,如何在不冒犯他人的情况下充分展示个性等等。通过观察和模仿,你渐渐地会发现,自己的人际交往能力会有意想不到的改进。在学校里,每一个朋友都可以成为你的良师,他们的热心、幽默、机智、博学、正直、沟通、礼貌等品德都可以成为你的学习对象。同时那些你不喜欢的人和事也可以为你敲响警钟,警告你千万不要做那样的人和事。当然,你也应当慷慨地帮助每一个朋友,试着做他们的良师和模范。

   第五,提高自身修养和人格魅力。如果觉得没有特长、没有爱好可能会成为自己人际交往能力提高的一个障碍,那么,你可以有意识地去选择和培养一些兴趣爱好。共同的兴趣和爱好也是你与朋友建立深厚感情的途径之一。很多在事业上有所建树的人都不是只会闭门苦读的书呆子,他们大多都有自己的兴趣和爱好。我在微软亚洲研究院的同事中就有绘画、桥牌和体育运动方面的高手。业余爱好不仅是人际交往的一种方式,还可以让大家发掘出自己在读书以外的潜能。例如,体育锻炼既可以发挥你的运动潜能,也可以培养你的团队合作精神。如果真的没有什么兴趣爱好,那么,多读些好书丰富自己的知识也可以改进自己的人际交往能力,因为没有什么比智慧和渊博更能体现一个人的人格魅力了。

   所以,学会与人相处,这也是大学中的一门“必修课”。

 

对大学生们的期望

   踏入大学校门时,你还是一个忙碌的、青涩的、被动的、为分数读书的、被家庭保护着的中学毕业生。

   就读大学时,你应当掌握七项学习,学好自修之道、基础知识、实践贯通、兴趣培养、积极主动、掌控时间、为人处事。

   经过大学四年,你会从思考中确立自我,从学习中寻求真理,从独立中体验自主,从计划中把握时间,从交流中锻炼表达,从交友中品味成熟,从实践中赢得价值,从兴趣中攫取快乐,从追求中获得力量。

   离开大学时,只要做到了这些,你最大的收获将是“对什么都可以拥有的自信和渴望”。你就能成为一个有潜力、有思想、有价值、有前途的中国未来的主人翁。

   所以,我认为大学四年应是这样度过。


--------------------------------------------------------------------------------
 
[1] VisiCalc是当时最热门的计算机应用软件,但它在二十年前就被淘汰了(这件事又一次证明了科技的发展是日新月异的)。而且,VisiCalc的使用方法也不是计算机系的学生应该学的。


 

posted @ 2006-12-14 14:33 重归本垒(Bing) 阅读(312) | 评论 (0)编辑 收藏
 

李开复2005年11月

有一位中国留学生看完了我《写给中国学生的第三封信》后,感触很深,他写了一封信给我说:“很小的时候,我的目标就是长大,长大了做什么,我当时没有想;读小学的时候,父母给我的目标就是考初中,考上初中做什么,我没有想过;读初中的时候,父母给我的目标就是考高中,考上高中做什么,我没有想过;读高中的时候,父母给我的目标就是考大学,考上大学做什么,我没有想过;上大学的时候,父母给我的目标就是要出国,出国做什么,我也没有想过;现在留学拿到了学位,要找工作了,下一步我该做些什么呢?这次,我要好好地想一想。谢谢你的第三封信,它唤醒了我埋藏了25年的进取心,它改变了我25年来被动的生活方式。从今天开始,我要积极主动地为自己而生活!”
  当我为这位中国留学生终于理解他“有选择的权利”感到欢欣鼓舞的时候,我不禁想到,还有更多的年轻人依然在被动的道路上迷茫地生活着。在“开复学生网”我每天都看到:“只有你能告诉我,我该怎么做。”的被动思维。
  在中国的教育体制下,学生们事事要听从父母和老师的安排,遇到问题也可以直接从父母和老师那里获得帮助,这很容易养成被动的习惯。因此,许多中国年轻人不善于主动规划自己的成长路线,不知道如何积极地寻找资源,使自己的学业和人生迈上更高的阶梯。
  另一方面,中国的父母和老师习惯于使用越俎代庖的方式,帮助孩子设计人生规划,这通常会使很多人忽视了自己真正的性格和兴趣,当这些孩子长大以后,他们多半会发现,自己早已迷失在“自我缺失”的海洋里了。
  此外,中国的传统文化强调群体意识,大力推崇“从上”、“从众”等行为方式,这些思想潜移默化地影响着一代又一代的青年,以至于许多年轻人觉得,“自主”这两个字是那么陌生和遥远。
  所以,消极到积极之路是充满荆棘的。虽然在我的前四封信都有提到积极主动的重要性,我决定特别写一封有关积极主动的信。
  为了成为国际化的人才,为了在信息时代发挥自己的最大潜能,每一个有进取心的中国青年都应该努力迫使自己从被动转向主动,大家必须成为自己未来的主人,必须积极地管理自己的学业和未来的事业——没有人比你自己更在乎你的工作与生活,没有人比你自己更适于管理你的人生和事业,只有积极主动的你,才能找到真正的“自我”,才能让自己在成功的道路上永远快乐!
什么是积极主动?

消极被动的人 积极主动的人
自己和环境 自己受环境的左右 自己有选择的权利
人和事 事情主导人 人可以主导或推动事情的进展
遇到问题时 寻求帮助 独立思考
环境不好时 怨天尤人 积极进取
自常说的话 只有你可以告诉我该怎么做。
我必须服从环境的安排。
谁可以告诉我该选什么专业?
怎么都没有人注意到我?
我总是没时间做某事。
只有你可以告诉我该怎么做。
我父母都有糖尿病,我也一定会得。
一切靠自己,我可以做得更好。
我有选择的权利。
我要制定一个计划,以选择最适合我的专业。
我要去学习如何引起人们的重视。
我该放弃哪些不重要的事,才能做最重要的事?
只有我自己才有权利和责任决定我该怎么做。
虽然父母有糖尿病,但只要注意锻炼,注意饮食,就能降低得病的几率。
  消极被动(Reactive)的人总是认为自己受环境和他人的左右,如果别人不指点,环境不改变,自己就只有消极地生活下去。碰到问题的时候,消极被动的人总会找人帮着决定,环境不好的时候,他们就会怨天尤人。他们总是在等待命运安排或贵人相助。对一件事情,他们总认为是事情找上他们,自己无法主导或推动事情的进展。
  积极主动(Pro-active)的人认为,无论在任何情况下,自己总有选择的权利。所以,他们对自己总是有一份责任感,因为命运操纵在自己的手里,而自己并不是环境或他人的附庸。对一件事情,他们总是认为,自己可以主导事情的发生、发展。
为什么要积极主动?
三十年前,在工业社会里,每位员工是企业的机器里的一个齿轮。虽然机器需要齿轮,但是齿轮是可替换的。最好的齿轮是耐用的,不是卓越的。因此这些公司最喜欢的人才是:
一个有专业知识的、能够埋头苦干的人。

  斗转星移,在今天这个瞬息万变的时代里,人们对人才的定义已经发生了很大的变化,因为在现代化的企业中,有更多的人享有决策的权利,有更多的人必须在思考中不断创新,也更多的人有足够的空间来决定要做什么、要怎么做……大多数人的工作不再是机械式的重复劳动,而是需要独立思考、自主决策的复杂过程。著名的管理学家彼得?德鲁克(Peter Druker)曾指出:“未来的历史学家会说,这个世纪最重要的事情不是技术或网络的革新,而是人类生存状况的重大改变。在这个世纪里,人将拥有更多的选择,他们必须积极地管理自己。”所以,今天大多数优秀的企业对的人才的期望是:

积极主动、充满热情、灵活自信的人。

  要想在现代化的企业中获得成功,就必须努力培养自己的主动意识:在工作中要勇于承担责任,主动为自己设定工作目标,并不断改进方式和方法;此外,还应当培养推销自己的能力,在领导或同事面前要善于表现自己的优点,
  作为当代中国的青年一代,你应该不再只是被动地等待别人告诉你应该做什么,而是应该主动去了解自己要做什么,并且规划它们,然后全力以赴地去完成。想想今天世界上最成功的那些人,有几个是唯唯诺诺、被动消极的人?对待自己的学业和研究项目,你需要以一个母亲对孩子那样的责任心全力投入、不断努力。只要有了积极主动的态度,没有什么目标是不能达到的。
  其实,许多年轻人并不是没有积极主动的态度做出自己的决定,而是不习惯在重大问题上做出自己的决定。如果我问一位中国的大学生:“你最常做的决定是什么?”他的回答很有可能是决定买什么样的电脑,看什么电影,读什么书等等。这些事情固然需要做出决定,但是,许多更重要的决定更需要由你自己做出。例如,像读什么专业,读什么学校,考研还是出国等决定,大家可能习惯于听父母的安排,或参考大多数同学的选择——殊不知,在这些最重要的问题上,只有你自己的决定才能帮助你迈向真正的成功。自己做无关紧要的决定,但是对一生有重大影响的决定却听他人的。这是多么不合逻辑呀!此外,就算你自己做出了决定,也不见得你事先已经花了足够的时间调查和研究。鲁莽或草率的决定可能会让你后悔一辈子!
  当Google的创始人赛吉?布林(Sergey Brin)和拉里?佩奇(Larry Page)在电视上被访问时,记者问他们的成功应该归功于哪一所学校,他们并没有回答斯坦福大学或密西根大学,而回答的是“蒙台梭利小学”自由自在的学习没有任一消极输入的方式。在蒙台梭利教育的环境下,他们学会了“自己的事,自己负责,自己解决”是这样的积极教育方式赋予了他们鼓励尝试,积极自主,自我驱动的习惯,因而带来了他们的成功。
  所以,每一个年轻人都要拥有一个积极、主动的心,你必须善于规划和管理自己的事业,为自己的人生做出最为重要的抉择。没有人比你更在乎你自己的事业,没有什么东西像积极主动的态度一样更能体现你自己的独立人格。
  正如美国诗人惠特曼《草叶集》里所写的那样:“我不能,别的任何人也不能代替你走过那条路;你必须自己去走。”
积极主动的七个步骤
  要达到积极主动的境界,我建议大家按照下面图中所示的七个步骤,循序渐进地调整自己的心态,培养自己的习惯,学习把握机遇、创造机遇的方法,并在积极展示自我的过程中收获成功和快乐。

步鄹一:拥有积极的态度,乐观面对人生
  心理学家早已发现:一个人被击败,不是因为外界环境的阻碍,而是取决于他对环境如何反应。中国国家男子足球队前主教练米卢蒂诺维奇所说的“态度决定一切”就是这个意思。埋怨不会改变现实,但是积极的心态和行动可能改变一切。
根据心理学家的统计,每个人每天大约会产生5万个想法。如果你拥有积极的态度,那么你就能乐观地、富有创造力地把这5万个想法转换成正面的能源和动力;如果你的态度是消极的,你就会显得悲观、软弱、缺乏安全感,同时也会把这5万个想法变成负面的障碍和阻力。
  消极的人允许或期望环境控制自己,喜欢一切听别人安排,但在这样的情况下,他不可能拥有控制自己命运的能力,也无法避免失败的厄运;相反的,积极的人总是以不屈不挠、坚忍不拔的精神面对困难,他的成功是指日可待的。积极的人总是使用最乐观的精神和最辉煌的经验支配、控制自己的人生;消极者则刚好相反,他们的人生总是处在过去的种种失败与困惑的阴影里。
  有了积极的态度,并不能保证事事成功。积极的态度肯定会改变一个人的生活方式,但并不能保证他每件事都心想事成;可是,坚持消极的态度却必败无疑,我从来没见过哪个持有消极态度的人能够取得可持续的、真正的成功。
  当然,不是每一件事情都必须由自己来选择,也不是每一件事情都可以由自己来主导。所以,在选择积极态度的同时,我们必须保持平和的心态,也就是我常说的那句话:
有勇气改变可以改变的事情,有胸怀接受不可改变的事情,有智慧来分辨两者的不同。

步鄹二:远离被动的习惯,从小事做起
  消极被动的习惯是积极主动最大障碍,如果你从小就在消极、被动的环境下长大,你就更应该努力剔除自身所拥有的那些消极因素。
  例如,消极被动的人总是迷信宿命论,把不如意的事情纷纷归罪于基因遗传、星座、血型等因素,并由此变得自怨自艾,总是怪罪别人的不是,指摘环境的恶劣——如果这样的想法成为习惯,他就会陷入消极被动的恶性循环,难以自拔。
  年轻人该如何远离消极被动?我想向大家提出五个建议:
一、不要盲目听信人言,应冷静辨析,积极求证
   现在,网上经常流传着各种谣言。如果盲目轻信这些谣言,你就会被某些别有用心的人左右。例如,有同学发信来说:“自己想读一个民办学校的课程,因为它可以发‘英国剑桥大学的学位’。”冷静辨析应该会告诉你:在这样“天上掉馅饼”的事情里总会暗藏着什么圈套。然后只要到搜索引擎积极求证,马上就可辨其真伪。
  此外,有许多同学不懂得主动搜寻和验证信息的方法或重要性。有不少同学请我帮他找某某大学的信息,甚至,还有的同学向我询问某个单词的意义和用法——实际上,这些信息在网上只要简单搜索一下,就能找到答案。因此,当我每次查出答案后,总是告诫这些同学说:
  “如果你想知道什么,就自己到网上去找,不要急着去问别人;如果你听到了什么,不要盲目信从,应当自己主动去网上求证。”
二、不要让事情找上你,应主动对事情施加影响
  每一件发生在你身上的事都应该是因你的决定而发展、变化的,而不应该是因为你无所作为才变成现实的。
  有位同学告诉我说:“我申请了两个工作,其中,我比较喜欢的那份竞争激烈的工作,但同学们也都在争取那份工作。我现在只好选择等待,如果那家公司不聘请我,我就到另一家公司去。”
  我很惊讶地问他:“既然你很喜欢第一份工作,为什么你这么被动,只知道等待而不去主动争取呢?”
  不要忘了,被动就是弃权,不做决定也是一种决定。
  在微软工作的华人都知道郭蓓菁,一位小巧玲珑、年轻活泼的女孩。见她第一眼你可能很惊讶她是微软最资深的华人经理之一。但是如果你和她交谈一分钟,你就会一点也不惊讶了。她讲的每一句话流露了自信和积极乐观的领导力,和严谨的逻辑和战略思想。她曾告诉我她积极主动的一个故事:
  “我十六岁从中国移民到美国。我到美国后六个月就必须参加SAT考试。那时我英语口语已经不差,但是文法、字汇、作文都很不行。虽然我的SAT数学考了780分(接近满分800分),但是英语只考了280分。如果交白卷也有200分,你就可以想象280分是多么糟糕!但是我依然满怀希望地申请了加州大学的电机工程系。”
  “由于我的英语SAT分数太低,我的申请表很可能没有被阅读就被直接被拒绝了。但是我不服输,我深信如果我被录取,我会是一个成功的工程师。于是,我决定‘上诉’。”
  “我直接写了一封信给加州大学的工学院长。在信里,我做了自我介绍,我自豪地描述了我在理工方面的成就,解释了我刚到美国六个月的英语问题,强调了我的学习能力和刻苦精神。最后,我说:‘院长女士,如果你录取我,我保证我会成为贵校的的财产。’”
  “两天后,院长约谈了我。我和她面谈时,她看出我的英语其实已经进步很快。我对她当面保证我的英语会学的和美国同学一样好。一星期后,加州大学收回成命,决定录取我。”
三、不要习惯性地同意或追随别人,应当学会“有主见”
  年轻人必须知道自己喜欢什么、需要什么,而不应当随波逐流。
  许多同学有很强的“从众”心态,自己有想法不表达,时间久了甚至都不清楚自己的想法是什么了。他们每次都会习惯性地先问别人:“你怎么想?”而从不会问问自己:“我怎么看?”
  要改掉这个习惯,你就需要下定决心,每一件小事都要表达出自己的意见,就算你不是很在乎。例如,自己决定在餐馆点什么菜,自己决定自己的衣着打扮,周末时自己决定要去哪里玩,等等。你应该学会对自己的生活做出合理的安排,而不是“别人怎样我就怎样”。当自己感觉“无所谓”,想依从别人的意见时,记得提醒自己,一定要把自己的选择展现出来。甚至在自己不是很在乎或不是很确定时,也要正确表达出自己的想法。让“无所谓”这个词从你的字汇里消失。
  不要被别人影响,也不要觉得自己一定要“从众”。如果和朋友出去吃饭,大家都不要甜点,但是你想吃,那么,千万不要因为别人的决定而影响你自己意见的表达。有没有什么人总是喜欢告诉你该做什么?如果有,下定决心,要求他们不要再这么做。如果他们不听,那就不要和他们在一起。
  也就是说,大家要设法让自己潜意识里的“我感觉,我想要”体现出来,不要被动,不要从众,避免盲目听从父母、老师、名人……答应自己,当你认为必须说“No”的时候,千万不要说“Yes”。从小事到大事,你如果都能做到听从自己的意愿,日子久了,你就会养成积极主动的习惯。
四、不要说“我办不到”,应当积极去尝试
  遇到困难时,不要找借口,应该多想一想,有没有别的解决方案?能不能将问题分解开来,一步一步地加以解决?或者,是否需要先提高自己在某方面的能力,然后再回头来处理这个难题?不要因为逃避而说自己没有选择或没有时间——没有人缺少时间,只不过,每个人分配时间的方式有所不同而已。
五、使用语言下意识地训练自己
  在史蒂芬•柯维的《高效能人士的七个习惯〉中,他提出:我们的语言会下意识地引导我们的思想,也会真切地反映一个人对环境的态度。
  习惯于消极被动的人,言语中就会流露出推卸责任的个性。
  例如,他们在生气时会抱怨说:“他使我怒不可遏!”——他们想说的其实是:责任不在我,是外力左右了我的情绪。
  他们总是抱怨:“我没时间。”——这表明:又是外力控制了我,让我没有选择的机会。
  他们还喜欢说:“我不得不如此。”——这其实意味着:迫于环境或他人的压力,我只好选择服从。
  他们在自我表白的时候说:“我就是这样的人。”——这其实是在宣称:我已经无法改进或提高自己了。
  相反,积极主动的人总是在言语中赋予自己决定的权利,他们喜欢说的话包括:“试试看有没有其他的可能性。”“也许我可以换个思路。”“我可以控制自己的情绪。”“我可以想出更有效的表达方式。”“我的感觉是……”“我选择……”“我要……”“我情愿……”“我打算……”“我决定……”等等。
  所以,我们要多学习积极主动者的讲话方式,在说话时多用“我……”的句式,多给自己决定的权利,少推卸责任,少埋怨。
步鄹三:对自己负责,把握自己的命运
  有位学生问我:“这个世界到底是不是公平的?”这个问题在“开复学生网”上引起了一场大讨论。有些同学认为世界公平,一个人只要有志气就一定能克服一切障碍;也有些同学认为世界级端不公平,因为无论是财富、天赋还是运气,老天爷好像总是青睐别人。
  对此,我的回答是:一切都靠命运(宿命论)和一切都靠自己(人定胜天)都是不合适的。
  每一个人都有选择,都有机会,但是,先天和环境因素造成每个人的机会多少不同。所以,这个世界不是完全公平的。但如果你因为世界不公平而放弃了自己的机会和选择,那就是你自己的责任,就不能怪世界不公平了。
  举一个比喻。有些人出生时就因为遗传的原因,可能会在某个时候患上较严重的疾病。但这并不表明他一定会患病。如果他能把握机会,做正确的选择,安排好自己的锻炼和饮食,他很可能比谁都健康;但是,如果他就因为‘基因不好’就自暴自弃,那么他得病的几率几乎一定会成倍增加。
  所以,凡事都要想清楚,什么是自己不能改变而必须接受的,什么是自己可以选择的,什么是自己必须勇敢挑战的。当你碰到不可改变的事情时,要勇敢地接受它,不要把时间浪费在悔恨、羡慕和嫉妒上。你应该做的事是积极主动地抓住命运中你可以选择、可以改变、可以最大化你的影响力的部分。
  还有,就算在最艰苦的时候,当你感觉命运已抛你而去时,你总是有选择的。就像弗兰克说的:“在任何极端的环境里,人们总会拥有一种最后的自由,那就是选择自己的态度的自由。”
  “积极主动”的含义不仅限于主动决定并推动事情的进展,还意味着人必须为自己负责。责任感是一个很重要的观念,积极主动的人不会把自己的行为归咎于环境或他人。他们在待人接物时,总会根据自身的原则或价值观,做有意识的、负责任的抉择,而非完全屈从于外界环境的压力。
  对自己负责的人会勇敢地面对人生。大家不要把不确定的或困难的事情一味搁置起来。比方说,有些同学认为英语重要,但学校不考试时,自己就不学英语;或者,有些同学觉得自己需要参加社团锻炼沟通能力,但因为害羞就不积极报名。对此,我们必须认识到,不去解决也是一种解决,不做决定也是一个决定,消极的解决和决定将使你面前的机会丧失殆尽,你终有一天会付出沉重的代价。
  有同学问我:“不确定时,该如何负责?”其实,就算你不确定自己想要什么,你至少应该知道自己不要什么;就算你不能积极争取你最想要的,至少也应积极避免你最不想要的。
如果你想做一个积极主动、对自己负责的人,我建议你立即行动起来,按照以下几点严格要求自己:

  • 以一整天时间,倾听自己以及四周人们的语言,注意是否有“但愿”、“我办不到”或“我不得不”等字眼出现。
  • 依据过去的经验,设想一下,自己近期内是否会遭遇一些令人退缩逃避的情况?这种情况处在你自己的影响范围之内吗?你应该如何本着积极主动的原则加以应对?请在脑海中一一模拟。
  • 从工作或日常生活中,找出一个令你备感挫折的事情。想一想,它属于哪一类,是可以直接控制的事情,还是可以间接控制的事情,抑或根本无法控制的事情?然后在自己的影响范围内寻找解决方案并付诸行动。
  • 锻炼自己积极主动的意识。在下30天内,专注于自己影响范围内的事物,对自己许下承诺,并予以兑现;做一支照亮他人的蜡烛,而非评判对错的法官;以身作则,不要只顾批评;解决问题,不要制造问题;不必怪罪别人或为自己文过饰非,不怨天,不尤人;别活在父母、同事或社会的荫庇之下,善用天赋的独立意志,为自己的行为与幸福负责。试行积极主动的三十天训练法,观察一下,自己的影响范围在训练之后是否有所变化?
    步鄹四:积极尝试,邂逅机遇
      在和学生的交流中,我发现,一些学生因为受到一些挫折就丧失了奋斗的勇气。例如,有的学生因为应试教育在大学中延续而后悔念大学,有些学生因为专业不合适就虚度时光,还有的学生因为在研究生期间遇到种种学术上难题而感到气馁……不知道大家有没有想过,这些都是可以直面的挫折,它们都需要你具有积极主动的态度。生命中随处是机遇,许多机遇就藏在一个又一个挫折之中,如果你在挫折面前气馁,你很可能会与自己的机遇擦肩而过。
      积极尝试是学习最好的方法。在一个先进的公司,你不需要担心失败。在一项美国公司的首席执行官的调查中发现,他们最欣赏的就是那些主动要求做某项新工作的员工。无论是否能做好,至少这些员工比那些只会被动接受工作的员工要令人欣赏,因为他们有勇气、积极上进,而且会从中学习。
      对于那些正在选择人生道路的年轻人来说,他们更应该积极地尝试不同的事情。在美国,父母经常说的一句话是:“你没有试过,怎么知道自己不喜欢呢?”所以,我建议大家充分利用自己的时间,尝试做不同的事情,找到通向成功的门径。只有这样,我们才能在人生之路上邂逅更多的机遇。
      我的积极主动的习惯是五岁开始的。记得五岁的时候,我觉得幼儿园的课程太简单了,于是就主动跟父母说:“我想跳级读小学。”父母建议我还是按部就班地读书,等到有足够的能力时再去读小学。为了学到更多的知识,我大胆地提出:“让我尝试一下好吗?如果我的能力不够,我就没法通过小学的入学考试;可如果我通过了考试,就表明我有这样的能力,那你们就应该让我去读小学。”父母很爽快地答应了下来。于是我努力读书,最后以高分考进了私立小学。事过三十多年,当时母亲带我去看“放榜”时,看到“李开复”三字排在榜首的那份兴奋,今天想来依然历历在目。这件事让我懂得,只要大胆尝试,积极进取,我就有机会得到我期望中的成功。这也为我日后的自信和积极奠定了坚实的基础。
      另外一个例子来自于我的年轻朋友郭去疾。他的人生之学是:每一扇机遇之门,都有一个守门人。收获机遇的临门一脚,在于主动执著地去找这个守门人。当他1999年从中国科技大学本科毕业时,受到了很多美国一流大学的录取通知,但是一律没有奖学金。于是,他开始给这些大学的教授们写信,希望他们能接受我作为研究助理从而资助。一个月中,他写了两百封信,虽然有很多教授感兴趣,却都因为他研究经验不足而拒绝了。他还尝试写信给中国科大的海外校友,希望得到推荐,也没有结果。一天夜里,面对电脑里一封封挽拒的邮件,他一个人在黑暗的实验室里失声痛哭。然而第二天醒来,他决定继续去敲击这扇机遇之门。几天之后,他收到伊利诺大学的一位教授的回信,欣然答应资助。那位教授说,当他到系里索取郭去疾的材料的时候,发现系里正在准备给郭寄拒信。郭去疾最后说:“我的‘叩门之旅’在继续着,绝大多时候,都无功而返。然而,石沉大海却不代表徒劳无功,因为一次一次,机会之门这样被我敲开。一步一步,我得以到微软总部工作,到斯坦福大学读MBA,到Mckinsey到Amazon和Google工作的机会”。
      美国人很喜欢尝试不同的工作,他们一生中平均要换四次工作。在长期计划经济的思想影响下,更多的中国人不愿意换工作,而更倾向于终生做一件事。其实,换工作岗位的意义在于,你一开始做的决定并不一定是你的终生决定,你仍然有机会去尝试更多的东西,只有这样才能真正找到自己的兴趣所在,才能最大限度地发挥自己的潜力。
      所以,不要因为暂时不了解自已的长处而犹疑不决,积极行动起来吧!你会发现自己的才华和天赋。大家要珍惜每一次尝试,因为机遇往往不可复制。要随时做好准备,以免机遇到来时错失良机,同时也应学会从每一个失去的机遇中吸取教训。此外,只有敢于挑战自我,你才能充分地开发自身的潜力。我建议大家经常给自己设立一些极具挑战性、但绝非遥不可及的目标。
    步鄹五:充分准备、把握机遇
      不要坐等机遇上门,因为那是消极的做法。屠格涅夫说:“等待的方法有两种,一种是什么事也不做地空等,另一种是一边等,一边把事情向前推动。”也就是说,在机遇还没有来临时,就应事事用心,事事尽力。
      如果被苦难或挫折阻挡,我们应该学习把挫折转换成动力,而不要一遇到困境就躲在阴暗的角落里怨天尤人,更不要在需要立即行动的时候犹豫不决。人生不能用这种消极的方式度过。我们终有一天要面对自己,对自己的生命负责。因此,我们必须在平时做好充分的准备,掌握足够的信息,以便在必要时做出最好的抉择,把握住稍纵即逝的机遇。
      一旦机遇到来,一定要全力以赴,把握机遇。
      我在攻读博士学位时,通过自己的努力(和同学洪小文的帮助),把语音识别系统的识别率从以前的40%提高到了80%,学术界对我的工作给予了充分的肯定。当时,有些老师认为,只要把已有的结果加工好,写好论文,几个月之内我就可以拿到博士学位了。
      但是,我很清楚,第一步的成功给我提供的只是一个机遇,而不是一个答案,因为80%的识别率决不是最后的最佳结果,因为我用的方法只是冰山一角。而且,我已经公开发表了我的研究成果,每一个研究机构都会学习、使用我的方法,所以,如果我此时放松下来,不再做实验,埋头写论文以求尽快毕业的话,别的学校或公司很快就会超过我。
      所以,我不但没有放松,反而更加抓紧时间研究攻关,甚至为此推迟了我的论文答辩时间。那时候,我每周工作七天,每天工作16个小时。这些努力没有白费,它们让我的语音识别系统百尺竿头更进一步,识别率从80%提高到了96%。在我毕业之后,这个系统多年蝉联全美语音识别系统评比的冠军。如果我当时在80%的水平上止步不前,随随便便就毕业的话,后来商业周刊颁发的“1988年最重要科技创新奖”就肯定会让别人抢走了。
      所以,当你知道机遇来临的时候,要积极把握;当你尚未看到机遇的时候,要时刻准备。
    步鄹六:积极争取,创造机遇
      当机遇尚未出现时,除了时刻准备之外,我们也应该主动为自己创造机遇,不能总是守株待兔,等着机遇上门。
      记得当我在苹果工作时,有一段时间公司经营状况不佳,大家士气低落。这时,我看到了一个机遇:公司有许多很好的多媒体技术,但是因为没有用户界面设计领域的专家介入,这些技术无法形成简便、易用的软件产品。
      于是,我写了一份题为《如何通过互动式多媒体再现苹果昔日辉煌》的报告。这份报告被送到多位副总裁手里,最后,他们决定采纳我的意见,发展简便、易用的多媒体软件,并且请我出任互动多媒体部门的总监。
      多年以后,一位当年的上司见到我,他深有感触地对我说:“当时,看到你提交的报告,我们感到十分惊讶。以前,我们一直把你当作语音技术方面的专家,没想到你对公司战略的把握也这么在行。如果不是这份报告,公司很可能会错过在多媒体发展的机会,你不会有升任总监和副总裁的可能。今天,在iPod的成功里,也有不小的一部分要归功于你和你那份价值连城的报告。”
      在微软公司,大家都很重视向比尔•盖茨每年四次的汇报工作成果的机会。在报告的几个月前,全球各研究院就开始提早排队,报上最得意的成果。
      微软中国研究院刚成立的那一年,当几个研究项目都还没有得到最终结果的时候,我就冒险争取了六个月后向比尔汇报两个研究成果的机会。因为那时我知道很多人对中国研究院还不太理解,如果能在比尔面前成功地演示我们的研究成果,就会对研究院的发展提供很大的帮助。
      当时,我知道有四个研究项目各有60%以上的可能性在六个月后得到好的结果,但是,我不能等到100%确定后再去申请。于是,我用两个措辞含糊的报告题目预订了位置。六个月后,果然有两个项目得到了非常好的结果,于是,我们修改了报告题目,十多个人飞到美国为比尔做了现场演示。那次汇报非常成功,得到了比尔高度评价。
      报告的第二天,比尔对所有的公司领导说了他著名的那句话:“我敢打赌你们都不知道,在微软中国研究院,我们拥有许多位世界一流的多媒体研究方面的专家。”是这句话开始建立了研究院在公司的信誉的。
      显然,如果我总是消极地等待,那么,我们恐怕就要错过向比尔汇报研究成果的机会了。
      对大学生来说,大家应该积极地计划大学的四年,积极地争取和创造机遇。你的毕业计划将成为你学业的终点和事业的起点,你的志向和兴趣将为你提供方向和动力。你如果不知道你的志向和兴趣,应该马上做一个发掘志向和兴趣的计划;你如果不知道毕业后要做什么,应该马上制定一个尝试新领域的计划;你如果不知道自己最欠缺什么,应该马上写一份简历,找你的老师、朋友打分,看看哪里需要改进;如果你毕业后想出国读博士,你应该想想如何让自己在申请出国前有实际的研究经验和论文;如果你毕业后想到某个公司工作,那你应该找找该公司的聘请广告,和你的履历对比,看自己还欠缺什么经验……只要做到了这些,你就不难发现,自己每天都会比前一天离成功更近一些。
    步鄹七:积极地推销自己
      在全球化和信息化的时代里,那些能够积极推销自我的人更容易脱颖而出。
      很多在美国工作多年的中国人对美国同事的印象总是这样的:“他们怎么这么能说?他们充分地表达了自己的工作成绩,而中国同事在很多时候做得很好,却没有展现出来,这不能不说是一个遗憾。”
      在公司里,经常得到晋升机会的人,大多是能够积极推销和表达自己的、有进取心的人。当他们还是公司的一名普通员工时,只要和公司利益或者团队利益相关的事情,他们就会不遗余力地发表自己的见解、贡献自己的主张,帮助公司制定和安排工作计划;在完成本职工作后,他们总能协助其他人尽快完成工作;他们常常鼓励自己和同伴,提高整个队伍的士气;这些人总是以事为本、以事为先——他们都是最积极主动的人。
      要想把握住转瞬即逝的机会,就必须学会说服他人,向别人推销自己、展示自己的观点。一般说来,一个好的自我推销策略可以让自己的人生和事业锦上添花。好的自我推销者会主动寻找每一个机会,让老板或老师知道自己的业绩、能力和功劳。当然,在展示自己时,不要贬低别人,更不可以忘记团队精神。
      当我被微软总部调回美国,在美国启动总部把工作外包给中国合作伙伴的工作时,我一直在考虑如何把这项极为重要但又缺乏资源的项目做好。
      这时,我很意外地收到了一封毛遂自荐的信。这封信来自一位在微软技术支持中心工作的经理。她在信中说:“虽然我没有这方面的经验,但是我曾在多个部门工作,而且学习很快。我愿意用我自己的时间帮你把这件事情做好。我不需要酬劳,我也不是申请工作,我只是希望为中国做点事情。你选择我没有风险,因为我至少可以把每个细节都帮你想清楚,这样可以节约你的时间。”
      如果不是这封信和后来的交谈,我怎么也不会想到,把这个工作交给一位业余而又没有相关经验的人来做。事实证明,我的选择是对的。她没有辜负我的期望,把这件事情做得非常好。因为她起头的工作,微软后来三年中提供给中国的外包业务量增加了三倍。几个月后,当我们终于成立了一个部门来负责这件事情时,她毫无怨言地把所有的工作交给了这个新部门。
      后来,微软亚洲研究院有一个很好的工作机会,沈向洋院长要我推荐人选,我想到了这位多才多艺的志愿者。她就是今天微软亚洲研究院高校合作部总监宋罗兰。
      有些人可能会认为:“要求我们展示自己,这是不是要我从一个内向的人彻底转变为外向的人?”其实,一个内向的人很难彻底地改变自己的性格。所以,我建议大家可以在自身性格允许的范围内往“外向”靠拢,尽量寻找一些“比较外向但又不给自己带来太大压力”的机会。
    我的选择;你的选择
      2005年7月19日,我离开了微软,加入了Google。我在过去的几年中,一直希望回到中国。而且同时,我发现许多我的朋友加入了Google后都非常愉快。当我听说Google将在中国有很大的计划时,我没有等着它的电话,而我积极地直接联系了我认识多年的Google的CEO斯密特。他积极邀请我去看看。我发现,Google是一个让我震撼的公司 – 从它的新一代技术到员工的激情,从它诚信和对大众利益的执著,从它独有的自由和透明度,我发现了一片我向往的净土。我有选择的权利。于是,我选择了Google。我选择了中国。
      有记者问我这个选择带来不少麻烦,我会不会后悔。我的回答是:“直到我死的那一天,我要做我有激情的事情。对这个决定,无论带来多大的困扰和麻烦,我终身不悔。”
      在人生的旅途中,你是你自己惟一的司机,千万不要让别人驾驶你的生命之车。你要稳稳地坐在司机的位置上,决定自己何时要停、要倒车、要转弯、要加速、要刹车等等。人生的旅途十分短暂,你应该珍惜自己所拥有的选择和决策的权利,虽然可以参考别人的意见,但千万不要随波逐流。
      只有积极主动的人才能在瞬息万变的竞争环境中赢得成功,只有善于展示自己的人才能在工作中获得真正的机会。
     

     最后,我将下面一段话赠给中国的学生:

    你们的时间有限,所以不要浪费时间在别人的生活里。
    不要被信条所惑 – 盲从信条是活在别人的生活里。
    不要让任何人的意见淹没了你内在的心声。
    重要的,拥有跟随内心和直觉的勇气。
    你的内心与直觉知道你真正想成为什么样的人。
    任何其他事物都是次要的。
        斯蒂夫 乔布斯 (苹果公司总裁)
        2005年斯坦福大学毕业典礼

  • posted @ 2006-12-14 14:31 重归本垒(Bing) 阅读(376) | 评论 (0)编辑 收藏
     

    李开复2003年12月


    三年前离开中国时,我在《给中国学生的一封信》中,与广大青年学生一道,讨论了一些大家共同关心的话题,并结合自己的学习和工作经历,就青年学生如何对待机遇、学业、工作、他人、自己等问题,阐述了我的个人意见。我提出诚信和正直、主动意识、交流和沟通、努力一生学习这几个个人素质方面值得中国学生高度重视,

    在这三年,许多中国学生,经过电子邮件、讲座后的问答、座谈、和其他渠道(例如在电视节目“对话”中),常对我提到“如何成才”的问题。对于这个大家关注的问题,我整理了许多材料,集成这封“第二封信”。

    在第一封信力所提到的个人素质或“价值观”是成材的必要的基础。但是,除了素质之外,成才同样的需要领导能力(leadership)。很多人误以为领导能力最重视的是天资、号召力、管理能力。但是,根据我个人的经验,和最近一些研究的结论,如果你想成为一名成功的领导,最重要的不是你的智商(IQ),而是你的情商(EQ)。最重要的不是要成为一个有号召力令人信服的领导,而是要成为一个有 “谦虚”、“执著”和“勇气” 的领导。

    这“给中国学生的第二封信”是为那些希望不断提高自己,不断学习事业成功所必需的基本技能和领导艺术的人所写的。第一部分重申了《给中国学生的一封信》中讨论过的有关个人素质的话题;第二部分阐释了领导能力中最重要的情商;第三部分给出了卓越的领导所必须具备的、有别于普通人的基本特质。


     

    如何提高个人素质
     

    诚信和正直

    一个人的人品如何直接决定了这个人对于社会的价值。而在与人品相关的各种因素之中,诚信又是最为重要的一点。微软公司在用人时非常强调诚信,我们只雇佣那些最值得信赖的人。去年,当微软列出对员工期望的“核心价值观”时,诚信(honesty and integrity)被列为一位。

    在我发表“第一封信”后,曾经有一位同学问我:为什么一个公司要涉入员工的道德呢?我回答:这是为了公司自己的利益。例如,一位应聘者在面试时曾对我说,如果他能加入微软公司,他就可以把他在前一家公司所做的发明成果带过来。对这样的人,无论他的技术水平如何,我都不会雇用他。他既然可以在加入微软时损害先前公司的利益,那他也一定会在加入微软后损害微软公司的利益。

    另外有一位同学看了“对话”后问我,为什么我会把诚信放在智慧之前呢?难道我们会去衡量员工的诚信和他们的智慧而给诚信更高的比重?其实,我们的衡量都在直接的工作目标上,并不会对诚信或智慧做直接的衡量。但是,作为第一“核心价值”,诚信是我们对员工最基本的要求。 我们根本不会去雇用没有诚信的人。如果一个员工发生了严重诚信的问题,他会被立刻解雇。

    当一个公司这么重视诚信,员工一定更值得信赖。因此,公司对员工也能够完全信任,让他们发挥自己的才能。在微软公司,公司的各级管理者都会给员工较大的自由和空间发展他们的事业,并在工作和生活上充分信任、支持和帮助员工。只要是微软录用的人,微软就会百分之百地信任他。和一些软件企业对员工处处提防的做法不同,微软公司内的员工可以看到许多源代码,接触到很多技术或商业方面的机密。正因为如此得到公司的信任,微软的员工对公司才有更强的责任心和更高的工作热情。



    培养主动意识

    坦白地说,中国的学生和职员大多属于比较内向的类型,在学习和工作中还不够主动。在学校时,学生们往往需要老师安排学习任务,或是按照老师的思路做课题研究。在公司里,中国职员常常要等老板吩咐做什么事、怎么做之后,才开始工作。此外,许多中国人并不善于推销和宣传自己,这恐怕和中国自古以来讲求中庸的文化氛围有很大关系。

    但是,要想在现代企业中获得成功,就必须努力培养自己的主动意识:在工作中要勇于承担责任,主动为自己设定工作目标,并不断改进方式和方法;此外,还应当培养推销自己的能力,在领导或同事面前要善于表现自己的优点,有了研究成果或技术创新之后要通过演讲、展示、交流、论文等方式和同事或同行分享,在工作中犯了错误也要勇于承认。只有积极主动的人才能在瞬息万变的竞争环境中获得成功,只有善于展示自己的人才能在工作中获得真正的机会。



    客观、直接的交流和沟通


    开诚布公的交流和沟通是团队合作中最重要的环节。人与人之间遮遮掩掩、言不由衷甚至挑拨是非的做法都会严重破坏团队中的工作氛围,阻碍团队成员间的正常交流,并最终导致项目或企业经营失败。

    比如,在开会讨论问题的时候,与会的所有人员都应当坦诚地交换意见,这样才能做出正确的决定。如果某个人因为考虑到某些其他因素(比如不愿反驳上级领导的意见)而在会议上不敢表达自己的观点,一味地唯唯诺诺,会后到了洗手间里再和别人说“其实我不同意他的观点”,这种戴着假面具工作的人不但不能坚持自己的观点,还会破坏公司内部的沟通和交流渠道,对工作产生负面的影响。

    微软公司有一个非常好的文化叫“开放式交流(Open communication)”,它要求所有员工在任何交流或沟通的场合里都能敞开心扉,完整地表达自己的观点。在微软开会时,大家如果意见的不统一,一定要表达出来,否则公司可能错过良机。当Internet刚开始时,很多微软的领导者不理解、不赞成花太多精力做这个“不挣钱”的技术。但是有几位技术人员,他们不断地提出他们的意见和建议,虽然他们的上司不理解,但是仍然支持他们“开放式交流”的权利。后来,他们的声音很快的达到比尔•盖茨的耳里,促成比尔改变公司方向,彻底支持Internet。从这个例子我们可以看到,这种开放的交流环境对微软公司保持企业活力和创新能力都是非常重要的。

    彻底的开放式交流也有缺点。开放式交流有时会造成激烈的辩论甚至是争吵,而吵到气头上有时会说出不尊重别人的语言,会破坏人与人之间的关系。因此,微软公司的总裁史蒂夫•鲍尔默去年在微软的核心价值观中,提出我们要把这种开放式交流文化改进成“开放并相互尊重(Open and respectful)”。这要求我们在相互交流时充分尊重对方。当我们不同意对方的意见时,一定要用建设性的语言提出。



    挑战自我、学无止境

    从一名大学生到一名程序员,再到一位管理者,在软件人才的成长历程中,学习是永无止境的。在大学期间,我们要打好基础,培养自己各方面的素质和能力;工作以后,我们应当努力在实际工作中学习新的技术并积累相关经验;即使走上了管理岗位,我们也应当不断学习,不断提高自己。软件产业本身就是一个每天都会有新技术、新概念诞生,充满了活力和创造力的产业。作为软件产业的从业人员,如果只知道闭门造车、抱残守缺,我们就必然会落伍,必然会被市场淘汰。

    许多中国学生喜欢与别人竞争,但这种竞争更多地表现为一种“零和游戏”,无法使自己和他人得到真正的提高。我建议大家最好能不断和自己竞争——不要总想着胜过别人,而要努力超越自我,不断在自身的水平上取得进步。

    在学习的过程中,打好基础最为重要。从软件产业对人才的需求来看,我们必须学好数学和英语这两门基础学科。数学是所有工程科学的基础,无论是软件产品的开发,还是软件技术的研究,都要大量使用数学方法和数学原理。英文则是软件行业中的国际语言,要想了解国际上软件技术的发展趋势,掌握最新的研究成果,或是与国外同行进行技术交流,就必须掌握英文的听、说、读、写,能够在工作中熟练使用英文来解决问题。

     


    情商和领导能力


    同学们都希望增进自己的leadership skills(领导能力)。从我的经验和一些最近的研究结果看来,领导能力中最重要的是所谓的“情商”( EQ)。

    智商(IQ)反映人的智慧水平,情商则反映了人在情感、情绪方面的自控和协调能力。在高新技术企业中,大家都知道智慧的重要,但是情商的重要性甚至超过了智商。我看过一篇文章,该文的作者调查了188个公司,他用心理学方法测试了这些公司里每一名员工的智商和情商,并将测试结果和该员工在工作上的表现联系在一起进行分析。经过研究,该文的作者发现,在对个人工作业绩的影响方面,情商的影响力是智商的两倍。此外,他还专门对公司中的高级管理者进行了分析。他发现在高级管理者中,情商对于个人成败的影响力是智商的九倍。这说明,智商略逊他人的人如果拥有更高的情商指数,也一样可以获得成功;反之,智商很高,但情商不足的人欠缺“领导能力”,很难成为一个成功的领导。


    什么是情商?
     

    在现代社会,如果你只知道智商而不晓得情商的话,你至少在意识上已经落伍了。许多心理学家早已明确地指出,单单使用智商的标准考察一个人在才智方面的表现,并不足以准确预测这个人在事业上可能取得的成就。为了全面考察个人能力,特别是考察个人在社会生活中的适应能力和创造能力,心理学家们提出了情商的概念。

    情商主要是指那些与认识自我、控制情绪、激励自己以及处理人际关系等相关的个人能力。在情商所描述的各项能力因素中,自觉、同理心、自律和人际关系是四种对现代人的事业成败起决定性作用的关键因素。

    智商是先天赋予的,但是情商是可以培养的。多花功夫理解和应用这四种情商的关键因素。除此之外,因为情商不是自己能看清楚的,我建议可多理解别人对你的看法、多吸取别人(尤其是情商高的人)的意见。


    自觉

    中国人常说,人贵有自知之明。这实际上是说,社会生活中的每个人都应当对自己的素质、潜能、特长、缺陷、经验等各种基本能力有一个清醒的认识,对自己在社会工作生活中可能扮演的角色有一个明确的定位。心理学上把这种有自知之明的能力称为“自觉”,这通常包括察觉自己的情绪对言行的影响,了解并正确评估自己的资质、能力与局限,相信自己的价值和能力等几个方面。

    我的下属中有一个“自觉心”明显不足的人:他虽然有一些能力,但是他自视甚高,总是对自己目前的职位不满意,随时随地自吹自擂,总是不满现状。前一段时间,他认为我不识才,没有重用他,决定离开我的组,并期望在微软其他组中另谋高就。但是,他最终发现,自己不但找不到更好的工作,公司里的同事也都对他颇有微辞,认为他缺少自知之明,期望和现实相距太远。最近,他沮丧地离开了公司。接替他职位的人,是一个能力很强,而且很有“自觉心”的人。虽然这个人在上一个职位工作时不很成功,但他理解自己升迁太快,愿意自降一级来做这份工作,以便打好基础。他现在的确做得很出色。

    简单地说,一个人既不能对自己的能力判断过高,也不能轻易低估自己的潜能。对自己判断过高的人往往容易浮躁、冒进,不善于和他人合作,在事业遭到挫折时心理落差较大,难以平静对待客观事实;低估了自己的能力的人,则会在工作中畏首畏尾、踟蹰不前,没有承担责任和肩负重担的勇气,也没有主动请缨的积极性。无论是上述哪一种情况,个人的潜力都不能得到充分的发挥,个人事业也不可能取得最大的成功。

    有自知之明的人既能够在他人面前展示自己的特长,也不会刻意掩盖自己的欠缺。谈成自己的不足而向他人求教不但不会降低了自己,反而可以表示出自己虚心和自信,赢得他人的青睐。比如,当一个领导对某个职员说“在技术上你是专家,我不如你,我要多向你学习”的时候,职员不但认为这个领导非常谦虚,也一定会对这个领导更加信任,因为他理解自己的能力。

    在微软公司,大家在技术上互帮互学,在工作中互相鼓励,没有谁天天都摆出盛气凌人的架子,也没有谁自觉矮人一头,这就自然营造出了一种坦诚、开放的工作氛围。

    有自知之明的人在工作遇到挫折的时候不会轻言失败,在工作取得成绩时也不会沾沾自喜。认识自我,准确定位自我价值的能力不仅仅可以帮助个人找到自己合适的空间及发展方向,也可以帮助企业建立起各司其职、协同工作的优秀团队。有自知之明的人让人感觉他是一个自信、谦虚、真诚的人。



    同理心

    同理心(Empathy)是一个比较抽象的心理学概念,但解释起来非常简单:同理心指的是人们常说的设身处地、将心比心的做法。也就是说,在发生冲突或误解的时候,当事人如果能把自己放在对方的处境中想一想,也许就可以更容易地了解对方的初衷,消除误解。我们在生活中常说“人同此心,心同此理”,就是这个道理。

    人与人之间的关系没有固定的公式可循,要从关心别人、体谅别人的角度出发,做事时为他人留下空间和余地,发生误会时要替他人着想,主动反省自己的过失,勇于承担责任。只要有了同理心,我们在工作和生活中就能避免许多抱怨、责难、嘲笑和讥讽,大家就可以在一个充满鼓励、谅解、支持和尊重的环境中愉快地工作和生活。

    对于软件企业中的管理者来说,体现同理心的最重要一点就是要体谅和重视职员的想法,要让职员们觉得你是一个非常在乎他们的领导。拿我自己来说,我在工作中不会盲目地褒奖下属,不会动不动就给职员一些“非常好”、“不错”、“棒极了”等泛泛的评价,但是我会在职员确实做出了成绩的时候及时并具体地指出他对公司的贡献,并将他的业绩公之于众。例如,我会给部门内的全体职员发电子邮件说某个员工在上一周的工作中取得了出色的成绩,并详细说明他的工作成果,列举他的工作对于公司的重要价值,给出具体的表彰意见。这种激励员工的方式能够真正赢得员工的信任和支持,能够对企业的凝聚力产生巨大的影响。

    同理心也是一种了解和认识他人的有效方法。我被调到新部门担任领导职位的时候,部门中有400多名员工,我都不认识。于是,我每周选出了10名员工,与他们共进午餐。在午餐时,我详细了解了每一个人的姓名、履历、工作情况以及他们对部门工作的建议。这些信息对于一个部门领导来说非常重要。在午餐会后,我立即根据这10名员工对部门的建议,安排部署相关的工作,并给这10名员工一一发回反馈意见,告诉他们我的处理方法。我的计划是在一个不长的时间里,认识并了解部门中的每一位员工,并在充分听取员工意见的基础上合理地安排工作。


    自律

    自律(Self-Regulation)指的是自我控制和自我调整的能力。这包括:自我控制不安定的情绪或冲动,在压力面前保持清晰的头脑;以诚实赢得信任,并且随时都清晰地理解自己的行为将影响他人。

    自律对于领导者来说更为重要。作为软件企业的领导,要管理别人,要让下属信服,就要先从自我做起。这是因为,领导的做法通常是大家做事的目标和榜样,领导的每一次举手投足都会给下属留下深刻的印象,如果处理不好的话,可能会造成负面的影响。特别是当公司或团队处于危急时刻,需要领导带领大家克服困难、冲出重围的时候,如果领导表现得比职员还要急躁,翻来覆去拿不定主意,大家就会对领导丧失信心,公司或团队也会因此而走向失败。

    有一次,我见过公司里的两个组即将被合并。第一个组的经理缺少自律,开会时对他的队伍说合并不是他的决定,他自己也不知下一步该怎么办。这个经理对未来没有信心,并猜测自己的队伍可能会被裁员。而第二个组的经理则在合并后告诉他的队伍这次合并对公司的好处。他也坦诚地说自己并不掌握所有的信息,但是他承诺会提醒上级尽快地做决定。并且,第二个经理还告诉大家他会尽其所能,帮助每一个员工安排最合理、最公平的出路。最后的结果是,第一个组的人很快就散了,他们的经理离开了公司,而第二个组的经理接管了合并后的机构。

    自律必须建立在诚信的基础上。为了表现所谓的“自律”而在他人面前粉饰、遮掩自己的缺点,刻意表演的做法是非常不可取的。只有在赢得他人信任的基础上,严于律己、宽以待人,才能真正获得他人的尊重和赞许。



    人际关系

    人际关系包括在社会交往中的影响力、倾听与沟通的能力,处理冲突的能力、建立关系、合作与协调的能力,说服与影响的能力等等。

    有些人在人际交往中的影响力是与生俱来的,他们在参加酒会或庆典的时候,只要很短的时间就能和所有人交上朋友。但也有些人并不具备这样的天赋,他们在社交活动中常常比较内向,宁愿一个人躲在角落里也不愿主动与人交谈。

    我个人就缺乏人际交往的倾向。以前,我并不认为这有什么不妥,直到我遇到了一位非常具有个人影响力的经理为止。那个经理没有超人的智慧,但是他自称他认识了公司中几乎每一个有能力的人,并和其中的许多人成为了非常要好的朋友。我不知道他是怎么做到这一点的,但我很快就发现,他的这种能力对公司非常有用。比如,我需要在公司内部选拔一些职员到我的部门工作时,我就可以从他那里获得许多有关该职员的详细信息;与公司其他部门协调工作时,他的人际关系网也可以发挥非常大的作用。从那时起,我发现处理人际关系的能力对于一个人,特别是一个领导者来说非常重要,我开始特别注重培养自己在人际关系方面的影响力。

    在技术研究和开发方面,沟通和说服的能力也至关重要。比如,我们开发出了一项先进的技术,要把它变成公司的产品。这首先要说服公司的决策层。我们必须细心准备我们的产品建议书,并通过精彩的演讲和现场展示让领导者相信我们研究出的技术对公司来说大有裨益,让决策层认为即将开发的产品可以在市场上取得成功。这些工作都需要我们具备处理人际关系、展示自己、影响他人的能力。

     


    从优秀到卓越


    在著名企业管理学家吉姆·柯林斯的《从优秀到卓越》(中信出版社,2002年)一书中,作者通过大量的案例调查和统计,讨论并分析了一家企业或一位企业的领导者是如何从优秀(Good)上升到卓越(Great)的层次的。柯林斯和他的研究小组耗费了10.5个人年,阅读并系统整理了6000多篇文章,记录了2000多页的专访内容,对1435家企业进行了问卷调查,收集了28家公司过去50年甚至更早的信息,进行了大范围的定性和定量分析,得出了如何使公司和公司的管理者从优秀跨越到卓越的令人惊异而振奋的答案。

    根据吉姆·柯林斯得出的结论,优秀的公司和优秀的领导者很多,许多公司都可以在各自的行业里取得不俗的业绩。但如果以卓越的标准来衡量公司和个人的成绩,那么,能够保持持续健康增长的企业和能够不断取得事业成功的领导者都非常少。一位企业的领导者在成功的基础上,要想进一步提高自己,使自己的企业保持持续增长,使自己的个人能力从优秀向卓越迈进,就必须努力培养自己在“谦虚”、“执著”和“勇气”这三个方面的品质。

    谦虚使人进步。许多领导者在工作中唯我独尊,不能听取他人的规谏,不能容忍他人和自己意见相左,这些不懂得谦虚谨慎的领导者也许可以取得暂时的成功,但却无法在事业上不断进步,达到卓越的境界。这是因为,一个人的力量终究有限,在瞬息万变的商业环境中,领导者必须不断学习,善于综合他人的意见,否则就将陷入一意孤行的泥潭,被市场所淘汰。比尔·盖茨就是一个非常谦虚的人。例如,他在每一次演讲结束后,请撰写演讲稿的人分析一下他的演讲有哪些不足之处,以便下一次改进。

    执着是指我们坚持正确方向,矢志不移的决心和意志。无论是公司也好,还是个人也好,一旦认明了工作的方向,就必须在该方向的指引下锲而不舍地努力工作。在工作中轻言放弃或者朝三暮四的做法都不能取得真正的成功。微软公司在Windows 95操作系统取得了巨大的成功之后,比尔·盖茨仍然坚持发展企业级的Windows NT和Windows 2000操作系统。这是因为,他看到了企业级市场的广阔前景和微软在此方面的巨大潜力。经过几年的发展,微软公司的企业级操作系统终于在原本被Unix统治的市场上取得了成功,现在,包括个人操作系统在内的所有Windows产品都已经被构建在了更加安全、可靠的Windows NT架构之上。


    成功者需要有足够的勇气来面对挑战。任何事业上的成就都不是轻易就可以取得的。一个人想要在工作中出类拔萃,就必须面对各种各样的艰难险阻,必须正视事业上的挫折和失败。只有那些有勇气正视现实,有勇气迎接挑战的人才能真正实现超越自我的目标,达到卓越的境界。正如马克·吐温所说:“勇气不是缺少恐惧心理,而是对恐惧心理的抵御和控制能力。”



    结论


    很多人认为,在IT和其他高科技领域内,西方人表现得更为出色,因此中国人只有吸取西方的企业文化才能获得一席之地。的确,IT产业内的一些新观点、新理念,与中国古老的东方文化之间确实有差异(例如,西方文化直截了当的沟通和主动参与的意识)。

    不过,从本文中我们不难发现,成功所需要的一些最重要、最基本的素质大多还是中华的传统美德。在故宫里,我看到“正大光明”的匾额,其含义也就是“诚信和正直”;“学无止境”、“人贵有自知之明”、“将心比心”、“严于律己、宽以待人”都是中国历来推崇的道德观;人际关系更是在西方人公认在中国成功的秘诀;而最重要的“谦虚”、“执著”、“勇气”这三点则是中国传统文化的直接体现。因此,我认为中国人的EQ决不低于西方人,我对中国卓越的人才无比乐观。

    在今天这个充满机遇和挑战的时代里,在软件产业这个高速发展、不断创新的领域内,只有那些不懈努力、善于把握自己、勇于迎接挑战的人才能取得真正的成功。我个人衷心地希望中国高新技术产业能够在新世纪中蓬勃发展,中国的人才能够在事业上不断取得成功,实现从优秀到卓越的跨越。

    posted @ 2006-12-14 14:20 重归本垒(Bing) 阅读(225) | 评论 (0)编辑 收藏
     

    李开复2000年4月


    今年5月23日,比尔·盖茨先生在《华尔街日报》上撰文,支持和敦促美国政府给予中国永久性正常贸易国待遇。文中,他特别谈到了在清华大学与中国大学生那次对话的愉快经历以及因此而留下的深刻印象。

    这篇文章令我不禁想到,在中国的这两年来,我工作中最大的享受也是到国内各高校与学生们进行交流。这些访问和交流使得我有机会与成千上万的青年学生就他们所关心的事业、前途等问题进行面对面的沟通。中国学生的聪明、好学和上进给我留下了非常深刻的印象。

    在与这些青年学生的交流过程中,我发现有一些问题是大家都十分关心的。那些已经获得国外大学奖学金的学生,大都希望我谈一谈应该如何度过自己在美国的学习生涯;那些决定留在国内发展的学生,非常关心如何确定一个正确的方向,并以最快的速度在科研和学业方面取得成功;还有那些刚刚踏进大学校门的学生,则希望我能讲给他们一些学习、做人的经验之谈。最近,更有一些学生关心网络信息产业的发展,希望了解美国的大学生是如何创业和致富的。

    看到这么多双渴求知识、充满希望的眼睛,我突然产生了一种冲动,那就是给中国的学生们写一封信,将我与同学们在交流过程中产生的一些想法以及我要对中国学生的一些忠告写出来,帮助他们在未来的留学、工作或者创业的过程中能够人格更完美、生活更顺利,事业更成功。



    坚守诚信、正直的原则


    我在苹果公司工作时,曾有一位刚被我提拔的经理,由于受到下属的批评,非常沮丧地要我再找一个人来接替他。我问他:“你认为你的长处是什么?”他说,“我自信自己是一个非常正直的人。”我告诉他:“当初我提拔你做经理,就是因为你是一个公正无私的人。管理经验和沟通能力是可以在日后工作中学习的,但一颗正直的心是无价的。”我支持他继续干下去,并在管理和沟通技巧方面给予他很多指点和帮助。最终,他不负众望,成为一个出色的管理人才。现在,他已经是一个颇为成功的公司的首席技术官。

    与之相反,我曾面试过一位求职者。他在技术、管理方面都相当的出色。但是,在谈论之余,他表示,如果我录取他,他甚至可以把在原来公司工作时的一项发明带过来。随后他似乎觉察到这样说有些不妥,特作声明:那些工作是他在下班之后做的,他的老板并不知道。这一番谈话之后,对于我而言,不论他的能力和工作水平怎样,我都肯定不会录用他。原因是他缺乏最基本的处世准则和最起码的职业道德“诚实”和“讲信用”。如果雇用这样的人,谁能保证他不会在这里工作一段时间后,把在这里的成果也当作所谓“业余之作”而变成向其它公司讨好的“贡品”呢?这说明:一个人品不完善的人是不可能成为一个真正有所作为的人的。

    在美国,中国学生的勤奋和优秀是出了名的,曾经一度是美国各名校最欢迎的留学生群体。而最近,却有一些学校和教授声称,他们再也不想招收中国学生了。理由很简单,某些中国学生拿着读博士的奖学金到了美国,可是,一旦找到工作机会,他们就会马上申请离开学校,将自己曾经承诺要完成的学位和研究抛在一边。这种言行不一的做法已经使得美国相当一部分教授对中国学生的诚信产生了怀疑。应该指出,有这种行为的中国学生是少数,然而就是这样的“少数”,已经让中国学生的名誉受到了极大的损害。另外,目前美国有很多教授不理会大多数中国学生的推荐信,因为他们知道这些推荐信根本就出自学生自己之手,已无参考性可言。这也是诚信受到损害以后的必然结果。

    我在微软研究院也曾碰到过类似的问题。一位来这里实习的学生,有一次出乎意料地报告了一个非常好的研究结果。但是,他做的研究结果别人却无法重复。后来,他的老板才发现,这个学生对实验数据进行了挑选,只留下了那些合乎最佳结果的数据,而舍弃了那些“不太好”的数据。我认为,这个学生永远不可能实现真正意义的学术突破,也不可能成为一名真正合格的研究人员。

    最后想提的是一些喜欢贪小便宜的人。他们用学校或公司的电话打私人长途、多报销出租车票。也许有人认为,学生以成绩、事业为重,其它细节只是一些小事,随心所欲地做了,也没什么大不了的。然而,就是那些身边的所谓“小事”,往往成为一个人塑造人格和积累诚信的关键。一些贪小便宜、耍小聪明的行为只会把自己定性为一个贪图小利、没有出息的人的形象,最终因小失大。对于这些行为,一言以敝之,就是“勿以恶小而为之”。



    生活在群体之中

    与大多数美国学生比较而言,中国学生的表达能力、沟通能力和团队精神要相对欠缺一些。这也许是由于文化背景和教育体制的不同而造成的。今天,当我们面对一个正在走向高度全球化的社会时,生活在群体之中,做出更好的表现,得到更多的和收获,是尤为重要的。

    表达和沟通的能力是非常重要的。不论你做出了怎样优秀的工作,不会表达,无法让更多的人去理解和分享,那就几乎等于白做。所以,在学习阶段,你不可以只生活在一个人的世界中,而应当尽量学会与各阶层的人交往和沟通,主动表达自己对各种事物的看法和意见,甚至在公众集会时发表演讲,锻炼自己的表达能力。

    表达能力绝不只是你的“口才”。哈佛大学的Ambady教授最近做过一个非常有趣的实验,他让两组学生分别评估几位教授的授课质量。他把这几位教授的讲课录像带先无声地放两秒钟给一组学生看,得出一套评估结果。然后与那些已经听过这几位教授几个月讲课的学生的结果进行对比,两个小组的结论竟然惊人的相似。这表明,在表达自己思想的过程中,非语言表达方式和语言同样重要,有时作用甚至更加明显。这里所讲的非语言表达方式是指人的仪表、举止、语气、声调和表情等。因为从这些方面,人们可以更直观、更形象地判断你为人、做事的能力,看出你的自信和热情,从而获得十分重要的“第一印象”。

    对于一个集体、一个公司、甚至是一个国家,团队精神都是非常关键性的。微软公司在美国以特殊的团队精神著称。象Windows 2000这样产品的研发,微软公司有超过3000名开发工程师和测试人员参与,写出了5000万行代码。没有高度统一的团队精神,没有全部参与者的默契与分工合作,这项工程是根本不可能完成的。

    相对来说,以前我在别的公司时也曾见到这样的现象。一项工程布置下来,大家明明知道无法完成,但都心照不宣,不告诉老板。因为反正也做不完,大家索性也不努力去做事,却花更多的时间去算计怎么把这项工程的失败怪罪到别人身上去。就是这些人和这样的工作作风几乎把这家公司拖垮。

    为了培养团队精神,我建议同学们在读书之余积极参加各种社会团体的工作。在与他人分工合作、分享成果、互助互惠的过程中,你们可以体会团队精神的重要性。

    在学习过程中,你千万不要不愿意把好的思路、想法和结果与别人分享,担心别人走到你前面的想法是不健康的,也无助于你的成功。有一句谚语说,“你付出的越多,你得到的越多”。试想,如果你的行为让人觉得“你的是我的,我的还是我的”,当你需要帮忙时,你认为别人会来帮助你吗?反之,如果你时常慷慨地帮助别人,那你是不是会得到更多人的回报?

    在团队之中,要勇于承认他人的贡献。如果借助了别人的智慧和成果,就应该声明。如果得到了他人的帮助,就应该表示感谢。这也是团队精神的基本体现。


    做一个主动的人

    三十年前,一个工程师梦寐以求的目标就是进入科技最领先的IBM。那时IBM对人才的定义是一个有专业知识的、埋头苦干的人。斗转星移,事物发展到今天,人们对人才的看法已逐步发生了变化。现在,很多公司所渴求的人才是积极主动、充满热情、灵活自信的人。

    作为当代中国的大学生,你应该不再只是被动地等待别人告诉你应该做什么,而是应该主动去了解自己要做什么,并且规划它们,然后全力以赴地去完成。想想今天世界上最成功的那些人,有几个是唯唯诺诺、等人吩咐的人?对待自己的学业和研究项目,你需要以一个母亲对孩子那样的责任心和爱心全力投入不断努力。果真如此,便没有什么目标是不能达到的。

    一个积极主动的人还应该虚心听取他人的批评和意见。其实,这也是一种进取心的体现。不能虚心接受别人的批评,并从中汲取教训,就不可能有更大的进步。比尔·盖茨曾经对公司所有员工说过:“客户的批评比赚钱更重要。从客户的批评中,我们可以更好地汲取失败的教训,将它转化为成功的动力。”

    除了虚心接受别人的批评,你还应该努力寻找一位你特别尊敬的良师。这位良师应该是直接教导你的老师以外的人,这样的人更能客观地给你一些忠告。这位良师除了可以在学识上教导你之外,还可以在其它一些方面对你有所指点,包括为人处世,看问题的眼光,应对突发事件的技能等等。我以前在苹果公司负责一个研究部门时,就曾有幸找到这样一位良师。当时,他是负责苹果公司全球运作和生产业务的高级副总裁,他在事业发展方面给我的许多教诲令我终身受益。如果有这样的人给你帮助,那你成长的速度一定会比别人更快一些。

    中国学生大多比较含蓄、害羞,不太习惯做自我推销。但是,要想把握住转瞬即逝的机会,就必须学会说服他人、向别人推销自己或自己的观点。在说服他人之前,要先说服自己。你的激情加上才智往往折射出你的潜力,这就是人们常说的化学反应。一般来说,一个好的自我推销策略可以令事情的发展锦上添花。

    例如,有一次我收到了一份很特殊的求职申请书。不同于已往大多数求职者,这位申请人的求职资料中包括了他的自我介绍、他对微软研究院的向往、以及他为什么认为自己是合适的人选,此外还有他已经发表的论文、老师的推荐信和他希望来微软作的课题等。尽管他毕业的学校不是中国最有名的学校,但他的自我推销奏效了。我从这些文件中看到了他的热情和认真。在我面试他时,他又递交了一份更充分的个人资料。最后,当我问他有没有问题要问我时,他反问我,:“你对我还有没有任何的保留?”当时,我的确对他能否进入新的研究领域有疑虑,于是就进一步问了他一些这方面的问题。他举出了两个很有说服力的例子。最后,我们雇用了这名应聘者。他现在做得非常出色。



    挑战自我、开发自身潜力


    我在苹果公司工作的时候,有一天,老板突然问我什么时候可以接替他的工作?我非常吃惊,表示自己缺乏象他那样的管理经验和能力。但是他却说,这些经验是可以培养和积累的,而且他希望我在两年之后就可以做到。有了这样的提示和鼓励,我开始有意识地加强自己在这方面的学习和实践。果然,我真的在两年之后接替了他的工作。我个人认为:一个人的领导素质对于他将来的治学、经商或从政都是十分重要的。在任何时候、任何环境里,我们都应该有意识地培养自己的领导才能。同时, 我建议你给自己一些机会展示这方面的能力,或许象我一样,你会惊讶自己在这一方面的潜力远远超过了想象中那样。

    给自己设定目标是一件十分重要的事情。目标设定过高固然不切实际,但是目标千万不可定得太低。在二十一世纪,竞争已经没有疆界,你应该放开思维,站在一个更高的起点,给自己设定一个更具挑战性的标准,才会有准确的努力方向和广阔的前景,切不可做“井底之蛙”。另外,只在一所学校取得好成绩、好名次就认为自己已经功成名就是可笑的,要知道,山外有山,人上有人,而且,不同地方的衡量标准又不一样。所以,在订立目标方面,千万不要有“宁为鸡首,不为牛后”的思想。

    一个一流的人与一个一般的人在一般问题上的表现可能一样,但是在一流问题上的表现则会有天壤之别。美国著名作家威廉·福克纳说过:“不要竭尽全力去和你的同僚竞争。你更应该在乎的是:你要比现在的你更强。”你应该永远给自己设立一些很具挑战性、但并非不可及的目标。

    在确立将来事业的目标时,不要忘了扪心自问:“这是不是我最热爱的专业?我是否愿意全力投入?”我希望你们能够对自己选择所从事的工作充满激情和想象力,对前进途中可能出现的各种艰难险阻无所畏惧。谈到对工作的热爱,我认识的一位微软的研究员曾经让我深有感触。他经常周末开车出门说去见“女朋友”,后来,一次偶然机会我在办公室里看见他,问他“女朋友在哪里?”他笑着指着电脑说:“就是她呀。”对于工作的热爱,比尔·盖茨也曾有过非常精彩的阐述,他说:“每天早晨醒来,一想到所从事的工作和所开发的技术将会给人类生活带来的巨大影响和变化,我就会无比兴奋和激动。”

    几个月前,《北京青年报》上曾有一场探讨比尔·盖茨和保尔·柯察金谁更伟大的讨论。由于从小在美国长大,我并不知道保尔和他的那些事迹。但是,我非常赞同保尔的这段名言:“人最宝贵的东西是生命,生命属于我们只有一次。人的一生应当这样度过,当他回首往事的时候,不因虚度年华而悔恨,也不因碌碌无为而羞耻……”所以,选择一个你真心热爱的事业,不断地挑战自我、完善自我,让自己的一生过得精彩和充实。


    客观、直接了当的沟通


    有一次,一位中国的大学教授找到我,希望我帮他找一位国外的专家在他组织的会议上去作主题演讲,末了还特意加了一句,最好是一个洋人。我很不以为然地对他说:“这个领域最具权威的人士就是在北京的一个中国人,为什么你一定要找一位洋人呢?”他表面上同意我的说法,但是他仍然请了一个美国人来作这个演讲,结果效果很差。所以,我们不应该陷入盲目的崇洋情结。我们应该用客观的眼光来判断事物,而不是以他的肤色或他的居住地来决定。

    有一句话说,“真理总是掌握在少数人手中”。我们理解这句话的意思,应该有自己的眼光,有独立思考的能力,不一定大多数人认可的,或某个权威说的,就是对的。不论是作学问、搞研究还是经商,我们都不能盲从,要多想几个为什么。

    有了客观的意见,你就应该直接了当地表达。如果做任何事情都象“打太极拳”,会让人不知所云,也会造成很多误会。有一次,在微软研究院工作的一位研究人员就自己所选择的研究方向来征求我的意见,我作了一番分析,认为这个方向有不少问题,我个人认为对学术界的贡献不大,但如果他坚持,我愿意支持他试着去做。结果他认为我这句话的意思实际上就是不允许他去做,所以他就选择了其它的方向。后来他要出差时,负责行政事务的人告诉他,你可以选择坐火车或者坐飞机。他认为行政人员实际上是在暗示他坐火车,因为坐飞机太贵。其实,他的猜测都是错误的。因为我们的沟通方式是直接了当,而他却在“打太极拳”。这之后,我们通过一系列的公司文化讲座,让员工们了解到:心里想什么就讲什么,不要把简单的问题复杂化。现在,研究院里这类的误会少了很多。

    拐弯抹角,言不由衷,结果浪费了大家的宝贵时间。瞻前顾后,生怕说错话,结果是变成谨小慎微的懦夫。更糟糕的是还有些人,当面不说,背后乱讲,这样对他人和自己都毫无益处,最后只能是破坏了集体的团结。这样的人和作风既不能面对社会,也不可能在科学研究中走出新路,更不可能在激烈的商战中脱颖而出。

    希望同学们能够做到开诚布公,敢于说“不”,这才是尊重自己思想意愿的表现。当然,在表达你的意见时,无论反对和批评都应是建设性的,有高度诚意的,而不是为批评而批评,为辩论而批评。我赞成的方式是提供建设性的正面的意见。在开始讨论问题时,任何人先不要拒人千里之外,大家把想法都摆在桌面上,充分体现个人的观点,这样才会有一个容纳大部分人意见的结论。当然,你也要学习用适当的方法和口气表达你的意见,比如说不要在很多人面前让别人难堪。这样,你的批评才会奏效。


    珍惜校园学习生活


    几天前,报纸上登出一条消息,说有中学生辍学去开网络公司。我认为这并不值得提倡。对绝大多数学生来讲,在校生活是系统地学习基础理论知识,学习思考和解决问题方式的好机会。这些知识将成为你未来发展过程中所需要的最基本的知识和技能。就象建一栋高楼,如果不打好基础是经不起风吹雨打的。

    在全球范围内,美国的研究水平无疑是世界一流的。而除了美国之外,你会发现英国的研究水平也是相当突出的。究其原因,其实就是语言问题。英国人可以毫无阻碍地阅读美国乃至全球各种最新的英文研究报告和资料。这对于他们把握研究方向,跟踪最新进展,发表研究成果都有很大的帮助。因此,英语学习对于我们作研究的人来说,也是相当重要的。只有加强这方面素质的培养,才能适应将来的发展。我建议:学英语先学听说,再学读写,而且务必在大学阶段完全解决英语学习的问题。等到年龄大了,要付出的代价相比就会大得多。

    除了英语之外,数学、统计学对理工科学生也是很重要的基础课程,是不可忽视的。数学是人类几千年的智慧结晶,你们一定要用心把它学好,不能敷衍了事。我今天就很后悔自己当初没有花更多功夫把数学学得更好些。另外,计算机应用、算法和编程也都是每一个工科学生应该熟悉和掌握的,它们是将来人人必须会用的工具。

    科技的发展可谓日新月异。在校学习的目的,其实就是掌握最基本的学习工具和方法。将来利用这些工具和方法,再去学习新的东西。比如:上课学会了C++, 能否自己学会Java? 上课学会了HTML, 能否自己学会XML? 与其说上大学是为了学一门专业,不如说是为了学会如何学习,让自己能够“无师自通”。

    大学毕业后的前两年,同学们聚到一起,发现变化都还不算大。五年后再聚到一起,变化就大多了。一些人落伍了,因为他们不再学习,不再能够掌握新的东西,自然而然地落在了社会发展的后面。如果我们要在这个竞争激烈的社会中永不落伍,那就得永远学习。

    我的老板 - Rick Rashid博士是目前微软公司主管研究的高级副总裁,他已经功成名就,却始终保持着一颗学习和进取的心。现在,他每年仍然编写大约50,000行程序。他认为:用最新的技术编程可以使他保持对计算机最前沿技术的敏感,使自己能够不断进步。今天,有些博士生带着低年级的本科生和硕士生做项目,就自满地认为自己已经没有必要再编程了。其实,这样的做法是很不明智的。

    每次到清华和其它学校访问,被问到最多的就是学生打工的问题。我认为,打工从总体来说对学生是一件好事,是拓宽视野的一种方式。例如:在研究机构打工,可以学到最新的科技;在产品部门打工,可以学到开发的技术和技能;在市场部门打工,可以理解商业的运作。我认为每一个学生都应该有打工的经验,但不要打一些“没用的工”。首先要明白打工只是学生生活中的一种补充,学习才是最重要的。打工的目的是开阔眼界,不是提前上班。如果你把翻译书本、录入数据库所花的时间投入学习,将来可以赚更多的钱。那些钱将远远超出目前打工的收入。


    此外,还有一些学生受到目前退学创业的鼓励,为成为中国的比尔·盖茨和迈克尔·戴尔而中途辍学。以我的观点,除了十分特殊的情况,我不建议在校学生退学创业。你所看到的那些退学创业的成功者实际上少之又少。目前,大部分学生虽有创业的想法,但缺少创业的经验,所以失败的可能性非常大。如果要成功,我建议你们先把书读好。如果是要学习创业的经验,你完全可以利用假期的时间先去一间公司边打工边学。比尔·盖茨也曾说过,“如果你正在考虑自己成立一家新公司,你应该首先明确地知道:创办公司需要巨大的精力投入,要冒巨大的风险。我觉得你们不必象我,一开始就创办一家公司。你应该考虑加盟其他公司并在这家公司中学习他们的工作、创业方法。”


    你想戴一顶什么样的博士帽

    在我进入卡内基梅隆大学攻读计算机博士学位时,系主任曾对我讲,当你拿到你的博士学位时,你应该成为你所从事的研究领域里世界第一的专家。这句话对于初出茅庐的我来说简直高不可攀,但也让我踌躇满志、跃跃欲试。就这样,在经过五年寒窗、夜以继日的努力工作后,他所期待的结果就那么自然而然地出现了。一个打算攻读博士学位的人,就应该给自己树立一个很高的目标。如果没有雄心壮志,就千万不要自欺欺人,也许经商或从事其它工作,会有更大的成绩。

    在目标确立之后,我建议你为自己设计一个三年的学习和科研计划。首先,你需要彻底地了解在相关领域他人已有的工作和成绩。然后再提出自己的想法和见解,做脚踏实地的工作。另外,还要不断跟踪这个领域的最新研究进展。只有这样,才可以把握好方向,避免重复性工作,把精力集中在最有价值的研究方向上。

    在学术界,人们普遍认为“名师出高徒”。可见导师在你的成长道路中作用是多么的大。所以,你应该主动去寻找自己所研究的领域里最好的老师。除了你的老师之外,你还应该去求教于周围所有的专家。更不要忘了常去求教“最博学的老师”- Internet!现在,几乎所有的论文、研究结果、先进想法都可以在网上找到。我还鼓励你直接发电子邮件去咨询一些世界公认的专家和教授。以我的经验,对于这样的邮件,他们中的大部分都会很快给你回复。

    我在攻读博士学位时,每周工作七天,每天工作16个小时,大量的统计结果和分析报告几乎让我崩溃。那时,同领域其他研究人员采用的是与我不同的传统方法。我的老师虽然支持我,但并不认可我的研究方向。我也曾不止一次地怀疑自己的所作所为是否真的能够成功。但终于有一天,在半夜三点时做出的一个结果让我感受到了成功的滋味。后来,研究有了突飞猛进的进展,导师也开始采用我的研究方法。我的博士论文使我的研究成为自然语言研究方面当时最有影响力的工作之一。读博士不是一件轻松的事,切忌浮躁的情绪,而要一步一个脚印,扎扎实实地工作。也不可受一些稍纵即逝的名利的诱惑,而要200%的投入。也许你会疲劳,会懊悔,会迷失方向,但是要记住,你所期待的成功和突破也正孕育其中。那种一切都很顺利,谁都可以得到的工作和结果,我相信研究价值一定不高。

    从一定意义上讲,一个人如果打算一辈子从事研究工作,那么从他在读博士学位期间所形成的做事习惯、研究方法和思维方式基本上就可以判断出他未来工作的轮廓。所以,你一定要做一个“有心人”,充分利用在校的时间,为自己的将来打好基础。

    上述一些观点,是我在与同学们交往过程中的一些感受。我希望这些建议和想法能对正在未来之路上跋涉的你们有所启发,能对你们目前的学习有所帮助。或许因为观点不同、人各有志,或许因为忠言逆耳,这封信可能无法为每一位同学所接受。但是只要一百位阅读这封信的同学中有一位从中受益,这封信就已经比我所作的任何研究都更有价值。我真诚地希望,在新的世纪,中国学生无论是在国内,还是国外;无论是做研究,还是经商,都显得更成熟一些,成功的机率更大一些。

    posted @ 2006-12-14 14:14 重归本垒(Bing) 阅读(206) | 评论 (0)编辑 收藏
     
    1.RequestDispatcher.forward()
    是在服务器端起作用,当使用forward()时,Servlet engine传递HTTP请求从当前的Servlet or JSP到另外一个Servlet,JSP 或普通HTML文件,也即你的form提交至a.jsp,在a.jsp用到了forward()重定向至b.jsp,此时form提交的所有信息在b.jsp都可以获得,参数自动传递.
    但forward()无法重定向至有frame的jsp文件,可以重定向至有frame的html文件,同时forward()无法在后面带参数传递,比如servlet?name=frank,这样不行,可以程序内通过response.setAttribute("name",name)来传至下一个页面.

      重定向后浏览器地址栏URL不变.

    例:在servlet中进行重定向
    public void doPost(HttpServletRequest request,HttpServletResponse response)
    throws ServletException,IOException
    {

        response.setContentType("text/html; charset=gb2312");

        ServletContext sc = getServletContext();

        RequestDispatcher rd = null;

        rd = sc.getRequestDispatcher("/index.jsp");   //定向的页面

        rd.forward(request, response);

    }
    通常在servlet中使用,不在jsp中使用。

    2.response.sendRedirect()
      是在用户的浏览器端工作,sendRedirect()可以带参数传递,比如servlet?name=frank传至下个页面,同时它可以重定向至不同的主机上,sendRedirect()可以重定向有frame.的jsp文件.
      重定向后在浏览器地址栏上会出现重定向页面的URL。

    sendRedirect()实际上是reponse.setStatus(302)的快捷方式,后者用于设置Http响应的状态代码。


    例:在servlet中重定向
    public void doPost(HttpServletRequest request,HttpServletResponse response)

        throws ServletException,IOException

    {

        response.setContentType("text/html; charset=gb2312");

        response.sendRedirect("/index.jsp");

    }
    由于response是jsp页面中的隐含对象,故在jsp页面中可以用response.sendRedirect()直接实现重定位。
    注意:
    (1).使用response.sendRedirect时,前面不能有HTML输出。
    这并不是绝对的,不能有HTML输出其实是指不能有HTML被送到了浏览器。事实上现在的server都有cache机制,一般在8K(我是说JSP SERVER),这就意味着,除非你关闭了cache,或者你使用了out.flush()强制刷新,那么在使用sendRedirect之前,有少量的HTML输出也是允许的。
    (2).response.sendRedirect之后,应该紧跟一句return;
    我们已经知道response.sendRedirect是通过浏览器来做转向的,所以只有在页面处理完成后,才会有实际的动作。既然你已经要做转向了,那么后的输出还有什么意义呢?而且有可能会因为后面的输出导致转向失败。
    比较:
    (1).Request Dispatcher.forward()是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;
    (2).response.sendRedirect()则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。
    前者更加高效,在前者可以满足需要时,尽量使用RequestDispatcher.forward()方法.

    注:在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用HttpServletResponse.sendRequest()方法。

    3.<jsp:forward page="" />

    它的底层部分是由RequestDispatcher来实现的,因此它带有RequestDispatcher.forward()方法的印记。


    如果在<jsp:forward>之前有很多输出,前面的输出已使缓冲区满,将自动输出到客户端,那么该语句将不起作用,这一点应该特别注意。
    另外要注意:它不能改变浏览器地址,刷新的话会导致重复提交

    4.JSP中实现在某页面停留若干秒后,自动重定向到另一页面
    在html文件中,下面的代码:
      <meta http-equiv="refresh" content="300; url=target.jsp">
      它的含义:在5分钟之后正在浏览的页面将会自动变为target.html这一页。代码中300为刷新的延迟时间,以秒为单位。targer.html为你想转向的目标页,若为本页则为自动刷新本页。
      由上可知,可以通过setHeader来实现某页面停留若干秒后,自动重定向到另一页面。
      关键代码:
          String content=stayTime+";URL="+URL;
          response.setHeader("REFRESH",content);
     

    posted @ 2006-12-14 09:44 重归本垒(Bing) 阅读(289) | 评论 (0)编辑 收藏
     
    一 热诚的态度 我们的态度决定了我们的未来一个人能否成功,取决了他的态度!
      成功人士与失败之间的判别是:
      成功人士始终有最热诚的态度最积极的思考,最乐观的精神和最辉煌的以经验支配和控制自己的人生,失败者则相反,他们的人生是受过人生的种种失败怀疑虑所引导和支配。 我们的态度决定了我们人生的成功

      1,我们怎样对待生活,生活就怎样对待我们。
      2,我们怎样对待别人,别人怎样对待我们。
      3,我们在一项任务刚开始时的态度就决定了最后的多大成功。

      我们的环境---心里的\感情的\精神的\----完全由我们自己的态度来创造。

    二 目标明确\目标管理

      1目标明确

      没有线路图什么地方也去不了。
      目标就是构筑成功的砖石。
      目标使我们产生积极性,你给自己定了目标,有两个方面的作用:一是你努力的依据二是你的鞭策。目标给你一个看得着的射击靶,随着你努力去实现这些目标,你就会有成就感。有9 8%的人对心目中的世界没有一幅清晰的图画。如果计划不具体,无法衡量是否实现了----那会降低了你的积极性。

      2目标管理

      把整体目标分解成一个个易记的目标把你的目标象成一金字塔,塔顶就是你的人生目标,你定的目标和为达目标而做的每一件事都必须指向你的人生目标。
      金字塔由五层组成,最上的一层最小,最核心的。这一层包含着你的人生总目标。
      下面每层是为实现上一层较大目标而要达到的较小目标。

    三 一勤天下无难事

      一心向着自己目标前进的人,整个世界都给他让路。

    四 擅于理财、预算时间和金钱

    五 喜欢运动

      健康的体魄是成就事业的资本。成功人士几乎都有自己喜欢的体育项目。

    六 自律

      自控能力的强弱对人生的成功也有很大的影响。

      1 当你生气时,你能沉默不语吗?
      2 你习惯于三思而行吗?
      3 你的性情一般是平和的吗?
      4 你习惯让你的情绪控制你的理智。

    七 谦虚好学

      1 你是否把不断的学习更多的知识作为你的职责?
      2 你是否有一种习惯:对你所不熟悉的问题发表"意见"?
      3 当你需要知识时,你知道如何寻找吗?

      越是成功的人,他们越会抓住一切可以学习的机会。

    八 良好的人际关系

      成功意味着别人的参与

    九 信念

    十 立即行动
      有了价值连城的目标计划,成功已向你展示。有位先生几年以来一直暗恋着某位小姐,可是,连续几年过去了,他一直没有采取任何行动,他一直在等待,直到那位小姐成为他人之妻,他紧张起来,但是为时已晚! 别再犹豫,请立即行动吧!

    posted @ 2006-12-14 09:26 重归本垒(Bing) 阅读(238) | 评论 (0)编辑 收藏
     
    李开复
    2004年5月
    此前,我和中国学生的多次交流都是围绕如何达到优秀和卓越、如何成为领导人才而展开的。最近,在新浪网的聊天室和我收到的许多电子邮件中,我发现更多的中国学生需要知道的不是如何从优秀到卓越,而是如何从迷茫到积极、从失败到成功、从自卑到自信、从惆怅到快乐、从恐惧到乐观。

    一个极端的例子是2004年2月发生在云南大学的马加爵事件。马加爵残忍地杀害了自己的4名同学。但从马家爵被捕后与心理学家的对话内容看来,他应该不是一个邪恶的人,而是一个迷失方向、缺乏自信、性格封闭的孩子。他和很多大学生一样,迫切希望知道如何才能获得成功、自信和快乐。

    我这一封信是写给那些渴望成功但又觉得成功遥不可及,渴望自信却又总是自怨自艾,渴望快乐但又不知快乐为何物的学生看的。希望这封信能够带给读者一个关于成功的崭新定义,鼓励读者认识和肯定自己,做一个快乐的人。也希望这封信能够帮助读者理解成功、自信、快乐是一个良性循环:从成功里可以得到自信和快乐,从自信里可以得到快乐和成功,从快乐里可以得到成功和自信。

    成功就是成为最好的你自己
    美国作家威廉·福克纳说过:“不要竭尽全力去和你的同僚竞争。你应该在乎的是,你要比现在的你强。”

    中国社会有个通病,就是希望每个人都照一个模式发展,衡量每个人是否“成功”采用的也是一元化的标准:在学校看成绩,进入社会看名利。尤其是在今天的中国,人们对财富的追求首当其冲,各行各业,对一个人的成功的评价,更多地以个人财富为指标。但是,有了最好的成绩就能对社会有所贡献吗?有名利就一定能快乐吗?

    真正的成功应是多元化的。成功可能是你创造了新的财富或技术,可能是你为他人带来了快乐,可能是你在工作岗位上得到了别人的信任,也可能是你找到了回归自我、与世无争的生活方式。每个人的成功都是独一无二的。所以,凌志军在其《成长》一书中得出的重要结论是“成为最好的你自己”。也就是说,成功不是要和别人相比,而是要了解自己,发掘自己的目标和兴趣,努力不懈地追求进步,让自己的每一天都比昨天更好。

    成功的第一步:把握人生目标,做一个主动的人
    在新浪聊天室里,当网友问我的人生目标是什么时,我是这么回答的:“人生只有一次,我认为最重要的就是要有最大的影响力(impact),能够帮助自己、帮助家庭、帮助国家、帮助世界、帮助后人,能够让他们的日子过得更好、更有效率,能够为他们带来幸福和快乐。”我回答这个问题时丝毫不需要思考,因为我从大学二年级起就把“影响力”当作自己的人生目标。

    对我来说,人生目标不是一个口号,而是我最好的智囊,它曾多次帮我解决工作和生活中的难题。我当初放弃在美国的工作,只身来到中国创立微软中国研究院,就是因为我觉得后一项工作有更大的影响力,和我的人生目标更加吻合。此外,当我收到一封封迷茫学生的来信,给他们写回信时,我也会想:“如何让回信有更大的影响力?”我先后公开的三封“给中国学生的信”都是如此诞生的。

    马加爵也悟出了他的人生目标,只可惜他是在案发被捕后才悟出的。他说:“姐,现在我对你讲一次真心话,我这个人最大的问题就是出在我觉得人生的意义到底是为了什么?……在这次事情以后,此时此刻我明白了,我错了。其实人生的意义在于人间有真情。”如果马加爵能早几个月悟出人生目标,他在做傻事前就会问问自己,充满真情的父母、姐姐会怎么看待这件事?这样,他可能就不会走上歧途了。

    所以,无论是为了真情,为了影响力,还是为了快乐、家人、道德、宁静、求知、创新……一旦确定了人生目标,你就可以像我一样在人生目标的指引下,果断地做出人生中的重大决定。每个人的人生目标都是独特的。最重要的是,你要主动把握自己的人生目标。但你千万不能操之过急,更不要为了追求所谓的“崇高”,或为了模仿他人而随便确定自己的目标。

    那么,该怎么去发现自己的目标呢?许多同学问我他们的目标该是什么?我无法回答,因为只有一个人能告诉你人生的目标是什么,那个人就是你自己。只有一个地方你能找到你的目标,那就是你心里。

    我建议你闭上眼睛,把第一个浮现在你脑海里的理想记录下来,因为不经过思考的答案是最真诚的。或者,你也可以回顾过去,在你最快乐、最有成就感的时光里,是否存在某些共同点?它们很可能就是最能激励你的人生目标了。再者,你也可以想象一下,十五年后,当你达到完美的人生状态时,你将会处在何种环境下?从事什么工作?其中最快乐的事情是什么?当然,你也不妨多和亲友谈谈,听听他们的意见。

    成功的第二步:尝试新的领域、发掘你的兴趣
    为了成为最好的你自己,最重要的是要发挥自己所有的潜力,追逐最感兴趣和最有激情的事情。当你对某个领域感兴趣时,你会在走路、上课或洗澡时都对它念念不忘,你在该领域内就更容易取得成功。更进一步,如果你对该领域有激情,你就可能为它废寝忘食,连睡觉时想起一个主意,都会跳起来。这时候,你已经不是为了成功而工作,而是为了“享受”而工作了。毫无疑问的,你将会从此得到成功。

    相对来说,做自己没有兴趣的事情只会事倍功半,有可能一事无成。即便你靠着资质或才华可以把它做好,你也绝对没有释放出所有的潜力。因此,我不赞同每个学生都追逐最热门的专业,我认为,每个人都应了解自己的兴趣、激情和能力(也就是情商中所说的“自觉”),并在自己热爱的领域里充分发挥自己的潜力。

    比尔·盖茨曾说:“每天清晨当你醒来的时候,都会为技术进步给人类生活带来的发展和改进而激动不已。”从这句话中,我们可看出他对软件技术的兴趣和激情。1977年,因为对软件的热爱,比尔·盖茨放弃了数学专业。如果他留在哈佛继续读数学,并成为数学教授,你能想象他的潜力将被压抑到什么程度吗?2002年,比尔·盖茨在领导微软25年后,却又毅然把首席执行官的工作交给了鲍尔默,因为只有这样他才能投身于他最喜爱的工作——担任首席软件架构师,专注于软件技术的创新。虽然比尔·盖茨曾是一个出色的首席执行官,但当他改任首席软件架构师后,他对公司的技术方向做出了重大贡献,更重要的是,他更有激情、更快乐了,这也鼓舞了所有员工的士气。

    比尔·盖茨的好朋友,世界第二富人华伦·巴菲特也同样认可激情的重要性。当学生请他指示方向时,他总这么回答:“我和你没有什么差别。如果你一定要找一个差别,那可能就是我每天有机会做我最爱的工作。如果你要我给你忠告,这这是我能给你的最好忠告了。”

    比尔·盖茨和华伦·巴菲特给我们的另一个启示是,他们热爱的并不是庸俗的、一元化的名利,他们的名利是他们的理想和激情带来的。美国一所著名的经管学院曾做过一个调查,结果发现,虽然大多数学生在入学时都想追逐名利,但在拥有最多名利的校友中,有90%是入学时追逐理想、而非追逐名利的人。

    我刚进入大学时,想从事法律或政治工作。一年多后我才发现自己对它没有兴趣,学习成绩也只在中游。但我爱上了计算机,每天疯狂地编程,很快就引起了老师、同学的重视。终于,大二的一天,我做了一个重大的决定:放弃此前一年多在全美前三名的哥伦比亚大学法律系已经修成的学分,转入哥伦比亚大学默默无名的计算机系。我告诉自己,人生只有一次,不应浪费在没有快乐、没有成就感的领域。当时也有朋友对我说,改变专业会付出很多代价,但我对他们说,做一个没有激情的工作将付出更大的代价。那一天,我心花怒放、精神振奋,我对自己承诺,大学后三年每一门功课都要拿A。若不是那天的决定,今天我就不会拥有在计算机领域所取得的成就,而我很可能只是在美国某个小镇上做一个既不成功又不快乐的律师。

    即便如此,我对职业的激情还远不能和我父亲相比。我从小一直以为父亲是个不苟言笑的人,直到去年见到父亲最喜爱的两个学生(他们现在都是教授),我才知道父亲是多么热爱他的工作。他的学生告诉我:“李老师见到我们总是眉开眼笑,他为了让我们更喜欢我们的学科,常在我们最喜欢的餐馆讨论。他在我们身上花的时间和金钱,远远超过了他微薄的收入。”我父亲是在70岁高龄,经过从军、从政、写作等职业后才找到了他的最爱——教学。他过世后,学生在他抽屉里找到他勉励自己的两句话:“老牛明知夕阳短,不用扬鞭自奋蹄。”最令人欣慰的是,他在人生的最后一段路上,找到了自己的最爱。

    那么,如何寻找兴趣和激情呢?首先,你要把兴趣和才华分开。做自己有才华的事容易出成果,但不要因为自己做得好就认为那是你的兴趣所在。为了找到真正的兴趣和激情,你可以问自己:对于某件事,你是否十分渴望重复它,是否能愉快地、成功地完成它?你过去是不是一直向往它?是否总能很快地学习它?它是否总能让你满足?你是否由衷地从心里(而不只是从脑海里)喜爱它?你的人生中最快乐的事情是不是和它有关?当你这样问自己时,注意不要把你父母的期望、社会的价值观和朋友的影响融入你的答案。

    如果你能明确回答上述问题,那你就是幸运的,因为大多数学生在大学四年里都在摸索或悔恨。如果你仍未找到这些问题的答案,那我只有一个建议:给自己最多的机会去接触最多的选择。记得我刚进卡内基·梅隆的博士班时,学校有一个机制,允许学生挑老师。在第一个月里,每个老师都使尽全身解数吸引学生。正因为有了这个机制,我才幸运地碰到了我的恩师瑞迪教授,选择了我的博士题目“语音识别”。虽然并不是所有学校都有这样的机制,但你完全可以自己去了解不同的学校、专业、课题和老师,然后从中挑选你的兴趣。你也可以通过图书馆、网络、讲座、社团活动、朋友交流、电子邮件等方式寻找兴趣爱好。唯有接触你才能尝试,唯有尝试你才能找到你的最爱。

    我的同事张亚勤曾经说:“那些敢于去尝试的人一定是聪明人。他们不会输,因为他们即使不成功,也能从中学到教训。所以,只有那些不敢尝试的人,才是绝对的失败者。”希望各位同学尽力开拓自己的视野,不但能从中得到教益,而且也能找到自己的兴趣所在。

    成功的第三步:针对兴趣,定阶段性目标,一步步迈进
    找到了你的兴趣,下一步该做的就是制定具体的阶段性目标,一步步向自己的理想迈进。

    首先,你应客观地评估距离自己的兴趣和理想还差些什么?是需要学习一门课、读一本书、做一个更合群的人、控制自己的脾气还是成为更好的演讲者?十五年后达到的完美的自己和今天的自己会有什么差别?。。。你应尽力弥补这些差距。例如,当我决定我一生的目的是要让我的影响力最大化时,我发现我最欠缺的是演讲和沟通能力。我以前是一个和人交谈都会脸红,上台演讲就会恐惧的学生。我做助教时表现特别差,学生甚至给我取了个“开复剧场”的绰号。因此,为了实现我的理想,我给自己设定了多个提高演讲和沟通技巧的具体目标。

    其次,你应定阶段性的、具体的目标,再充分发挥中国人的传统美德——勤奋、向上和毅力,努力完成目标。比如,我要求自己每个月做两次演讲,而且每次都要我的同学或朋友去旁听,给我反馈意见。我对自己承诺,不排练三次,决不上台演讲。我要求自己每个月去听演讲,并向优秀的演讲者求教。有一个演讲者教了我克服恐惧的几种方法,他说,如果你看着观众的眼睛会紧张,那你可以看观众的头顶,而观众会依然认为你在看他们的脸,此外,手中最好不要拿纸而要握起拳来,那样,颤抖的手就不会引起观众的注意。当我反复练习演讲技巧后,我自己又发现了许多秘诀,比如:不用讲稿,通过讲故事的方式来表达时,我会表现得更好,于是,我仍准备讲稿但只在排练时使用;我发现我回答问题的能力超过了我演讲的能力,于是,我一般要求多留时间回答问题;我发现自己不感兴趣的东西就无法讲好,于是,我就不再答应讲那些我没有兴趣的题目。几年后,我周围的人都夸我演讲得好,甚至有人认为我是个天生的好演说家,其实,我只是实践了中国人勤奋、向上和毅力等传统美德而已。

    任何目标都必须是实际的、可衡量的目标,不能只是停留在思想上的口号或空话。制定目标的目的是为了进步,不去衡量你就无法知道自己是否取得了进步。所以,你必须把抽象的、无法实施的、不可衡量的大目标简化成为实际的、可衡量的小目标。举例来说,几年前,我有一个目标是扩大我在公司里的人际关系网,但“多认识人”或“增加影响力”的目标是无法衡量和实施的,我需要找一个实际的、可衡量的目标。于是,我要求自己“每周和一位有影响力的人吃饭,在吃饭的过程,要这个人再介绍一个有影响的人给我”。衡量这个目标的标准是“每周与一人一餐、餐后再认识一人”。当然,我不会满足于这些基本的“指标”。扩大人际关系网的目的是使工作更成功,所以,我还会衡量“每周一餐”中得到了多少信息,有多少我的部门雇用的人是在这样的人际网中认识的。一年后,我的确从这些衡量标准中,看到了自己的关系网有了显著的扩大。

    制定具体目标时必须了解自己的能力。目标设定过高固然不切实际,但目标也不可定得太低。对目标还要做及时的调整:如果超出自己的期望,可以把期望提高;如果未达到自己的期望,可以把期望调低。达成了一个目标后,可以再制定更有挑战性的目标;失败时要坦然接受,认真总结教训。

    最后,再一次提醒同学们,目标都是属于你的,只有你知道自己需要什么。制定最合适的目标,主动提升自己,并在提升过程中客观地衡量进度,这样才能获得成功,才能成为更好的你自己。

    自信是自觉而非自傲
    自信的人敢于尝试新的领域,能更快地发展自己的兴趣和才华,更容易获得成功。自信的人也更快乐,因为他不会时刻担心和提防失败。

    很多人认为自信就是成功。一个学生老得第一名,他有了自信。一个员工总是被提升,他也有了自信。但这只是一元化的成功和一元化的自信。

    其实,自信不一定都是好事。没有自觉的自信会成为自傲,反而会失去了别人的尊重和信赖。好的自信是自觉的,即很清楚自己能做什么,不能做什么。自觉的人自信时,他成功的概率非常大;自觉的人不自信时,他仍可努力尝试,但会将风险坦诚地告诉别人。自觉的人不需要靠成功来增强自信,也不会因失败而丧失自信。

    自信的第一步:不要小看自己,多给自己打气
    “自”信的关键在于自己。如果你自己总认为自己不行,你是无法得到自信的。例如,马加爵曾说:“我觉得我太失败的,同学都看不起我……很多人比我老练,让我很自卑。”虽然马加爵很聪明也很优秀,但他从没有真正自信过。

    自信的秘密是相信自己有能力。中国古谚:“天生我才必有用”,“一枝草,一点露”,每个人都有自己的特性和长处,值得看重和发挥。我记得我11岁刚到美国时,课堂上一句英语都听不懂,有一次老师问“1/7换算成小数等于几?”我虽然不懂英文,但认得黑板上的“1/7”,这是我以前“背”过的。我立刻举手并正确回答了这个问题。不会“背书”的美国老师诧异地认为我是个“数学天才”,并送我去参加数学竞赛,鼓励我加入数学夏令营,帮助同学学习数学。她的鼓励和同学的认可给了我自信。我开始告诉自己,我有数学的天分。这时,我特别想把英文学好,因为只有这样才能学习更多的数学知识。这种教育方式不但提高了我的自信,也帮助我在各方面取得了长足的进步。

    中国式教育认为人的成长是不断克服缺点的过程,所以老师更多是在批评学生,让学生弥补最差的学科。虽然应把每科都学得“足够好”,但人才的价值在于充分发挥个人最大的优点。美国盖洛普公司最近出了一本畅销书《现在,发掘你的优势》。盖洛普的研究人员发现:大部分人在成长过程中都试着“改变自己的缺点,希望把缺点变为优点”,但他们却碰到了更多的困难和痛苦;而少数最快乐、最成功的人的秘诀是“加强自己的优点,并管理自己的缺点”。“管理自己的缺点”就是在不足的地方做得足够好,“加强自己的优点”就是把大部分精力花在自己有兴趣的事情上,从而获得无比的自信。

    凌志军的《成长》一书里还有很多得到自信的例子:微软亚洲工程院院长张宏江说他从小就“相信我是最聪明的。即使再后来的日子里我常常不如别人,但我还是对自己说:我能比别人做得好”;微软亚洲研究院的主任研究员周明小时候在“学生劳动”中刷了108个瓶子,打破了纪录,从而获得自信。他说:“我原来一直是没有自信心的,但是这件事给了我自信。这是我一生中最快乐的经验,散发着一种迷人的力量,一直持续到今天。我发现了天才的全部秘密,其实只有6个字:不要小看自己。”

    自信是一种感觉,你没有办法用背书的方法“学习”自信,而唯一靠“学习”提升自信的方法是以实例“训练”你的大脑。要得到自信,你必须成为自己最好的拉拉队,每晚入睡前不妨想想,今天发生了什么值得你自豪的事情?你得到了好的成绩吗?你帮助了别人吗?有什么超出了你的期望吗?有谁夸奖了你吗?我相信每个人每天都可以找到一件成功的事情,你会慢慢发现,这些“小成功”可能会越来越有意义。

    有个著名教练在每次球赛前,总会要求队员回忆自己最得意的一次比赛。他甚至让队员把最得意的比赛和一个动作(如紧握拳头)联系起来,以便使自己每次做这个动作时,就会下意识地想到得意的事,然后在每次比赛前反复做这个动作以“训练”大脑,提升自信。

    希望同学们都能成为自己最好的拉拉队,同时多结交为你打气的朋友,多回味过去的成功,千万不要小看自己。

    自信的第二步:用毅力、勇气,从成功里获得自信,从失败里增加自觉
    当你感觉到自信时,无论多么小的成功,你都会特别期望再一次得到自己或别人的肯定,这时,你需要有足够的毅力。只要你有毅力,就会像周明所说的那样,“什么事情只要我肯干,就一定可以干好。你能学会你想学会的任何东西,这不是你能不能学会的问题,而是你想不想学的问题。如果你对自己手里的东西有强烈的欲望,你就会有一种坚韧不拔的精神,尤其当你是普通人的时候。”

    有时,你可能没做过某一件事,不知道能不能做成。这时,除了毅力外,你还需要勇气。我以前在工作中,一般的沟通没有问题,但到了总裁面前,总是不敢讲话,怕说错话。直到有一天,公司要做改组,总裁召集十多个人开会,他要求每个人轮流发言。我当时想,既然一定要讲,那不如把心里话讲出来。于是,我鼓足勇气说:“我们这个公司,员工的智商比谁都高,但是我们的效率比谁都差,因为我们整天改组,不顾到员工的感受和想法……”我说完后,整个会议室鸦雀无声。会后,很多同事给我发电子邮件说:“你说得真好,真希望我也有你的胆子这么说。”结果,总裁不但接受了我的建议,改变了公司在改组方面的政策,而且还经常引用我的话。从此,我充满了自信,不惧怕在任何人面前发言。这个例子充分印证了“你没有试过,你怎么知道你不能”这句话。

    有勇气尝试新事物的同时,也必须有勇气面对失败。大家不能只凭匹夫之勇去做注定要失败的事。但当你畏惧失败时,不妨想一想,你怕失去什么?最坏的下场是什么?你不能接受吗?在上面的例子中,如果总裁否定了我的看法,他会不尊重我吗?不但不会,别人很可能还会认为我勇气可嘉。而且,自觉的人会从失败中学习,认识到自己不适合做什么事情,再提升自己的自觉。因此,不要畏惧失败,只要你尽了力,愿意向自己的极限挑战,你就应为自己的勇气而自豪。

    一个自信和自觉的人,如果能勇敢地尝试新的事物,并有毅力把它做好,他就会从成功里获得自信,从失败里增加自觉。

    自信的第三步:自觉地定具体的目标,虚心地听他人的评估
    培养自信也要设定具体的目标,一步步地迈进。这些目标也必须是可衡量的。我曾把我在总裁面前发言的例子讲给我女儿听,因为她的老师认为她很害羞,在学校不举手发言,我希望鼓励她勇于发言。她同意试一试,但她认为只有在适当的时候,有最好的意见时才愿意发言。但是,我认为有了“最好的意见”这个主观的评估,目标就很难衡量。于是,我和她制定了一个可衡量的、实际的目标:她每天举一次手,如果坚持一个月就有奖励。然后,我们慢慢增加举手的次数。一年后,老师注意到,她对课堂发言有了足够的自信。

    自信绝非自我偏执、不容许自己犯错,或过度自我中心,失去客观的立场。我有个绝顶聪明的同事,他一生认准了“我永远不会错”这句“真理”。他表现得无比自信,一旦证明他某句话是对的,他就会提醒所有人几个月前他早就说过了。但因为他几乎是为了自信而活着,一旦证明他某句话是错的,他就会顾左右而言他,或根本否认此事。虽然他的正确率高达95%,但5%的错误让他失去了自己的信誉和他人的尊敬。这个例子告诉我们,自傲的自信或不自觉的自信甚至比不自信更加危险。

    情商中的自觉有两个层面:对自己和环境皆能俱到,掌握主客观的情势。有自觉的人不会过度地自我批评,也不会天真地乐观,他们能客观地评估自己。所以,他们会坦诚地面对自己的能力极限,不会轻易地接受自己能力范围外的工作。当然,他们仍乐于接受挑战,但会在接受挑战时做客观的风险评估。这样的人不但对自己坦诚,对他人也坦诚。坦诚地面对失败会得到别人的信赖,因为他们知道你接受了教训。坦诚地面对自己的缺点也会得到别人的尊敬,因为他们知道你不会自不量力。所以,自觉的人容易成功,也容易自信。

    自觉的人不但公平地评价自己,还主动要求周围的人给自己批评和反馈。他们明白,虽然自己很自觉,但别人眼中的自己是更为重要的。一方面,别人眼中的自己更为客观,另一方面,别人眼中的自己才是真正存在的自己(“Perception is reality”),也就是说,如果别人都认为你错了,只有你自认为没有错,那么在社会、学校或公司眼中,你就是错了。所以,你必须虚心地理解和接受别人的想法,而且以别人的想法作为最终的目标。比如,我女儿可以每天评估自己的发言,但最终,只有当老师和同学们认为她是个开朗的、有想法的学生时,她才达到了最终的目标。

    获得坦诚的反馈特别是负面的回馈并不容易。所以,你最好能有一些勇敢坦诚的知心好友,他们愿意在私下对你说真心话。当然,你不能对负面的反馈有任何不满,否则你以后就听不到真心话了。除了私下的反馈外,在美国的公司里,还有一种“360度”意见调查,可以对员工的上司、下属同时做多方面的调查。因为这种调查是匿名的,它往往能获得真实的意见,如果很多人都说你在某方面仍须改进,这样的说法就比自己的或老板的看法更有说服力。虽然在学校里没有这种正式的调查,但是你仍然可以尽力地去理解他人对你的想法。我的父亲常教诲我们凡事谋之于众,就是指开放心胸,切勿以井观天,局限了自己的视野。

    马加爵说:“同学都看不起我。”其实,如果他有勇气向他信任的同学求证,他也许会发现自己错怪了同学,也许会发现交错了朋友,也许会证实同学确实看不起他并了解其中的原因,然后自我改进。坦诚的交流和真心的朋友或许都可以帮助马加爵避免悲剧的发生。

    有自觉的人会为自己制定现实的目标,客观地衡量自己,并会请他人帮助评估。这样的人能持续提升自己的自信,并能避免自信发展为自傲。

    快乐比成功更重要
    科学研究证明:心情好的人最能发挥潜力;快乐能提高效率、创造力和正确决策的概率;快乐的人有开明的思想,愿意帮助别人。但与其说快乐带来成功,还不如说成功的目的是带来快乐。我曾建议同学们追逐自己的理想和兴趣,其实做自己理想的、有兴趣的事情就是一种快乐。所以,快乐比成功更应成为我们的最终目标。

    快乐的第一步:接受你的父母、环境、自己
    不快乐的人总对一些无奈的事生闷气,不喜欢自己、父母和老师,不愿意读枯燥的书、不愿意应付考试。对于这些无奈的事,我希望同学们能学会坦然地接受它们。

    在所有“不能改变的事情” 中,最不能改变的是父母,最应接受的也是父母。有不少学生说:“父母不理解我,不接受我,不体会我的想法,总要求我用他们的价值观和理念来做事、读书、求学。所以我总是避开他们,越来越孤独。”对这些同学,我的回答包括以下两个方面:

    第一,你应该接受你的父母,千万不要因为感觉父母不理解你而自我封闭。父母的成长环境不同,思维方式不同,他们对成功的定义可能也不同,对你的期望与你对自己的期望就有较大的差异。但他们人生的路走得比你长,经验比你丰富,你不能先入为主地排斥他们。另外,你必须理解,父母是世界上最爱你的人,他们也是唯一可以无条件为你付出的人,你应该无条件地接受你的父母。作子女的经常把父母亲过度理想化,而疏忽了绝大多数的父母,在他们生长的环境中,比我们更为匮乏、不足,他们可能没有机会学习如何当一个称职的父母,但以他们的条件,也尽力了。如果我们鄙视、排斥父母,无异是对自己生命的来源不敬,那如何能快乐?

    第二,你可以试着去改变父母的想法,但你首先应反问,你理解和接受你的父母吗?你能体会父母的想法吗?当你抱怨父母总是期望你完美时,难道你不也是在期望父母完美吗?凌志军建议说:“父母对你们的期望没有错,只是你们应该让父母了解,你们对他们的期望。”所以,在要求他们理解你之前,你应先去理解他们,这样才能更成功地和他们沟通。相互了解后,也许你们仍有不同意见但能彼此谅解,也许你或他们会改变原来的看法而达到共识。为此,你首先应和父母建立一个坦诚的沟通关系。也许起初你们会觉得别扭,但我相信你们很快就会体会到亲情与温馨。

    除了接受父母,你还应接受环境中不能改变的事情。有些同学期望着不必考他们认为没用的题目,不必上他们认为没用的课,不必听他们不信任的老师讲课。但在社会中生存,我们必须学会接受那些不能改变的事。凌志军说:“如果我遇到‘应该做的事情’和‘喜欢做的事情’之间的冲突,我会给自己安排一个时间表,每天在规定的时间里完成‘应该做的事情’——时间表能激励你集中精力并提高效率。然后去做‘喜欢做的事情’。”人生是有限的,大家应把有限的时间用在“喜欢做的事情”上,但必须先把“应该做的事情”做得足够好。

    最无谓的“发愁”就是对自己不满意。这不但浪费了时间,而且会造成事倍功半。所以,同学们一方面要培养自己的自信,以每一个小的成功来激励自己,另一方面也必须能接受自己,理解你们是为自己而生活的。为自己而生活就是要为了自己的快乐、兴趣和人生目标而努力,不要活在别人的价值观里。微软亚洲研究院院长沈向洋小时候一直活在别人的价值观里,为了“第一名”拼命,但是有一天,“我忽然意识到原来的想法错了。打败别人,得第一名,不是最重要的。最重要的是,你能不能学会尊重你自己,能不能发现自己的价值在哪里。”

    当你开始为自己而生活,接受并喜欢你自己,接受并接近你的父母,接受环境中不能改变的事情,你就会发现你开始快乐了。

    快乐的第二步:宣泄你的情感,控制你的脾气
    心理学家认为,马加爵“在精神上一直是孤独的,因为他总不愿与人交流,不愿说出自己真实的感受……是一个情绪反应相当激烈的人,但是他外表上又是一个相当压抑的人。”马加爵给亲人的信上也写道:“我这个人动情的话历来就讲不出口。”如果马加爵能直接地宣泄自己的感情,他也许可以防止悲剧发生。事后马加爵也想到:“逃亡的时候觉得自己傻,可以选择吵架就算了,没有必要杀人。”

    中国人总认为矜持、含蓄是美德。但我认为,在今天的时代里,直截了当的沟通更为重要。拐弯抹角、言不由衷、瞻前顾后、当面不说、背后乱讲都是坏习惯。有一位中国老板和他的下属吵架,他问我是不是该请第三者调解,我给他的建议是:因为这是情感的事情,你应该直接去和下属沟通;第三者为了做和事佬,可能会说出违背你或你的下属意愿的话(例如谎称你已经认错,但其实你没有),这反而会造成更多的麻烦。

    当然,在情感问题上,直接沟通也需要技巧。例如,那位老板如果第一句话就对下属说:“你错了,但是我不和你计较。”那么下属肯定会反感。如果老板说:“你在那么多人面前骂我,很显然是你想抢我的工作。”结果就更不堪设想。显然,当你直接沟通时,不要论对错,不要猜测别人的动机,更不要再趁机补一句。最有效的沟通就是直接谈到你的感情,比如那位老板可以说:“当你在那么多人面前骂我时,我感到失去尊严,非常为难。”这样一句话是不能反驳的,甚至可能会引发理解和同情。

    当你怒火中烧时,把愤怒的话转变成感性的话并不容易。要做到这一点,我们又需要依靠“自觉”和 “自控”。自觉不只是认识自己的能力,更是认识自己的感情。自觉的人知道自己何时会喜怒哀乐,也理解喜怒哀乐的宣泄会造成何种后果。如果他感到气愤,他不会瞬间爆炸,因为他知道爆炸的后果,但他也不会压抑自己的感情,因为那会对心灵造成很大的伤害,他通常会尽量自控地用最有建设性的方式处理。正面、感性的沟通可以降低火爆的气氛。感情和沟通都是最有感染性的,你完全可以用有建设性的、宽容的态度来与他人沟通并影响他人。

    自控是一种内心的自我对话,可以提醒自己不要落入恶劣态度的陷阱。除了上溯的理智分析外,深呼吸是最快、最简单的情绪调节方法,中国人说:“心浮气躁”、“心神不宁”、“心乱如麻”、“心焦如焚”,指的都是心情紊乱和情绪及精神状态的关系,而“气定神闲”、“心安理得”最方便的作法就是深呼吸,也就藉由调气调息,把气调顺了,比较能摆脱情绪的牵扯,回到理性思考。美国对有暴力行为的加害人,都会施以团体教育,而教导他们认清暴力的毁灭性,学习控制自己的冲动,也就是懂得“叫停”或“离开现场”,以保护自己和对方的安全,避免铸成大错。

    如果认为自控不容易,那么,你可以请你的知心好友随时提醒你。我过去的一个老板常常一生气就一发不可收拾,而且他生气都有前兆:他会先用刁钻的问题考倒你,然后他开始战抖,最后他才发脾气。但他想改掉这个毛病,于是他要求我在每次看到前兆时,用一句“密语”(如“让我们言归正传吧”)来提醒他。几次“密语”提醒之后,他就有了自觉和自控的能力,再也不需要别人提醒了。

    快乐的第三步:有人分享快乐加倍,有人分担痛苦减半
    科学研究告诉我们,调节自己的心情最好的方法就是找到知心的人倾诉和沟通。科学的根据是,感情源于人脑的lymbic系统,而该系统主要靠与他人的接触调节。科学证明,在一起交谈的两个人会慢慢达到同样的心理状态(喜怒哀乐)和生理状态(体温、心跳等)。因此,若想达到感情的平衡,我们必须懂得依靠别人。与人沟通是提升你的情商和快乐的唯一方法。与世隔绝的人只会越来越苦闷。西方有一古谚:“有人分享快乐加倍,有人分担痛苦减半。”马加爵所谓的真情,应该就是指能分享心情、内心的人吧!

    所以,如果你情绪不好,或受了委屈时,应多向父母、朋友倾诉,不要像马加爵那样总把话闷在心里,只对日记倾诉。马加爵很苦闷,却没有倾诉苦闷的渠道。他说:“我在学校一个朋友也没有,我在学校那么落魄……在各种孤独中间,人最怕精神上的孤独。”马加爵在人际交往中碰到很多障碍,这些障碍带给他苦闷,而这些苦闷又没有渠道宣泄,进而造成更大的苦闷。这个恶性循环最终导致了悲剧的发生。其实,马加爵的内心独白,证明他是一个有自觉的人,他能看清自己的困境,可惜他将自己锁在自我封闭的牢笼里,让仇恨把他带向毁灭。记得去年,非典风波,最恐怖的威胁就是被隔离,可是平日里我们却常忽略了心里的孤立,使我们和快乐绝缘。

    要得到快乐,你需要幽默、乐观的想法和沟通。在所有的沟通中,“笑”的感染力是最大的。耶鲁大学的研究发现,“笑”的感染力超过了所有其他感情,人们总会反射式地以微笑来回报你的微笑,而开怀的大笑更能迅速创造一个轻松的气氛,此外,幽默的笑也能促进相互信任,激发灵感。乐观、正面思考的力量是无穷的。近年来忧郁症已成为全世界来势汹汹的心理疾病,而其和负面思考有极大的关系,有些人习惯钻牛角尖,往悲观无助的方向想,困在死胡同中。如果能换个角度,半杯水有一半满的而非一半空的!现在的不如意,代表有无限成长进步的空间。学习检查自己,常保正念。

    无论是驱逐悲伤或是获取快乐,我们都需要从倾诉和沟通中得到正面的激励。最自然的沟通对象可能是你的亲人,特别是你的父母。我相信,所有的父母都愿意听孩子的倾诉。

    但是,“在家靠父母,出外靠朋友”,所以我们也需要和知心朋友沟通、倾诉。交朋友时不要只看朋友的嗜好和个性,更重要的是,你需要一些会鼓励人的、乐观的、幽默的、诚恳的、有同理心的、乐于助人的、愿意听人诉说的朋友。也许你会说:“我没有这样的朋友,也不敢去乱找朋友,如果别人拒绝怎么办?”如果别人拒绝你,你没有失去任何东西,但如果别人接受你,你可能因此找到你自己。

    我希望你也会在寻找好友的过程中,也让自己成为这样一个会鼓励人的、乐观的、幽默的、诚恳的、有同理心的、乐于助人的、愿意听人诉说的人,并尽力去帮助你周围的亲人和朋友。唯有更多人愿意付出,快乐才能更迅速地通过人际网扩散。

    给中国学生的祝福
    我一直信奉以下做事的三原则:有勇气来改变可以改变的事情,有度量接受不可改变的事情,有智慧来分辨两者的不同。

    祝福中国的学生,当你碰到挫折时,能用这三个原则,以度量、勇气、智慧来帮助你渡过难关。

    祝福中国的学生,当你追求成功、自信、快乐时,不要忘了成功是多元化的,不要忘了自信是自觉而非自傲,不要忘了快乐的人总能理解、接受和喜欢自己。

    祝福中国的学生,当你逐步获得成功、自信、快乐时,会发现一个良性循环:从成功里得到自信和快乐,从自信里得到快乐和成功,从快乐里得到成功和自信。

    祝福中国的学生,当你拥有成功、自信、快乐后,不要忘了帮助他人获得成功、自信和快乐。
    posted @ 2006-12-14 09:24 重归本垒(Bing) 阅读(229) | 评论 (0)编辑 收藏
     
    在我们不断塑造自我的过程中,影响最大的莫过于是选择乐观的态度还是悲观的态度。我们思想上的这种抉择可能给我们带来激励,也有可能阻滞我们前进。

      清晰地规划目标是人生走向成功的第一步,但塑造自我却不仅限于规划目标。要真正塑造自我和自己想要的生活,我们必须奋起行动。莎士比亚说得好:"行动胜过雄辩。"

      一旦掌握自我激励,自我塑造的过程也就随即开始。以下方法可以帮你塑造自我,塑造那个你一直梦寐以求的自我。

      树立远景 迈向自我塑造的第一步,要有一个你每天早晨醒来为之奋斗的目标,它应是你人生的目标。远景必须即刻着手建立,而不要往后拖。你随时可以按自己的想法做些改变,但不能一刻没有远景。

      离开舒适区 不断寻求挑战激励自己。提防自己,不要躺倒在舒适区。舒适区只是避风港,不是安乐窝。它只是你心中准备迎接下次挑战之前刻意放松自己和恢复元气的地方。

      把握好情绪 人开心的时候,体内就会发生奇妙的变化,从而获得阵阵新的动力和力量。但是,不要总想在自身之外寻开心。令你开心的事不在别处,就在你身上。因此,找出自身的情绪高涨期用来不断激励自己。

      调高目标 许多人惊奇地发现,他们之所以达不到自己孜孜以求的目标,是因为他们的主要目标太小、而且太模糊不清,使自己失去动力。如果你的主要目标不能激发你的想象力,目标的实现就会遥遥无期。因此,真正能激励你奋发向上的是,确立一个既宏伟又具体的远大目标。

      加强紧迫感 20世纪作者Anais Nin(阿耐斯)曾写道:"沉溺生活的人没有死的恐惧"。自以为长命百岁无益于你享受人生。然而,大多数人对此视而不见,假装自己的生命会绵延无绝。惟有心血来潮的那天,我们才会筹划大事业,将我们的目标和梦想寄托在enis Waitley(丹尼斯)称之为 "虚幻岛" 的汪洋大海之中。其实,直面死亡未必要等到生命耗尽时的临终一刻。事实上,如果能逼真地想象我们的弥留之际,会物极必反产生一种再生的感觉,这是塑造自我的第一步。

      撇开朋友 对于那些不支持你目标的 "朋友" ,要敬而远之。你所交往的人会改变你的生活。与愤世嫉俗的人为伍,他们就会拉你沉沦。结交那些希望你快乐和成功的人,你就在追求快乐和成功的路上迈出最重要的一步。对生活的热情具有感染力。因此同乐观的人为伴能让我们看到更多的人生希望。

      迎接恐惧 世上最秘而不宣的秘密是,战胜恐惧后迎来的是某种安全有益的东西。哪怕克服的是小小的恐惧,也会增强你对创造自己生活能力的信心。如果一味想避开恐惧,它们会象疯狗一样对我们穷追不舍。此时,最可怕的莫过于双眼一闭假装它们不存在。

      做好调整计划 实现目标的道路绝不是坦途。它总是呈现出一条波浪线,有起也有落。但你可以安排自己的休整点。事先看看你的时间表,框出你放松、调整、恢复元气的时间。即使你现在感觉不错,也要做好调整计划。这才是明智之举。在自己的事业波峰时,要给自己安排休整点。安排出一大段时间让自己隐退一下,即使是离开自己爱的工作也要如此。只有这样,在你重新投入工作时才能更富激情。

      直面困难 每一个解决方案都是针对一个问题的。二者缺一不可。困难对于脑力运动者来说,不过是一场场艰辛的比赛。真正的运动者总是盼望比赛。如果把困难看作对自己的诅咒,就很难在生活中找到动力。如果学会了把握困难带来的机遇,你自然会动力陡生。

      首先要感觉好 多数人认为,一旦达到某个目标,人们就会感到身心舒畅。但问题是你可能永远达不到目标。把快乐建立在还不曾拥有的事情上,无异于剥夺自己创造快乐的权力。记住,快乐是天赋权利。首先就要有良好的感觉,让它使自己在塑造自我的整个旅途中充满快乐,而不要再等到成功的最后一刻才去感受属于自己的欢乐。

      加强排练 先"排演"一场比你要面对的珲要复杂的战斗。如果手上有棘手活而自己又犹豫不决,不妨挑件更难的事先做。生活挑战你的事情,你定可以用来挑战自己。这样,你就可以自己开辟一条成功之路。成功的真谛是:对自己越苛刻,生活对你越宽容;对自己越宽容,生活对你越苛刻。

      立足现在 锻炼自己即刻行动的能力。充分利用对现时的认知力。不要沉浸在过去,也不要耽溺于未来,要着眼于今天。当然要有梦想、筹划和制订创造目标的时间。不过,这一切就绪后,一定要学会脚踏实地、注重眼前的行动。要把整个生命凝聚在此时此刻。

      敢于竞争 竞争给了我们宝贵的经验,无论你多么出色,总会人外有人。所以你需要学会谦虚。努力胜过别人,能使自己更深地认识自己;努力胜过别人,便在生活中加入了竞争 "游戏 " 。不管在哪里,都要参与竞争,而且总要满怀快乐的心情。要明白最终超越别人远没有超越自己更重要。

      内省 大多数人通过别人对自己的印象和看法来看自己。获得别人对自己的反映很不错,尤其正面反馈。但是,仅凭别人的一面之辞,把自己的个人形象建立在别人身上,就会面临严重束缚自己的危险。因此,只把这些溢美之词当作自己生活中的点缀。人生的棋局该由自己来摆。不要从别人身上找寻自己,应该经常自省并塑造自我。

      走向危机 危机能激发我们竭尽全力。无视这种现象,我们往往会愚蠢地创造一种追求舒适的生活,努力设计各种越来越轻松的生活方式,使自己生活得风平浪静。当然,我们不必坐等危机或悲剧的到来,从内心挑战自我是我们生命力量的源泉。圣女贞德(Joan of Arc)说过:"所有战斗的胜负首先在自我的心里见分晓。"

      精工细笔 创造自我,如绘巨幅画一样,不要怕精工细笔。如果把自己当作一幅正在描绘中杰作,你就会乐于从细微处做改变。一件小事做得与众不同,也会令你兴奋不已。总之,无论你有多么小的变化,点点都于你很重要。

      敢于犯错 有时候我们不做一件事,是因为我们没有把握做好。我们感到自己"状态不佳"或精力不足时,往往会把必须做的事放在一边,或静等灵感的降临。你可不要这样。如果有些事你知道需要做却又提不起劲,尽管去做,不要怕犯错。给自己一点自嘲式幽默。抱一种打趣的心情来对待自己做不好的事情,一旦做起来了尽管乐在其中。

      不要害怕拒绝 不要消极接受别人的拒绝,而要积极面对。你的要求却落空时,把这种拒绝当作一个问题: "自己能不能更多一点创意呢?"不要听见不字就打退堂鼓。应该让这种拒绝激励你更大的创造力。

      尽量放松 接受挑战后,要尽量放松。在脑电波开始平和你的中枢神经系统时,你可感受到自己的内在动力在不断增加。你很快会知道自己有何收获。自己能做的事,不必祈求上天赐予你勇气,放松可以产生迎接挑战的勇气。

      一生的缩影 塑造自我的关键是甘做小事,但必须即刻就做。塑造自我不能一蹴而就,而是一个循序渐进的过程。这儿做一点,那儿改一下,将使你的一天(也就是你的一生)有滋有味。今天是你整个生命的一个小原子,是你一生的缩影。

      大多数人希望自己的生活富有意义。但是生活不在未来。我们越是认为自己有充分的时间去做自己想做的事,就越会在这种沉醉中让人生中的绝妙机会悄然流逝。只有重视今天,自我激励的力量才能汩汩不绝。

    posted @ 2006-12-14 09:22 重归本垒(Bing) 阅读(199) | 评论 (0)编辑 收藏
     
         摘要: ---servlet文件 import  java.io. * ; import  java.util.Date; import  javax.servlet. * ; import  javax.servlet.http. * ;...  阅读全文
    posted @ 2006-12-12 10:43 重归本垒(Bing) 阅读(418) | 评论 (0)编辑 收藏
     
    1.文件打包

          jar cf myname.jar *.class

    2.证书位置

    自签名的数字证书要放在一个文件中(通常称为“密钥链”(keychain)),如果输入
          keytool -list
    那么访问缺省文件,如果没有这个文件,那么就要创建一个,或指定一个已存在的文件。一般为“cacerts”,运行:
          keytool -list -file <path/filename>
    缺省位置一般为:
          {java.home}/lib/security/cacerts

    3.创建签名

    运行:
          keytool -genkey -alias <keyname> -keystore <url>
    这里keyname就是为你的密钥取一个别名,url就放密钥的位置,通常为"cacerts".按提示输入密码等信息。
    keytool有很多的运行参数,如-valid就是可以指定密钥的有效天数。

    4.查看新建的密钥

    运行:
          keytool -list -keystore <url>

    5.给自己的jar文件签名

    运行:
       jarsigner -keystore <url> <jarfile> <keyname>
    url表示cacerts文件的位置,jarfile是自己的jar文件的名称,keyname是密钥的名称。

    6.在网页用使用

    现在就有一个jar文件,它标识成是采用自己提供的密钥进行签名的,这样子就能保证在签名之后,这个jar文件没有被篡改过。
    不过要确保html文件中的applet标记包含了“archive”属性,来指定jar文件的名称。

        <applet code=ifpre.io.FileAccessApplet
         achive=ifpreFileAccessApplet 
         width=200 
         heigt =100> 
        </applet> 
    posted @ 2006-12-12 09:51 重归本垒(Bing) 阅读(1031) | 评论 (2)编辑 收藏
     

     

              

    ========

    Chap11    对象的集合

     

           1.数组

           数组与其它容器的区别体现在三个方面:效率,类型识别,以及可以持有primitives。

           数组是Java提供的,能随机存储和访问reference序列的诸多方法中,最高效的一种。速度的代价是,当一个数组创建后,容量就固定了。

           创建数组的时候,同时指明了数组元素的类型。而泛型容器类如List,Set和Map等,所持有的对象均被上传为Object。

          

           2.数组是第一流的对象

           数组的标识符实际上是一个“创建在堆(heap)里的实实在在的对象的”reference。这个对象持有其它对象的reference,或直接持有primitive类型的值。

          

           3.Arrays类

           java.util.Arrays类,包括了一组可用于数组的static方法。其中asList()方法,可把数组转成一个List。

           Arrays.fill()方法,把一个值或对象的reference拷贝到数组的各个位置,或指定的范围。

          

           4.复制一个数组

           相比for循环,System.arrayCopy()能以更快的速度拷贝数组。如果是对象数组,拷贝的是数组中对象的reference,对象本身不会被拷贝。这被称为浅拷贝(Shallow copy)。

          

           5.数组的比较

           Arrays提供了equals()方法。数组是否相等是基于其内容的。

           数组要想完全相等,它们必须有相同数量的元素,且数组的每个元素必须与另一个数组的对应位置上的元素相等。

           元素的相等性,用equals()判断。对于primitive,会使用其wrapper类的equals()。

          

           6.数组元素的比较

           实现比较功能的一个方法是实现java.lang.Comparable接口。这个接口只有一个compareTo()方法。

           Arrays.sort()会把传给它的数组的元素转换成Comparable。如果数组元素没有实现Comparable接口,就会引发一个ClassCastException。

           实现比较功能的另一个方法使用策略模式(strategy design pattern),即实现Comparator接口。

           Arrays.sort()可接受一个数组和一个Comparator,根据Comparator的compare()方法对数组元素排序。

           Java标准类库所用的排序算法已经作了优化--对于primitive,它用的是快速排序(Quicksort),对于对象,它用的是稳定合并排序(stable merge sort)。

          

           7.查询有序数组

           一旦对数组进行了排序,就能用Arrays.binarySearch()进行快速查询了。但切忌对一个尚未排序的数组使用binarySearch()。

           如果Arrays.binarySearch()查找到了,就返回一个大于或等于0的值。否则返回负值。这个负值的意思是,如果手动维护这个数组,这个值应该插在哪个位置。这个值是:

           -(插入点)-1

           “插入点”就是,在所有比要找的值更大的值中,最小的那个值的下标。如果数组中所有值都比要查找的值小,它就是a.size()。

           如果数组里有重复元素,binarySearch()不能保证返回哪一个,但也不报错。

           如果排序的时候用到了Comparator,那么调用binarySearch()的时候,也必须使用同一个Comparator。

          

           8.数组部分的总结

           如果要持有一组对象,首选,同时效率最高的,应该是数组。如果是要持有一组primitive,也只能用数组。

          

           9.容器简介

           Java2的容器类要解决“怎样持有对象”,它把这个问题分成两类:

           (1).Collection:通常是一组有一定规律的独立元素。List必须按特定的顺序持有这些元素,而Set不能保存重复的元素。

           (2).Map:一组以“键-值”(key-value)形式出现的pair。Map可以返回键(Key)的Set,值的Collection,或者pair的Set。

          

           10.填充容器

           Collection也有一个辅助类Collections,它包含了一些静态的使用工具方法,其中有fill()。fill()只是把同一个对象的reference负值到整个容器,而且只能为List,不能为Set和Map工作。并且这个fill()只能替换容器中的值,而不是往List加新元素。如:

           List list = new ArrayList();

           for(int i = 0; i<10; i++)

                  list.add("");

           Collections.fill(list, "Hello");

          

           11.容器的缺点:不知道对象的类型

           Java的容器只持有Object。容器对“能往里面加什么类型的对象”没有限制。在使用容器中的对象之前,还必须进行类型转换

          

           12.迭代器

           迭代器(iterator),又是一个设计模式。iterator能让程序员在不知道或不关心他所处理的是什么样的底层序列结构的情况下,在一个对象序列中前后移动,并选取其中的对象。iterator是“轻量级”的对象,即创建代价很小的对象。

           不经意的递归(Unintended recursion)

           public class A{

                  public String toString(){

                         return "A address:" + this +"\n";//

                  }

                  public static void main(String[] args){

                         System.out.println(new A());

                  }

           }

           上面的程序会出现无穷无尽的异常。

           "A address:" + this         ,编译器会试着将this转换成String,要用大toString(),于是就变成递归调用了。

           如果想打印对象的地址,应该调用Object的toString()方法。而不要用this,应该写super.toString()。

          

           13.List的功能

           ArrayList,一个用数组实现的List。能进行快速的随机访问,但是往列表中插入和删除元素比较慢。

           LinkedList,对顺序访问进行了优化。在List中插入和删除元素代价也不高。但是随机访问的速度相对较慢。可以把它当成栈(Stack),队列(queue)或双向队列(deque)来用。

          

           14.Set的功能

           加入Set的每个元素必须是唯一的。要想加进Set,Object必须定义equals(),才能标明对象的唯一性。

           HashSet,为优化查询速度而设计的Set。要放进HashSet的Object还要定义hashCode()。

           TreeSet,一个有序的Set,能从中提取一个有序序列。用了红黑树(red-black tree)数据结构。

           LinkedHashSet,使用链表的Set,既有HashSet的查询速度,又能保存元素的插入顺序。用Iterator遍历Set的时候,它是按插入顺序进行访问的。

           Set要有一个判断以什么顺序来存储元素的标准,也就是说必须实现Comparable接口,并且定义compareTo()方法。

          

           15.SortedSet

           SortedSet(只有TreeSet这一个实现可用)中的元素一定是有序的。SortedSet的意思是“根据对象的比较顺序”,而不是“插入顺序”进行排序。

          

           16.Map的功能

           如果知道get()是怎么工作的,就会发觉在ArrayList里面找对象是相当慢的。而这正是HashMap的强项。HashMap利用对象的hashCode()来进行快速查找。

           Map的keySet()方法返回一个由Map的键组成的Set。values()返回的是由Map的值所组成的Collection。由于这些Collection的后台都是map,因此对这些Collection的任何修改都会反映到Map上。

          

           17.SortedMap

           SortedMap(只有TreeMap这一个实现)的键肯定是有序的。

          

           18.LinkedHashMap

           为提高速度,LinkedHashMap对所有东西都作了hash,而且遍历的时候,还会按插入顺序返回pair。此外,还可通过构造函数进行配置,让它使用基于访问的LRU(least-recently-used)算法,这样没被访问过的元素(通常也是要删除的候选对象)就会出现在队列的最前面。

          

           19.散列算法与Hash数

           要想用自己的类作HashMap的键,必须覆写equals()和hashCode()。HashMap用equals()来判断查询用的键是否与表里其它键相等。

           Object的hashCode(),在缺省情况下就是返回对象的内存地址。

          

           一个合适的equals()必须做到以下五点:

           (1).反身性:对任何x,x.equals(x)必须是true。

           (2).对称性:对任何x和y,如果y.equals(x)是true的,那么x.equals(y)也必须是true。

           (3).传递性:对任何x,y和z,如果x.equals(y)是true,且y.equals(z)也是true,那么x.equals(z)也必须是true。

           (4).一致性:对任何x和y,如果对象里面用来判断相等性的信息没有修改过,那么无论调用多少次x.equals(y),它都必须一致地返回true或false。

           (5).对于任何非空的x,x.equals(null)必须返回false。

          

           默认的Object.equals()只是简单地比较两个对象的地址,所以一个Dog("A")会不等于另一个Dog("A")。

           下面是覆写equals()和hashCode()的例子。

           public class Dog{

                  public int id;

                  public Dog(int x){ id = x; }

                  public int hashCode(){ return id; }

                  public boolean equals(Object o){

                         return (o instanceof Dog) && (id == ((Dog)o).id)

                  }

           }

           equals()在利用instanceof检查参数是不是Dog类型的同时,还检查了对象是不是null,如果是null,instanceof会返回false。

          

           20.理解hashCode()

           数组是最快的数据结构,所以很容易想到用数组存储Map的键的信息(而不是键本身)。Map要能存储任意数量的pair,而键的数量又被数组的固定大小限制了,所以不能用数组存储键本身。

           要解决定长数组的问题,就得允许多个键生成同一个hash数,也就是会有冲突,每个键对象都会对应数组的某个位置。

           查找过程从计算hash数开始,算完后用这个数在数组里定位。如果散列函数能确保不产生冲突(如果对象数量是固定的,这是可能的),那么它就被称为“完全散列函数”,这是特例。通常,冲突是由“外部链(external chaining)”处理的:数组并不直接指向对象,而是指向一个对象的列表。然后再用equals()在这个列表中一个个找。如果散列函数定义得好,每个hash数只对应很少的对象,这样,与搜索整个序列相比,能很快跳到这个子序列,比较少量对象,会快许多。

           hash表的“槽位”常被称为bucket。

          

           21.影响HashMap性能的因素

           Capacity:hash表里bucket的数量。

           Initial capacity:创建hash表时,bucket的数量。

           Size:当前hash表的记录的数量。

           Load factor:size/capacity。一个负载较轻的表会有较少的冲突,因此插入和查找的速度会比较快,但在用迭代器遍历的时候会比较慢。

           HashMap和HashSet都提供了能指定load factor的构造函数,当load factor达到这个阀值的时候,容器会自动将capacity(bucket的数量)增加大约一倍,然后将现有的对象分配到新的bucket里面(这就是所谓的rehash)。缺省情况下HashMap会使用0.75的load factor。

          

           22.选择实现

           HashTable,Vector和Stack属于老版本遗留下来的类,应该避免使用。

           如何挑选List

           数组的随机访问和顺序访问比任何容器都快。ArrayList的随机访问比LinkedList快,奇怪的时LinkedList的顺序访问居然比ArrayList略快。LinkedList的插入和删除,特别时删除,比ArrayList快很多。Vector各方面速度都比ArrayList慢,应避免使用。

           如何挑选Set

           HashSet各项性能都比TreeSet好,只有在需要有序的Set时,才应该用TreeSet。

           LinkedHashSet的插入比HashSet稍慢一些,因为要承担维护链表和hash容器的双重代价,但是它的遍历速度比较快。

           如何挑选Map

           首选HashMap,只有在需要有序map时,才选TreeMap。LinkedHashMap比Hashmap稍慢一些。

          

           23.把Collection和Map设成不可修改的

           Collections.unmodifiableCollection()方法,会把传给它的容器变成只读版返回。这个方法有四种变形,unmodifiableCollection(),unmodifiableList(),unmodifiableSet(),unmodifiableMap()。

          

           24.Collection和Map的同步

           Collections里有一个自动对容器做同步的方法,它的语法与“unmodifiable”方法有些相似。synchronizedCollection(),synchronizedList(),synchronizedSet(),synchronizedMap()。

          

           25.Fail fast

           Java容器类库继承了fail-fast(及早报告错误)机制,它能防止多个进程同时修改容器的内容。当它发现有其它进程在修改容器,就会立即返回一个ConcurrentModificationException。

          

           26.可以不支持的操作

           可以用Arrays.asList()把数组改造成List,但它只是部分的实现了Collection和List接口。它支持的都是那些不改变数组容量的操作,不支持add(),addAll(),clear(),retainAll(),remove(),removeAll()等。调用不支持的方法会引发一个UnsupportedOperationException异常。

           要想创建普通容器,可以把Arrays.asList()的结果做为构造函数参数传给List或Set,这样就能使用它的完整接口了。

          

          

          

          

    =============

    Chap12   Java I/O系统

     

           1.File类

           File类有一个极具欺骗性的名字,可以用来表示某个文件的名字,也可以用来表示目录里一组文件的名字。

           File类的功能不仅限于显示文件或目录。它能创建新的目录,甚至是目录路径。此外还能检查文件的属性,判断File对象表示的是文件还是目录,以及删除文件等。

          

           2.输入与输入

           流(Stream)是一种能生成或接受数据的,代表数据的源和目标的对象。流把I/O设备内部的具体操作给隐藏起来了。

           Java的I/O类库分成输入和输出两大部分。

          

           3.添加属性与适用的接口

           使用“分层对象(layered objects)”,为单个对象动态地,透明地添加功能的做法,被称为Decorator Pattern。Decorator模式要求所有包覆在原始对象之外的对象,都必须具有与之完全相同的接口。无论对象是否被decorate过,传给它的消息总是相同的。

           为InputStream和OutputStream定义decorator类接口的类,分别是FilterInputStream和FilterOutputStream,它们都继承自I/O类库的基类InputStream和OutputStream,这是decorator模式的关键(惟有这样,decorator类的接口才能与它要服务的对象的完全相同)。

           对于I/O类库来说,比较明智的做法是,普遍都做缓冲,把不缓冲当特例。

          

           Reader和Writer类系

           InputStream和OutputStream的某些功能已经淘汰,但仍然提供了很多有价值的,面向byte的I/O功能。而Java 1.1引进的Reader和Writer则提供了Unicode兼容的,面向字符的I/O功能。Java 1.1还提供了两个适配器(adapter)类,InputStreamReader和OutputStreamWriter负载将InputStream和OutputStream转化成Reader和Writer。

           Reader和Writer要解决的,最主要是国际化。原先的I/O类库只支持8位的字节流,因此不可能很好地处理16位的Unicode字符流。此外新类库的性能也比旧的好。

          

           4.数据源和目的

           几乎所有的Java I/O流都有与之对应的,专门用来处理Unicode的Reader和Writer。但有时,面向byte的InputStream和OutputStream才是正确的选择,特别是java.util.zip,它的类都是面向byte的。

           明智的做法是,先用Reader和Writer,等到必须要用面向byte的类库时,你自然会知道,因为程序编译不过去了。

          

           5.常见的I/O流的使用方法

           (1).对输入文件做缓冲

           BufferedReader in = new BufferedReader( new FileReader("IOStreamDemo.java"));

           String s, s2 = new String();

           while((s = in.readLine())!= null)

                  s2 += s + "\n";//readLine()会把换行符剥掉,所以在这里加上。

           in.close();

           //读取标准输入

           BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in));

           System.out.print("Enter a line:");

           System.out.println(stdin.readLine());

          

           (2).读取内存

           StringReader in2 = new StringReader(s2);

           int c;

           while((c = in2.read())!=-1)//read()会把读出来的byte当做int

                  System.out.print((char)c);

          

           (3).读取格式化内存

           try{

                  DataInputStream in3 = new DataInputStream(new ByteArrayInputStream(s2.getBytes()));

                  while(true)

                         System.out.print((char)in3.readByte());//无法根据readByte()返回值判断是否结束

           } catch(EOFException e){

                  System.err.println("End of stream");

           }

           //使用available()来判断还有多少字符

           DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("TestEOF.java")));

           while(in.available() != 0)

                  System.out.print((char)in.readByte());

          

           (4).读取文件

           try{

                  BfferedReader in4 = new BufferedReader(new StringReader(s2));

                  PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter(IODemo.out)));

                  int lineCount = 1;

                  while((s = in4.readLine())!= null)

                         out1.println(lineCount++ +": "+ s);

                  out1.close();

           } catch(EOFException e){

                  System.err.println(End of stream);

           }

           使用PrintWriter去排版,就能得出能够读得懂的,普通的文本文件。

          

           6.标准I/O

           标准I/O是Unix的概念,意思是,一个程序只使用一个信息流。所有输入都是从“标准输入”进来的,输出都从“标准输出”出去,错误消息都送到“标准错误”里。

           Java遵循标准I/O的模型,提供了Syetem.in,System.out,以及System.err。

          

           将System.out转换成PrintWriter

           System.out是PrintStream,也就是说它是OutputStream。不过可通过PrintWriter的构造函数把它改造成PrintWriter。

           PrintWriter out = new PrintWriter(System.out, true);

           out.println("Hello, world");

           为了启动自动清空缓冲区的功能,一定要使用双参数版的构造函数,并把第二个参数设成true。这点非常重要,否则就有可能会看不到输出。

          

           标准I/O的重定向

           Java的System类提供了几个能重定向标准输入,标准输出和标准错误的静态方法:

           setIn(InputStream),setOut(PrintStream),setErr(PrintStream)。

           I/O重定向处理的不是character流,而是byte流,因此不能用Reader和Writer,要用InputStream和OutputStream。

          

           7.New I/O

           Java 1.4的java.nio.*引入了一个新的I/O类库,其目的就是提高速度。实际上,旧的I/O类库已经用nio重写。

           性能的提高源于它用了更贴近操作系统的结构:channel和buffer。

           java.nio.ByteBuffer是唯一一个能直接同channel打交道的buffer。它是一个相当底层的类,存储和提取数据的时候,可以选择是以byte形式还是以primitive形式,但它不能存储对象。这是为了有效地映射到绝大多数操作系统上。

           新I/O修改了旧I/O的三个类,即FileInputStream,FileOutputStream,以及RandomAccessFile,以获取FileChannel。

           // Write a file:

        FileChannel fc = new FileOutputStream("data.txt").getChannel();

        fc.write(ByteBuffer.wrap("Some text ".getBytes()));

        fc.close();

        // Add to the end of the file:

        fc = new RandomAccessFile("data.txt", "rw").getChannel();

        fc.position(fc.size()); // Move to the end

        fc.write(ByteBuffer.wrap("Some more".getBytes()));

        fc.close();

        // Read the file:

        fc = new FileInputStream("data.txt").getChannel();

        ByteBuffer buff = ByteBuffer.allocate(4096);

        fc.read(buff);

        buff.flip();

        while(buff.hasRemaining())

          System.out.print((char)buff.get()); 

           用wrap( )方法把一个已经拿到手的byte数组"包"到ByteBuffer。如果是用这种方法,新创建的ByteBuffer是不会去拷贝底层的(byte)数组的,相反它直接用那个byte数组来当自己的存储空间。所以我们说ByteBuffer的"后台"是数组。

           从buffer中取数据前,要调用buffer的flip()。往buffer中装数据前,要调用buffer的clear()。

           FileChannel

          in = new FileInputStream(args[0]).getChannel(),

          out = new FileOutputStream(args[1]).getChannel();

        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);

        while(in.read(buffer) != -1) {

          buffer.flip(); // Prepare for writing

          out.write(buffer);

          buffer.clear();  // Prepare for reading

        }

     

           View Buffers

          

           View Buffer能让你从特殊的视角,来观察其底层的ByteBuffer。对view的任何操作都会作用到ByteBuffer上。同一个ByteBuffer,能读出不同的数据。ByteBuffer以1字节区分数据,CharBuffer是2字节,IntBuffer,FloatBuffer是4字节,LongBuffer和DoubleBuffer是8字节。

           ByteBuffer bb = ByteBuffer.wrap(new byte[]{ 0, 0, 0, 0, 0, 0, 0, 'a' });

        bb.rewind();

        System.out.println("Byte Buffer");

        while(bb.hasRemaining())

          System.out.println(bb.position()+ " -> " + bb.get());

        CharBuffer cb = ((ByteBuffer)bb.rewind()).asCharBuffer();

        System.out.println("Char Buffer");

        while(cb.hasRemaining())

          System.out.println(cb.position()+ " -> " + cb.get());

        FloatBuffer fb = ((ByteBuffer)bb.rewind()).asFloatBuffer();

        System.out.println("Float Buffer");

        while(fb.hasRemaining())

          System.out.println(fb.position()+ " -> " + fb.get());

        IntBuffer ib = ((ByteBuffer)bb.rewind()).asIntBuffer();

        System.out.println("Int Buffer");

        while(ib.hasRemaining())

          System.out.println(ib.position()+ " -> " + ib.get());

         

        Buffer的细节

        如果使用相对定位的get()和put()方法,buffer的position会跟着变化。也可以用下标参数调用绝对定位的get()和put()方法,这时它不会改动buffer的position。

        mark()方法会记录当前position,reset()会把position设置到mark的位置。rewind()把position设置到buffer的开头,mark被擦掉了。flip()把limit设为position,把position设为零。当你将数据写入buffer,准备读取的时候,必须先调用这个方法。

       

           内存映射文件

           memory-mapped file能让你创建和修改那些大到无法读入内存的文件(最大2GB)。

           int length = 0x8FFFFFF; // 128 Mb

           MappedByteBuffer out = new RandomAccessFile("test.dat","rw").getChannel().map(FileChannel.MapMode.READ_WRITE,0,length);

           for(int i = 0; i < length; i++)

                  out.put((byte)'x');

           for(int i = length/2;i<length/2+6;i++)

                  System.out.print((char)out.get(i));

           MappedByteBuffer是ByteBuffer的派生类。例程创建了一个128MB的文件,文件的访问好像只是一瞬间的事,这是因为,真正调入内存的只是其中的一小部分,其余部分则被放在交换文件上。Java是调用操作系统的"文件映射机制(file-mapping facility)"来提升性能的。只有RandomAccessFile才能写映射文件。

          

           文件锁

           Java的文件锁是直接映射操作系统的锁机制的,因此其它进程也能看到文件锁。

           FileOutputStream fos= new FileOutputStream("file.txt");

        FileLock fl = fos.getChannel().tryLock();

        if(fl != null) {

          System.out.println("Locked File");

          Thread.sleep(100);

          fl.release();

          System.out.println("Released Lock");

        }

        fos.close();

        tryLock( ) 是非阻塞的。它会试着去获取这个锁,但是如果得不到(其它进程已经以独占方式得到这个锁了),那它就直接返回。而lock( )是阻塞的。如果得不到锁,它会在一直处于阻塞状态,除非它得到了锁,或者你打断了调用它(即lock( )方法)的线程,或者关闭了它要lock( )的channel,否则它是不会返回的。最后用FileLock.release( )释放锁。

        还可以像这样锁住文件的某一部分,

    tryLock(long position, long size, boolean shared)

           或者

    lock(long position, long size, boolean shared)

    这个方法能锁住文件的某个区域(size - position)。其中第三个参数表示锁能不能共享。

           对于带参数的lock( )和tryLock( )方法,如果你锁住了position到position+size这段范围,而文件的长度又增加了,那么position+size后面是不加锁的。而无参数的lock方法则会锁定整个文件,不管它变不变长。

     

           8.压缩

           Java I/O类库还收录了一些能读写压缩格式流的类,它们是InputStream和OutputStream的派生类。这是因为压缩算法是针对byte而不是字符的。

           GZIP的接口比较简单,因此如果你只有一个流要压缩的话,用它会比较合适。

           BufferedReader in = new BufferedReader(new FileReader(args[0]));

        BufferedOutputStream out = new BufferedOutputStream(

          new GZIPOutputStream(new FileOutputStream("test.gz")));

        System.out.println("Writing file");

        int c;

        while((c = in.read()) != -1)

          out.write(c);

        in.close();

        out.close();

        System.out.println("Reading file");

        BufferedReader in2 = new BufferedReader(

          new InputStreamReader(new GZIPInputStream(new FileInputStream("test.gz"))));

        String s;

        while((s = in2.readLine()) != null)

          System.out.println(s);

           只要用GZIPOutputStream 或ZipOutputStream把输出流包起来,再用GZIPInputStream 或ZipInputStream把输入流包起来就行了。

          

           用Zip存储多个文件

           FileOutputStream f = new FileOutputStream("test.zip");

        CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());

        ZipOutputStream zos = new ZipOutputStream(csum);

        BufferedOutputStream out = new BufferedOutputStream(zos);

        zos.setComment("A test of Java Zipping");

        // No corresponding getComment(), though.

        for(int i = 0; i < args.length; i++) {

          System.out.println("Writing file " + args[i]);

          BufferedReader in = new BufferedReader(new FileReader(args[i]));

          zos.putNextEntry(new ZipEntry(args[i]));

          int c;

          while((c = in.read()) != -1)

            out.write(c);

          in.close();

        }

        out.close();

        // Checksum valid only after the file has been closed!

        System.out.println("Checksum: " + csum.getChecksum().getValue());

        // Now extract the files:

        System.out.println("Reading file");

        FileInputStream fi = new FileInputStream("test.zip");

        CheckedInputStream csumi = new CheckedInputStream(fi, new Adler32());

        ZipInputStream in2 = new ZipInputStream(csumi);

        BufferedInputStream bis = new BufferedInputStream(in2);

        ZipEntry ze;

        while((ze = in2.getNextEntry()) != null) {

          System.out.println("Reading file " + ze);

          int x;

          while((x = bis.read()) != -1)

            System.out.write(x);

        }

        System.out.println("Checksum: " + csumi.getChecksum().getValue());

        bis.close();

        // Alternative way to open and read zip files:

        ZipFile zf = new ZipFile("test.zip");

        Enumeration e = zf.entries();

        while(e.hasMoreElements()) {

          ZipEntry ze2 = (ZipEntry)e.nextElement();

          System.out.println("File: " + ze2);

          // ... and extract the data as before

        }

           虽然标准的Zip格式是支持口令的,但是Java的Zip类库却不支持。

          

           Java ARchives (JARs)

           一个JAR只有一个文件,包含两个文件,一个是Zip文件,另一个是描述Zip文件所包含的文件的"manifest(清单)"。

           如果JAR是用0(零)选项创建的,不会进行压缩,那么它就能被列入CLASSPATH了。

           不能往已经做好的JAR里添加新文件或修改文件。不能在往JAR里移文件的同时把原来的文件给删了。不过JAR格式是跨平台的,无论JAR是在哪个平台上创建的,jar程序都能将它读出来(zip格式有时就会有问题了)。

     

           9.对象的序列化

           Java的"对象序列化"能让你将一个实现了Serializable接口的对象转换成一组byte,需要的时候,根据byte数据重新构建那个对象。这一点甚至在跨网络的环境下也是如此,序列化机制能自动补偿操作系统方面的差异。

           对象序列化不仅能保存对象的副本,而且还会跟着对象里面的reference,把它所引用的对象也保存起来,然后再继续跟踪那些对象的reference,以此类推。这种情形常被称为"单个对象所联结的'对象网'"。这个机制所涵盖的范围不仅包括对象的成员数据,而且还包含数组里面的reference。

           Worm w = new Worm(6, 'a');

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));

        out.writeObject("Worm storage\n");

        out.writeObject(w);

        out.close(); // Also flushes output

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));

        String s = (String)in.readObject();

        Worm w2 = (Worm)in.readObject();

     

           把对象从序列化状态中恢复出来的必要条件是,一定要让JVM找到.class文件。

          

           控制序列化

           可以让对象去实现Externalizable而不是Serializable接口,并以此来控制序列化的过程。

           对于Externalizable对象,readExternal( )要在默认的构造行为会发生之后(包括在定义数据成员时进行的初始化)才启动。

           不但要在writeExternal( )的时候把重要的数据保存起来(默认情况下,Externalizable对象不会保存任何成员对象),还得在readExternal( )的时候把它们恢复出来。为了能正确地存取其父类的组件,你还得调用其父类的writeExternal( )和readExternal( )。

          

           transient关键词

           要想禁止敏感信息的序列化,除了可以实现Externalizable外。还可以使用transient关键词修饰Serializable对象中不想序列化的成员。

           默认情况下,Externalizable对象不保存任何字段,因此transient只能用于Serializable对象。

          

           Externalizable的替代方案

           如果你不喜欢Externalizable,还可以选择Serializable接口,然后再加入(注意,我没说"覆写"或"实现")序列化和恢复的时候会自动调用的writeObject( )和readObject( )方法。也就是说,如果你写了这两个方法,Java就会避开默认的序列化机制而去调用这两个方法了。

           两个方法的特征签名如下,(它们都是private的,怪异):

    private void writeObject(ObjectOutputStream stream) throws IOException;

    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException

           如果你决定用默认的序列化机制来存储非transient的数据,你就得在writeObject( )里面调用defaultWriteObject( ),不带参数,而且得第一个做。恢复的时候,也要在readObject( )的开头部分调用defaultReadObject( )。

           如果你要序列化static数据,就必须亲自动手。

          

           Preferences

           JDK 1.4所引入的Preferences API能自动存储和恢复信息。但是,它只能存取很少几种数据——primitive和String,而且每个String的长度都不能超过8K。

           Preferences是一组存储在"由节点所组成的层次体系(a hierarchy of nodes)"里的键值集(很像Map)。Preferences API是借用操作系统的资源来实现功能的。对于Windows,它就放在注册表里。

           //也可以用systemNodeForPackage( )

           //"user"指的是单个用户的preference,而"system"指整个系统的共用配置

           //一般用XXX.class做节点的标识符

           Preferences prefs = Preferences.userNodeForPackage(PreferencesDemo.class);

        prefs.put("Location", "Oz");

        prefs.putInt("Companions", 4);

        prefs.putBoolean("Are there witches?", true);

       

        10.正则表达式

        正则表达式是JDK 1.4的新功能。由java.util.regex的Pattern和Matcher类实现的。

        Pattern p = Pattern.compile(("\\w+");

           Matcher m = p.matcher(args[0]);

           while(m.find()) {

             System.out.println("Match \"" + m.group() +

               "\" at positions " +

               m.start() + "-" + (m.end() - 1));

           }

        只要字符串里有这个模式,find( )就能把它给找出来,但是matches( )成功的前提是正则表达式与字符串完全匹配,而lookingAt( )成功的前提是,字符串的开始部分与正则表达式相匹配。

          

           split()

           所谓分割是指将以正则表达式为界,将字符串分割成String数组。

           String[] split(CharSequence charseq)

           String[] split(CharSequence charseq, int limit)//限定分割的次数

           String input = "This!!unusual use!!of exclamation!!points";

        System.out.println(Arrays.asList(Pattern.compile("!!").split(input)));

     

     

    ===========

    Chap13   并发编程

     

           1.基本线程

           要想创建线程,最简单的办法就是继承java.lang.Thread。run( )是Thread最重要的方法,什么时候run( )返回了,线程也就中止了。

           Thread的start( )方法会先对线程做一些初始化,再调用run( )。

           整个步骤应该是:调用构造函数创建一个Thread对象,并且在构造函数里面调用start( )来配置这个线程,然后让线程的执行机制去调用run( )。如果你不调用start( ),那么线程永远也不会启动。

           有时我们创建了Thread,但是却没去拿它的reference。如果是普通对象,这一点就足以让它成为垃圾,但Thread不会。Thread都会为它自己"注册",所以实际上reference还保留在某个地方。除非run( )退出,线程中止,否则垃圾回收器不能动它。

           线程的调度机制是非决定性,即多个线程的执行顺序是不确定的。

          

           yielding

           如果知道run()已经告一段落了,你就可以用yield( )形式给线程调度机制作一个暗示。Java的线程调度机制是抢占式的(preemptive),只要它认为有必要,它会随时中断当前线程(运行到yield之前),并且切换到其它线程。总之,yield( )只会在很少的情况下起作用。

          

           Sleeping

           sleep( )一定要放在try域里,这是因为有可能会出现时间没到sleep( )就被中断的情况。如果有人拿到了线程的reference,并且调用了它的interrupt( ),这种事就发生了。(interrupt( )也会影响处于wait( )或join( )状态的线程,所以这两个方法也要放在try域里。)如果你准备用interrupt( )唤醒线程,那最好是用wait( )而不是sleep( ),因为这两者的catch语句是不一样的。

          

           优先级

           线程往控制台打印的时候是不会被中断的,否则控制台的显示就乱了。

          

           守护线程

           所谓"守护线程(daemon thread)"是指,只要程序还在运行,它就应该在后台提供某种公共服务的线程,但是守护线程不属于程序的核心部分。因此,当所有非守护线程都运行结束的时候,程序也结束了。

           要想创建守护线程,必须在它启动之前就setDaemon(true)。守护线程所创建的线程也自动是守护线程。

          

           连接线程

           线程还能调用另一个线程的join( ),等那个线程结束之后再继续运行。如果线程调用了另一个线程t的t.join( ),那么在线程t结束之前(判断标准是,t.isAlive( )等于false),主叫线程会被挂起。

          

           另一种方式:Runable

           类可能已经继承了别的类,这时就需要实现Runable接口了。

           如果要在这个实现了Runable的类里做Thread对象才有的操作,必须用Thread.currentThread()获取其reference。

           除非迫不得已只能用Runnable,否则选Thread。

          

           2.共享有限的资源

           多线程环境的最本质的问题:永远也不会知道线程会在什么时候启动。

           我们不能从线程内部往外面抛异常,因为这只会中止线程而不是程序。

          

           资源访问的冲突

           Semaphore是一种用于线程间通信的标志对象。如果semaphore的值是零,则线程可以获得它所监视的资源,如果不是零,那么线程就必须等待。如果申请到了资源,线程会先对semaphore作递增,再使用这个资源。递增和递减是原子操作(atomic operation,也就是说不会被打断的操作),由此semaphore就防止两个线程同时使用同一项资源。

          

           解决共享资源的冲突

           一个特定的对象中的所有的synchronized方法都会共享一个锁,而这个锁能防止两个或两个以上线程同时读写一块共用内存。当你调用synchronized方法时,这个对象就被锁住了。在方法返回并且解锁之前,谁也不能调用同一个对象的其它synchronized方法。

           一定要记住:所有访问共享资源的方法都必须是synchronized的,否则程序肯定会出错。

           一个线程能多次获得对象的锁。比如,一个synchronized方法调用了另一个synchronized方法,而后者又调用了另一synchronized方法。线程每获一次对象的锁,计数器就加一。当然,只有第一次获得对象锁的线程才能多次获得锁。线程每退出一个synchronized方法,计数器就减一。等减到零了,对象也就解锁了。

           此外每个类还有一个锁(它属于类的Class对象),这样当类的synchronized static方法读取static数据的时候,就不会相互干扰了。

          

           原子操作

           通常所说的原子操作包括对非long和double型的primitive进行赋值,以及返回这两者之外的primitive。不过如果你在long或double前面加了volatile,那么它就肯定是原子操作了。最安全的原子操作只有读取和对primitive赋值这两种。

           如果你要用synchronized修饰类的一个方法,索性把所有的方法全都synchronize了。要判断,哪个方法该不该synchronize,通常是很难的,而且也没什么把握。

           并发编程的最高法则:绝对不能想当然。

          

           关键段

           有时你只需要防止多个线程同时访问方法中的某一部分,而不是整个方法。这种需要隔离的代码就被称为关键段(critical section)。创建关键段需要用到synchronized关键词,指明执行下列代码需获得哪个对象的锁。

    synchronized(syncObject) {

      // This code can be accessed by only one thread at a time

    }

           关键段又被称为"同步块(synchronized block)"。相比同步整个方法,同步一段代码能显著增加其它线程获得这个对象的机会。

          

           3.线程的状态

           线程的状态可归纳为以下四种:

           (1).new: 线程对象已经创建完毕,但尚未启动(start),因此还不能运行。

           (2).Runnable: 处在这种状态下的线程,只要分时机制分配给它CPU周期,它就能运行。

           (3).Dead: 要想中止线程,正常的做法是退出run( )。

           (4).Blocked: 就线程本身而言,它是可以运行的,但是有什么别的原因在阻止它运行。线程调度机制会直接跳过blocked的线程,根本不给它分配CPU的时间。除非它重新进入runnable状态,否则什么都干不了。

           如果线程被阻塞了,那肯定是出了什么问题。问题可能有以下几种:

           (1).你用sleep(milliseconds)方法叫线程休眠。在此期间,线程是不能运行的。

           (2).你用wait( )方法把线程挂了起来。除非收到notify( )或notifyAll( )消息,否则线程无法重新进入runnable状态。

           (3).线程在等I/O结束。

           (4).线程要调用另一个对象的synchronized方法,但是还没有得到对象的锁。

          

           4.线程间的协作

           wait与notify

           线程sleep( )的时候并不释放对象的锁,但是wait( )的时候却会释放对象的锁。也就是说在线程wait( )期间,别的线程可以调用它的synchronized方法。    此外,sleep( )属于Thread。wait( ), notify( ), 和notifyAll( )是根Object的方法。

           只能在synchronized方法里或synchronized段里调用wait( ),notify( )或notifyAll( )。

           wait( )能让你在等待条件改变的同时让线程休眠,当其他线程调用了对象的notify( )或notifyAll( )的时候,线程自会醒来,然后检查条件是不是改变了。

           安全的做法就是套用下面这个wait( )定式:

           while(conditionIsNotMet)

                  wait( );

                 

           用管道进行线程间的I/O操作

           在很多情况下,线程也可以利用I/O来进行通信。对Java I/O类库而言,就是PipedWriter(可以让线程往管道里写数据)和PipedReader(让另一个线程从这个管道里读数据)。

          

           5.死锁

           Dijkstra发现的经典的死锁场景:哲学家吃饭问题。

           只有在下述四个条件同时满足的情况下,死锁才会发生:

           (1).互斥:也许线程会用到很多资源,但其中至少要有一项是不能共享的(同一时刻只能被一个线程访问)。

           (2).至少要有一个进程会在占用一项资源的同时还在等另一项正被其它进程所占用的资源。也就是说,要想让死锁发生,哲学家必须攥着一根筷子等另一根。

           (3).(调度系统或其他进程)不能从进程里抢资源。所有进程都必须正常的释放资源。我们的哲学家都彬彬有礼,不会从他的邻座手里抢筷子。

           (4).需要有等待的环。一个进程在等一个已经被另一进程抢占了的资源,而那个进程又在等另一个被第三个进程抢占了的资源,以此类推,直到有个进程正在等被第一个进程抢占了的资源,这样就形成了瘫痪性的阻塞了。这里,由于每个哲学家都是先左后右的拿筷子,所以有可能会造成等待的环。在例程中,我们修改了最后一位哲学家的构造函数,让他先右后左地拿筷子,从而破解了死锁。

           Java语言没有提供任何能预防死锁的机制。

          

           6.停止线程的正确的方法

           为了降低死锁的发生几率,Java 2放弃了Thread类stop( ),suspend( )和resume( )方法。

           应该设置一个旗标(flag)来告诉线程什么时候该停止。

     

           7.打断受阻的线程

           有时线程受阻之后就不能再做轮询了,比如在等输入,这时你就不能像前面那样去查询旗标了。碰到这种情况,你可以用Thread.interrupt( )方法打断受阻的线程。最后要把受阻线程的 reference设成null。

          

           8.总结

           诺贝尔经济学奖得主Joseph Stiglitz有一条人生哲学,就是所谓的承诺升级理论:

    "延续错误的代价是别人付的,但是承认错误的代价是由你付的。"

           多线程的主要缺点包括:

           (1).等待共享资源的时候,运行速度会慢下来。

           (2).线程管理需要额外的CPU开销。

           (3).如果设计得不不合理,程序会变得异常复杂。

           (4).会引发一些不正常的状态,像饥饿(starving),竞争(racing),死锁(deadlock),活锁(livelock)。

           (5).不同平台上会有一些不一致。

           通常你可以在run( )的主循环里插上yield( ),然后让线程调度机制帮你加快程序的运行。

     

     

    ==============

    Chap14 创建Windows与Applet程序

          

           设计中一条基本原则:让简单的事情变得容易,让困难的事情变得可行。

           软件工业界的“三次修订”规则:产品在修订三次后才会成熟。

          

           1.控制布局

           在Java中,组件放置在窗体上的方式可能与其他GUI系统都不相同。首先,它完全基于代码,没有用来控制组件布局的“资源”。第二,组件的位置不是通过绝对坐标控制,二十由“布局管理器”(layout manager)根据组件加入的顺序决定其位置。使用不同的布局管理器,组件的大小、形状和位置将大不相同。此外,布局管理器还可以适应applet或视窗的大小,调整组件的布局。

           JApplet,JFrame,JWindow和JDialog都可以通过getContentPane()得到一个容器(Container),用来包含和显示组件。容器有setLayout()方法,用来设置布局管理器。

          

           2.Swing事件模型

           在Swing的事件模型中,组件可以触发一个事件。每种事件的类型由单独的类表示。当事件被触发时,它将被一个或多个监听器接收,监听器负责处理事件。

           所谓事件监听器,就是一个“实现了某种类型的监听器接口的”类的对象。程序员要做的就是,先创建一个监听器对象,然后把它注册给触发事件的组件。注册动作是通过该组件的addXXXListener()方法完成的。

           所有Swing组件都具有addXXXListener()和removeXXXListener()方法。

     

           3.Swing组件一览

          

           工具提示ToolTip

           任何JComponent子类对象都可以调用setToolTipText(String)。

          

           Swing组件上的HTML

           任何能接受文本的组件都可以接受HTML文本,且能根据HTML格式化文本。例如,

           JButton b = new JButton("<html><b><font size=+2>Hello<br>Press me");

           必须以"<html>"标记开始,但不会强制添加结束标记。

           对于JApplet,在除init()之外的地方添加新组件后,必须调用容器的validate()来强制对组件进行重新布局,才能显示新添加的组件。

          

           4.选择外观(Look & Feel)

           “可插拔外观”(Pluggable Look & Feel)使你的程序能够模仿不同操作系统的外观。

           设置外观的代码要在创建任何可视组件之前调用。Swing的跨平台的金属外观是默认外观。

           try{

                  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

           } catch(Exception e){

           }

           catch子句中什么也不用做,因为缺省情况下,如果设置外观失败,UIManager将设置成跨平台的外观。

          

           动态绑定事件

           不能保证事件监听器被调用的顺序与它们被添加的顺序相同。

          

           5.Swing与并发

           始终存在着一个Swing事件调度线程,它用来依次对Swing的所有事件进行调度。

          

           管理并发

           当你在类的main()方法中,或在一个独立线程中,准备修改任何Swing组件属性的时候,要注意,Swing的事件调度线程可能会与你竞争同一资源。

           要解决这个问题,必须确保在任何情况下,只能在事件调度线程里修改Swing组件的属性。Swing提供了两种机制:SwingUtilities.invokeLater(Runnable)和SwingUtilities.invokeAndWait(Runnable)。它们都接受runnable对象作参数,并且在Swing的事件处理线程中,只有当事件队列中的任何未处理的事件都被处理完毕之后,它们才会调用runnable对象的run()方法。

           SwingUtilities.invokeLater(new Runnable(){

                  public void run(){

                         txt.setText("ready");

                  }

           });

           invokeLater()是异步方法,会立即返回。invokeAndWait()是同步方法,会一直阻塞,直到事件处理完毕才会放回。

          

           6.JavaBean与同步

           当你创建Bean的时候,你必须要假设它可能会在多线程环境下运行。也就是说:

           (1).尽可能让Beand中的所有公共方法都是synchronized。这将导致synchronized的运行时开销。

           (2).当一个多路事件触发了一组对该事件感兴趣的监听器时,必须假定,在遍历列表进行通知的同时,监听器可能会被添加或移除。

           public void notifyListeners(){

                  ActionEvent a = new ActionEvent(BangBean2.this, ActionEvent.ACTION_PERFORMED, null);

                  ArrayList lv = null;

                  //Make a shallow copy of the List in case someone adds a listener while we're

                  //calling listeners

                  synchronized(this){

                         lv = (ArrayList)actinListeners.clone();

                  }

                  for(int i = 0; i < lv.size(); i++){

                         ((ActionListener)lv.get(i)).actionPerformed(a);

                  }

           }

          

          

          

          

     

    ==============

    Chap15 发现问题

     

           1.单元测试

           //Discover the name of the class this object was created within:

           className = new Throwable().getStackTrace()[1].getClassName();

          

           JUnit

           JUnit在输出消息中使用"."表示每个测试的开始。

           JUnit为每个测试创建一个测试对象(继承自TestCase),以确保在测试运行之间没有不利的影响。所有的测试对象都是同时被创建的,而不是正好在测试方法执行之前才创建。

           setUp是在每个测试方法运行之前被调用的。

          

           2.利用断言提高可靠性

           断言语法

           assert boolean-expression;

           assert boolean-expression: information-expression;

          

           在JDK 1.4中,缺省情况下断言是关闭的。为了防止编译时的错误,必须带下面的标志进行编译:

           -source 1.4

           如:javac -source 1.4 Assert1.java

          

           运行程序也必须加上标志-ea,全拼是-enableassertions。这样才会执行所有的断言语句。

          

           我们也可以基于类名或包名来决定打开或关闭断言。

           还有另一种动态控制断言的方法:通过ClassLoader对象的方法setDefaultAssertionStatus(),它为所有随后载入的类设置断言的状态。

           public static void main(String[] args){

                  ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);

                  //other statements

           }

           这样可以在运行时,不必使用-ea标志,但是仍然必须使用-source 1.4标志编译。

          

           为DBC使用断言

          

           DBC(Design by Contract)是由Bertrand Meyer(Eiffel编程语言的创建者)所阐明的一个概念,它通过确保对象遵循特定的、不能被编译时的类型检查所验证的规则,来帮助建立健壮的程序。

          

           3.剖析和优化

           “我们应该忽略较小的效率,在97%的时间里我们都应该说:不成熟的优化是万恶之源。”--Donald Knuth

          

           最优化指南

           避免为性能而牺牲代码的可读性。

           不能孤立地考虑性能。要权衡所需付出的努力与能得到的利益之间的关系。

           性能是大型工程要关心的问题,但通常不是小型工程要考虑的。

           使程序可运转比钻研程序的性能有更高的优先权。仅当性能被确定是一个关键因素的时候,在初始设计开发过程期间才应该予以考虑。

           不要假设瓶颈在什么地方,而应该运行剖析器来获得数据。

           在任何可能的情况下,尽量通过将对象设置为null,从而显式地将其销毁。有时这可能是对垃圾回收器的一种很有帮助的提示。

           程序大小的问题。仅当程序是大型的、运行时间长而且速度也是一个问题时,性能优化才有价值。

           static final变量可以通过JVM进行优化以提高程序的速度。

          

           做可以运转的最简单的事物。(极限编程)

          

     

     

    ================

    附录A:对象的传递与返回

     

           确切地说,Java有指针。Java中(除了基本类型)每个对象的标识符就是一个指针。但是它们受到了限制,有编译器和运行期系统监视着它们。Java有指针,但没有指针的相关算法。可以将它们看作“安全的指针”。

           “别名效应”是指,多个引用指向同一个对象。将引用作为方法的参数传递时,它会自动被别名化。

          

           制作局部拷贝

           Java中所有的参数传递,执行的都是引用传递。当你传递对象时,真正传递的只是一个引用,指向存活于方法外的“对象”。对此引用做的任何修改,都是在修改方法外的对象。此外:

           (1).别名效应在参数传递时自动发生。

           (2).方法内没有局部对象,只有局部引用。

           (3).引用有作用域,对象则没有。

           (4).在Java中,不需要为对象的生命周期操心。

           (5).没有提供语言级别的支持(例如“常量”)以阻止对象被修改,或者消除别名效应的负面影响。不能简单地使用final关键字来修饰参数,它只能阻止你将当前引用指向其他对象。

          

           克隆对象

           如果确实要在方法调用中修改参数,但又不希望修改外部参数,那么就应该在方法内部制作一份参数的副本,以保护原参数。

           Object类提供了protected方法clone(),要使用它,必须在子类中以public方式重载此方法。例如,ArrayList就重载了clone()。ArrayList的clone()方法,并不自动克隆容器中包含的每个对象,只是将原ArrayList中的对象别名化,即只复制了ArrayList中对象的引用。这称为浅拷贝(shallow copy)。

          

           使类具有克隆能力

           虽然在所有类的基类Object中定义了克隆方法,但也不是每个类都自动具有克隆能力。

           克隆对象时有两个关键问题:

           (1).调用super.clone()

           (2).将子类的clone()方法声明为public

           基类的clone()方法,能“逐位复制(bitwise copy)”对象。

          

           实现Cloneable接口

           interface Cloneable{}

           这样的空接口称为“标记接口(tagging interface)”。

           Cloneable接口的存在有两个理由。第一,如果某个引用上传为基类后,就不知道它是否能克隆。此时,可以用instanceof检查该引用是否指向一个可克隆的对象。

           if(myref instanceof Cloneable)//...

           第二,与克隆能力的设计有关,考虑到也许你不愿意所有类型的对象都是可克隆的。所以Object.clone()会检查当前类是否实现了Cloneable接口,如果没有,就抛出CloneNotSupportedException异常。所以,作为实现克隆能力的一部分,通常必须实现Cloneable接口。

          

           ==与!=

           Java比较对象相等的等价测试并未深入对象的内部。==和!=只是简单地比较引用。如果引用代表的内存地址相同,则它们指向同一个对象,因此视为相等。所以,该操作符测试的是:不同的引用是否是同一个对象的别名。

          

           Object.clone()的效果

           克隆过程的第一步通常都是调用super.clone()。它制作出完全相同的副本,为克隆操作建立了基础。在此基础上,你可以执行对完成克隆必要的其他操作。

           这里的其他操作是指,对对象中的每个引用,都明确地调用clone()。否则,那些引用会被别名化,仍指向原本的对象。

           只要没有向子类中添加需要克隆的引用,那么无论clone()定义于继承层次中多深的位置,只需要调用Object.clone()一次,就能完成所有必要的复制。

           对ArrayList深层拷贝而言,以下操作是必须的:克隆ArrayList之后,必须遍历ArrayList中的每个对象,逐一克隆。对HashMap做深层拷贝,也必须做类似的操作。

          

           向继承体系的更下层增加克隆能力

           可以向任意层次的子类添加克隆能力,从那层以下的子类,也就都具备了克隆能力。

          

           克隆小结

           如果希望一个类可以被克隆:

           (1).实现Cloneable接口。

           (2).重载clone(),声明为public。

           (3).在clone()中调用Super.clone()。

           (4).在clone()中捕获异常。

          

           只读类

           在只读类中所有数据都是private的,并且没有定义会修改对象内部状态的方法。只读类的对象可以有很多别名,也不会造成伤害。例如,Java标准类库中所有基本类型的包装类。

          

           恒常性(immutability)的缺点

           当你需要一个被修改过的此类的对象的时候,必须承受创建新对象的开销,也会更频繁地引发垃圾回收。对于有些类(如String),其代价让人不得不禁止这么做。

           解决之道是创建一个可被修改的伴随类(companion class)。

          

     

    =============

    附录B:Java编程指南

     

           设计

           1.优雅设计终将得到回报。精心设计程序的时候生产率不会很高,但欲速则不达。

           2.先能运行,再求快速。

           3.分而治之。

           4.尽量让所有东西自动化。(如测试和构建,先写测试,再编写类)

           5.尽可能使类原子化。

           建议重新设计类的线索有:

           (1).复杂的switch语句,请考虑使用多态。

           (2).有许多方法,处理类型极为不同的操作:请考虑划分成不同的类。

           (3).有许多成员变量,表示类型极为不同的属性:请考虑划分成不同的类。

           (4).参考《Refactoring:Improving the Design of Existing Code》,Martin Fowler著,(Addison-Wesley 1999)。

           6.将变动的和不变的因素分离。

           7.在判断应该使用继承还是组合的时候,考虑是否需要上传为基类。

          

           实现

           1.编写通用性的类时,请遵守标准形式。包括定义equals()、hashCode()、toString()、clone()(实现Cloneable接口,或者选择其它对象复制策略),并实现Comparable和Serialiable接口。

           2.在构造器中只做必要的动作:将对象设定为正确的状态。避免在构造器内调用其它方法(final方法除外),因为这些方法可能会被其他人重载,这就可能在构造期间得到意外的结果。

           3.优先选择接口而不是抽象类。只有在必须放进方法定义或成员变量时,才把它改为抽象类。接口只和客户希望的动作有关,而类则倾向于实现细节。
     

    posted @ 2006-12-11 16:29 重归本垒(Bing) 阅读(887) | 评论 (0)编辑 收藏
     
    Web Page Rank Icon