Archive for the ‘Java’ Category

开始使用 TOAD EXTENSION 在 ECLIPSE (用于管理Oracle的插件)

用于管理Oracle的插件

To install Toad Extension for Eclipse:

  1. Open Eclipse.
  2. Select HelpInstall New Software.
  3. In the Install dialog, Work with box, enter the following website address:
    http://toaddownload.quest.com/toadextensions/eclipse/freeware/

To display the installed Toad Extension for Eclipse in Eclipse:

  1. Select WindowOpen PerspectiveOther.
  2. From the Open Perspective dialog select Toad Extension.

Important: If you don’t have Oracle Client installed on your machine or if you use operating system other than officially supported then you may need to download ojdbc driver from Oracle site. Toad Extension for Eclipse distribution packages do not contain any ojdbc driver.

DIRECT DOWNLOAD LINK

If you want to install Toad Extension for Eclipse freeware version manually, download ZIP package from the following location:http://toaddownload.quest.com/toadextensions/eclipse/ToadExtensionsForEclipse_freeware_1.1.1.zip

INTERFACE LAYOUT

Toad Extension for Eclipse

PRODUCT VIDEOS

See our short Flash movies and find out how to create new Toad Extension project or how to use some standard Eclipse features – e.g. how to edit XML, how to use Local History and more. Visit our Product Videossection.

 

Java程序员ActionScript 3入门

作者 Jack Herrington 译者 张凯峰

我们还是勇敢面对吧:客户端对于Java程序员来说,一直都不是个友好的地方。Java在客户端的技术,包括applet、Swing和JavaFX到目前为止只取得了有限的成绩。JavaScript除了它的名字外,几乎没有什么地方像Java语言。而Adobe Flash呢,它看起来的确像JavaScript,真的吗?也许在几年前说Flash就像JavaScript一样是可以理解的,但随着 ActionScript 3的出现,一切都改变了。而且我相信你会喜欢它的很多东西。

首先,ActionScript这门针对Adobe Flex和Flash的编程语言,现在是强类型的了。它也是一流的面向对象语言,包括有类和接口。它还拥有你在Java中找不到的东西——特别地,它包含属性的getset方法,以及一个叫做ECMAScript for XML(E4X)的语言扩展,可以将任何XML文档转换成对象,这样你就可以通过“.”操作符直接引用它们,就跟普通对象一样。

这篇文章会引领你浏览ActionScript的基础内容,以及展示它与你所熟悉的Java环境的不同。到最后,你就会放弃你对 ActionScript 的任何偏见,并开始有兴趣把玩它。关于Flex、Flash和ActionScript的最伟大的事情之一就是它们完全是免费的。只要下载了Adobe Flex Builder 3就可以开始了。Flex Builder是一个复杂的集成开发环境(IDE),而且不是免费的,但它用于构建Flash应用的Flex软件开发工具包(SDK)是完全免费的。

对阅读本文章的语言发烧友的一句忠告是:我并不是个语言教师,因此我可能忽略掉一些语言的细节。我也不会在这篇文章中演示ActionScript 3的所有内容。如果你的确需要这方面的内容,有很多非常棒的ActionScript 3的书籍。我能给予你的就是你对这门语言的初次的感觉。让我们开始吧。

类和接口

就和Java一样,在ActionScript 3中一切皆是对象。虽然有一些基本类型,比如integer,但除了这些,一切皆是对象。类似地,就像Java一样,ActionScript也有命名空间和包,比如com.jherrington.animals,其表示了company/jack herrington/animal下的类。你可以把类放到缺省的命名空间,但更好的方法是由你自己来控制自己的命名空间。

要定义一个类,你要使用class关键字,这也跟Java一样。请看示例:

package com.jherrington.animals
 {
 	public class Animal
 	{
 		public function Animal()
 		{
 		}
 	}
 }

在这个例子中,我定义了一个Animal类,以及什么也没干的构造函数。我还可以很容易地添加一些成员变量并完善这个构造函数,请看示例:

package com.jherrington.animals
 {
 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}
 	}
 }

这里,我给一个Animal对象定义了两个成员变量:name,一个公有的字符串,以及age,一个私有的整数。(很明显,小动物们对于它们的年龄都很害羞。:) )构造函数可以接受一个或两个参数:要么是单独的name,要么name和age。你也可以在函数声明中为参数提供缺省的值。

你会注意到这里的类型定义是跟Java相反的。在Java中,类型在变量之前;而在ActionScript中,类型在变量之后。这是因为强类型定义是追加到ActionScript上的。所以为了支持旧的、没有定义类型的代码,类型就需要放在变量名的后面。

让我添加一些方法来扩展这个示例:

package com.jherrington.animals
 {
 	import flash.geom.Point;

 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var location:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}

 		public function moveTo( x:int, y:int ) : void {
 			location.x = x;
 			location.y = y;
 		}

 		public function getLocation( ) : Point {
 			return location;
 		}
 	}
 }

正如你所看到的,我又添加了一个私有成员变量location,类型是我从Flash的geometry包中引入的Point类型。而且我还添加了两个方法来操作location:moveTo,用来移动animalgetLocation,用来返回当前的位置。

到目前为止,这还是以Java的方式去get和set一个值。但ActionScript方式会清晰很多,请看示例:

package com.jherrington.animals
{
 	import flash.geom.Point;

 	public class Animal
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var myLocation:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )
 		{
 			name = _name;
 			age = _age;
 		}

 		public function set location( pt:Point ) : void {
 			myLocation = pt;
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}
 	}
 }

这里我使用getset函数,它们会在客户代码获取或设置成员变量location时被调用。对于客户代码来说,location变量看起来就像是个普通的成员变量。但事实上,你可以用你喜欢的任何代码来响应成员变量的设值,以及处理变量的获取。

如何来使用它呢?你可以添加一个事件,这个事件会在location发生改变时被触发。请看示例代码:

package com.jherrington.animals
{
  	import flash.events.Event;
 	import flash.events.EventDispatcher;
 	import flash.geom.Point;

 	public class Animal extends EventDispatcher
 	{
 		public var name:String = "";

 		private var age:int = 0;

 		private var myLocation:Point = new Point(0,0);

 		public function Animal( _name:String, _age:int = 30 )

 			name = _name;
 			age = _age;
 		}

 		public function set location ( pt:Point ) : void {
 			myLocation = pt;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}
 	}
 }

现在,我指定Animal类是一个事件分发者——也就是说,客户代码可以从这个对象监听到事件发生。接着,当location改变时,我发出了一个新的事件。

下面就是客户代码,它创建了一个animal对象,并开始监听事件是否发生,然后就改变了animallocation

	var a:Animal = new Animal();
 	a.addEventListener(Event.CHANGE, function( event:Event ) : void {
 		trace( "The animal has moved!" );
 	} );
 	a.location = new Point( 10, 20 );

这段代码在animal移动时会记录一条跟踪信息。在ActionScript中,你可以定义任何类型的消息。大多数的类都是EventDispatcher类,你可以为它们的事件添加监听器。

接口

就像Java一样,ActionScript 3语言也支持接口,并使用类来实现它们。下面的示例中,就是一个我们可以用Animal类来实现的接口:

package com.jherrington.animals
 {
 	import flash.geom.Point;

 	public interface IAnimal
 	{
 		function get name() : String;
 		function set name( n:String ) : void;

 		function get location() : Point;
 		function set location( pt:Point ) : void;
 	}
 }

在这个例子中,我为接口定义了两个可以set和get的成员变量。没错,你可以在ActionScript接口中定义方法和成员变量。是不是很酷?

为了实现这个接口,我对Animal类做了一点修改。请看示例:

package com.jherrington.animals
 {
 	import flash.events.Event;
 	import flash.events.EventDispatcher;
 	import flash.geom.Point;

 	public class Animal extends EventDispatcher implements IAnimal
 	{
 		private var myName:String = "";

 		public function get name() : String
 		{
 			return myName;
 		}
 		public function set name( n:String ) : void
 		{
 			myName = n;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}
 		private var myLocation:Point = new Point(0,0);

 		public function set location ( pt:Point ) : void {
 			myLocation = pt;
 			dispatchEvent( new Event( Event.CHANGE ) );
 		}

 		public function get location( ) : Point {
 			return myLocation;
 		}

 		public function Animal( _name:String )
 		{
 			name = _name;
 		}
 	}
 }

当然,我也可以为这个类添加特定的变量和方法,或者实现除了IAnimal接口之外的其他接口。但是和Java一样,我只能继承一个基类。

静态和常量

ActionScript 3支持常量和静态成员变量,以及静态方法。常量定义起来很方便,请看示例:

		public const MINIMUM_AGE:int = 0;
  		public const MAXIMUM_AGE:int = 2000;

常量可以是你期望的任何类型,但它们必须是在编译时定义。如果你愿意,你也可以把它们定义成受保护的或者是私有的作用域。

为了演示一下静态方法,我在Animal类中写了一个工厂方法:

		public static function buildAnimal( n:String ) : IAnimal {
 			return new Animal( n );
 		}

使用静态方法的另外一种方式是单例模式。下面就是一个针对Animal类的单例工厂类:

package com.jherrington.animals
 {
 	public class AnimalFactory
 	{
 		private static var _factory:AnimalFactory = new AnimalFactory();

 		public static function get instance() : AnimalFactory {
 			return _factory;
 		}

 		public function build( n:String ) : Animal {
 			return new Animal( n );
 		}
 	}
 }

我使用该单例工厂的instance成员变量来获得其对象,并调用它:

private var b:Animal = AnimalFactory.instance.build( "Russell" );

这句代码使用单例工厂对象创建了一个新的名叫Russell的animal对象。

继承

为了演示继承,我写了三个接口和类。第一个是之前的IAnimal接口,第二个是Animal类,第三个是名叫Dog的继承类,它覆写了一个方法。

接口IAnimal定义如下:

	public interface IAnimal
 	{
 		function get name() : String;
 		function set name( n:String ) : void;

 		function move( x:int, y:int ) : void;
 	}

我对它进行了简化,这样它只有一个name成员变量和一个move()方法。第一个实现这个接口的是Animal类:

public class Animal extends EventDispatcher implements IAnimal
 {
 	private var myName:String = "";

 	public function get name() : String
 	{
 		return myName;
 	}
 	public function set name( n:String ) : void
 	{
 		myName = n;
 		dispatchEvent( new Event( Event.CHANGE ) );
 	}

 	public function Animal( _name:String )
 	{
 		name = _name;
 	}

 	public virtual  function move( x:int, y:int ) : void
 	{
 	}
 }

然后,Dog类在Animal类的基础上构建起来,它具有自己的构造函数,并覆写了move()方法:

public class Dog extends Animal
 {
 	public function Dog(_name:String)
 	{
 		super(_name);
 	}

 	public override function move( x:int, y:int ) : void
 	{
 		trace( 'Moving to '+x+', '+y );
 	}
 }

这看起来非常像Java代码,所以你会感觉到用ActionScript来实现自己的面向对象设计会非常轻松。

操作符和条件语句

ActionScript中的操作符和你在Java中看到的完全一样。类似地,算术和布尔操作符也是一样的:

	var a:int = 5;
 	var b:int = 6;
 	var c:int = a * b;
 	c *= 10;
 	var d:Boolean = ( c > 10 );
 	var e:int = d ? 10 : 20;

这些实例演示了一些不同的操作符。在这些示例中,ActionScript和Java的唯一不同在于定义变量的语法不一样。

跟操作符一样,条件语句也是完全一样的,请看示例:

	if ( a > 10 ) {
 		trace( 'low' );
 	}
 	else if ( a > 20 ) {
 		trace( 'high' );
 	}
 	else {
 		threw new Exception( "Strange value" );
 	}

这里演示了条件语句的语法,以及如何抛出异常。异常处理和Java中的完全一样。你可以定义自己的异常类型,或者直接使用标准的Exception类。

下面是trycatchfinally语法的使用:

	try
 	{
 		location = new Point( -10, 10 );
 	}
 	catch( Exception e )
 	{
 		trace( e.toString() );
 	}
 	finally
 	{
 		location = null;
 	}

这段代码试图设置location,并在错误发生时跟踪错误信息。不管哪种情况,最终,location都会被设为null

迭代

ActionScript 3没有强类型的容器类,但数组和哈希表使用起来还是非常容易的。这里是一个使用for循环来迭代一个数组的例子:

	var values:Array = new [ 1, 2, 5 ];
 	for( var i:int = 0; i < values.length; i++ )
 		trace( values[i] );

但这并不是你在ActionScript中迭代数组应该使用的方式。最好的方式是使用for each语法,请看示例:

	var values:Array = new [ 1, 2, 5 ];
 	for each ( var i:int in values )
 		trace( i );

这段代码迭代访问数组中的每个元素,并把i的值设置为每个元素的值。

要创建一个哈希表,你可以使用ActionScript中基本的Object类型:

	var params:Object = { first:'Jack', last:'Herrington' };
 	for( var key:String in params )
 		trace( key+' = '+params[key] );

ActionScript起源于JavaScript意味着基础对象类型是基于插槽(slots-based)的容器,这样你可以轻而易举地把它作为哈希表来使用。

正则表达式

正则表达式是ActionScript中的基础语法。比如下面这段代码:

	if ( name.search( /jack/i ) )
 	{
 		trace('hello jack');
 	}

是对一个字符串的简单检查。

这段代码是使用正则表达式来执行分割操作:

	var values:String = "1,2,3";
 	for each( var val:String in values.split(/,/) ) {
 		trace( val );
 	}

你是否应该把正则表达式嵌在自己的核心代码里面,是值得商榷的。Java的架构师们显然认为这些表达式应该留在一个外部的库中。但我认为,它们非常有用,所以它们应该像在ActionScript中这样被集成。

E4X

XML应用得很广泛,以至于ActionScript直接把它构建在语言的语法里面以示支持。如果你是个XML爱好者,你会非常喜欢这个的。请看示例:

var myData:XML = <names>
 	<name>Jack</name>
 	<name>Oso</name>
 	<name>Sadie</name>
 </names>;
 	for each ( var name:XML in myData..name ) {
 		trace( name.toString() );
 }

这段代码定义了一个XML文档,然后对它进行搜索并打印出所有的标签

下面这段代码也是获取<name> 标签,但只获取那些type是dog的标签。

var myData:XML = <names>
 	<name type="person">Jack</name>
 	<name type="dog">Oso</name>
 	<name type="dog">Sadie</name>
 </names>;
 	for each ( var name:XML in myData..name.(@type='dog') ) {
 		trace( name.toString() );
 }

@语法有点类似于XPath和XSLT。它用来指定我们要查看的是属性而不是XML元素本身。

E4X是对这门语言的梦幻增强。它把XML解析从繁琐变成了轻松愉快的事情。Web services甚至也可以以E4X的格式返回以便于解析。

总结

Adobe对于ActionScript做了一些非凡的改进。它是一门比人们想象的成熟得多的语言。我认为你会最终发现Adobe所做的,就是吸取了Java的得失教训,并把它们合并进ActionScript 3语言的开发中。你会很乐意看到最后的结果。

使用 CAS 在 Tomcat 中实现单点登录

CAS 介绍

CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。CAS 具有以下特点:

  • 开源的企业级单点登录解决方案。
  • CAS Server 为需要独立部署的 Web 应用。
  • CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。

CAS 原理和协议

从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。图1 是 CAS 最基本的协议过程:

图 1. CAS 基础协议
CAS 基础协议

CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。用户在第 3 步中输入认证信息,如果登录成功,CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket,并缓存以待将来验证,之后系统自动重定向到 Service 所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新产生的 Ticket 过后,在第 5,6 步中与 CAS Server 进行身份合适,以确保 Service Ticket 的合法性。

在该协议中,所有与 CAS 的交互均采用 SSL 协议,确保,ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的。

另外,CAS 协议中还提供了 Proxy (代理)模式,以适应更加高级、复杂的应用场景,具体介绍可以参考 CAS 官方网站上的相关文档。

准备工作

本文中的例子以 tomcat5.5 为例进行讲解,下载地址:

http://tomcat.apache.org/download-55.cgi

到 CAS 官方网站下载 CAS Server 和 Client,地址分别为:

http://www.ja-sig.org/downloads/cas/cas-server-3.1.1-release.zip

http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip


部署 CAS Server

CAS Server 是一套基于 Java 实现的服务,该服务以一个 Java Web Application 单独部署在与 servlet2.3 兼容的 Web 服务器上,另外,由于 Client 与 CAS Server 之间的交互采用 Https 协议,因此部署 CAS Server 的服务器还需要支持 SSL 协议。当 SSL 配置成功过后,像普通 Web 应用一样将 CAS Server 部署在服务器上就能正常运行了,不过,在真正使用之前,还需要扩展验证用户的接口。

在 Tomcat 上部署一个完整的 CAS Server 主要按照以下几个步骤:

配置 Tomcat 使用 Https 协议

如果希望 Tomcat 支持 Https,主要的工作是配置 SSL 协议,其配置过程和配置方法可以参考 Tomcat 的相关文档。不过在生成证书的过程中,会有需要用到主机名的地方,CAS 建议不要使用 IP 地址,而要使用机器名或域名。

部署 CAS Server

CAS Server 是一个 Web 应用包,将前面下载的 cas-server-3.1.1-release.zip 解开,把其中的 cas-server-webapp-3.1.1.war 拷贝到 tomcat的 webapps 目录,并更名为 cas.war。由于前面已配置好 tomcat 的 https 协议,可以重新启动 tomcat,然后访问:https://localhost:8443/cas ,如果能出现正常的 CAS 登录页面,则说明 CAS Server 已经部署成功。

虽然 CAS Server 已经部署成功,但这只是一个缺省的实现,在实际使用的时候,还需要根据实际概况做扩展和定制,最主要的是扩展认证 (Authentication) 接口和 CAS Server 的界面。

扩展认证接口

CAS Server 负责完成对用户的认证工作,它会处理登录时的用户凭证 (Credentials) 信息,用户名/密码对是最常见的凭证信息。CAS Server 可能需要到数据库检索一条用户帐号信息,也可能在 XML 文件中检索用户名/密码,还可能通过 LDAP Server 获取等,在这种情况下,CAS 提供了一种灵活但统一的接口和实现分离的方式,实际使用中 CAS 采用哪种方式认证是与 CAS 的基本协议分离开的,用户可以根据认证的接口去定制和扩展。

扩展 AuthenticationHandler

CAS 提供扩展认证的核心是 AuthenticationHandler 接口,该接口定义如清单 1 下:

清单 1. AuthenticationHandler定义

                
public interface AuthenticationHandler {
    /**
     * Method to determine if the credentials supplied are valid.
     * @param credentials The credentials to validate.
     * @return true if valid, return false otherwise.
     * @throws AuthenticationException An AuthenticationException can contain
     * details about why a particular authentication request failed.
     */
    boolean authenticate(Credentials credentials) throws AuthenticationException;
/**
     * Method to check if the handler knows how to handle the credentials
     * provided. It may be a simple check of the Credentials class or something
     * more complicated such as scanning the information contained in the
     * Credentials object. 
     * @param credentials The credentials to check.
     * @return true if the handler supports the Credentials, false othewrise.
     */
    boolean supports(Credentials credentials);
}

该接口定义了 2 个需要实现的方法,supports ()方法用于检查所给的包含认证信息的Credentials 是否受当前 AuthenticationHandler 支持;而 authenticate() 方法则担当验证认证信息的任务,这也是需要扩展的主要方法,根据情况与存储合法认证信息的介质进行交互,返回 boolean 类型的值,true 表示验证通过,false 表示验证失败。

CAS3中还提供了对AuthenticationHandler 接口的一些抽象实现,比如,可能需要在执行authenticate() 方法前后执行某些其他操作,那么可以让自己的认证类扩展自清单 2 中的抽象类:

清单 2. AbstractPreAndPostProcessingAuthenticationHandler定义

                
public abstract class AbstractPreAndPostProcessingAuthenticationHandler 
                                           implements AuthenticateHandler{
    protected Log log = LogFactory.getLog(this.getClass());
    protected boolean preAuthenticate(final Credentials credentials) {
        return true;
    }
    protected boolean postAuthenticate(final Credentials credentials,
        final boolean authenticated) {
        return authenticated;
    }
    public final boolean authenticate(final Credentials credentials)
        throws AuthenticationException {
        if (!preAuthenticate(credentials)) {
            return false;
        }
        final boolean authenticated = doAuthentication(credentials);
        return postAuthenticate(credentials, authenticated);
    }
    protected abstract boolean doAuthentication(final Credentials credentials) 
throws AuthenticationException;
}

AbstractPreAndPostProcessingAuthenticationHandler 类新定义了 preAuthenticate() 方法和 postAuthenticate() 方法,而实际的认证工作交由 doAuthentication() 方法来执行。因此,如果需要在认证前后执行一些额外的操作,可以分别扩展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成为了子类必须要实现的方法。

由于实际运用中,最常用的是用户名和密码方式的认证,CAS3 提供了针对该方式的实现,如清单 3 所示:

清单 3. AbstractUsernamePasswordAuthenticationHandler 定义

                
public abstract class AbstractUsernamePasswordAuthenticationHandler extends 
                       AbstractPreAndPostProcessingAuthenticationHandler{
...
 protected final boolean doAuthentication(final Credentials credentials)
 throws AuthenticationException {
 return authenticateUsernamePasswordInternal((UsernamePasswordCredentials) credentials);
 }
 protected abstract boolean authenticateUsernamePasswordInternal(
        final UsernamePasswordCredentials credentials) throws AuthenticationException;   
protected final PasswordEncoder getPasswordEncoder() {
 return this.passwordEncoder;
 }
public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) {
 this.passwordEncoder = passwordEncoder;
    }
...
}

基于用户名密码的认证方式可直接扩展自 AbstractUsernamePasswordAuthenticationHandler,验证用户名密码的具体操作通过实现 authenticateUsernamePasswordInternal() 方法达到,另外,通常情况下密码会是加密过的,setPasswordEncoder() 方法就是用于指定适当的加密器。

从以上清单中可以看到,doAuthentication() 方法的参数是 Credentials 类型,这是包含用户认证信息的一个接口,对于用户名密码类型的认证信息,可以直接使用 UsernamePasswordCredentials,如果需要扩展其他类型的认证信息,需要实现Credentials接口,并且实现相应的 CredentialsToPrincipalResolver 接口,其具体方法可以借鉴 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。

JDBC 认证方法

用户的认证信息通常保存在数据库中,因此本文就选用这种情况来介绍。将前面下载的 cas-server-3.1.1-release.zip 包解开后,在 modules 目录下可以找到包 cas-server-support-jdbc-3.1.1.jar,其提供了通过 JDBC 连接数据库进行验证的缺省实现,基于该包的支持,我们只需要做一些配置工作即可实现 JDBC 认证。

JDBC 认证方法支持多种数据库,DB2, Oracle, MySql, Microsoft SQL Server 等均可,这里以 DB2 作为例子介绍。并且假设DB2数据库名: CASTest,数据库登录用户名: db2user,数据库登录密码: db2password,用户信息表为: userTable,该表包含用户名和密码的两个数据项分别为 userName 和 password。

1. 配置 DataStore

打开文件 %CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,添加一个新的 bean 标签,对于 DB2,内容如清单 4 所示:

清单 4. 配置 DataStore

                
<bean id="casDataSource" class="org.apache.commons.dbcp.BasicDataSource">
     <property name="driverClassName">
          <value>com.ibm.db2.jcc.DB2Driver</value>
     </property>
     <property name="url">
          <value>jdbc:db2://9.125.65.134:50000/CASTest</value>
     </property>
     <property name="username">
          <value>db2user</value>
     </property>
     <property name="password">
          <value>db2password</value>
     </property>
</bean>

其中 id 属性为该 DataStore 的标识,在后面配置 AuthenticationHandler 会被引用,另外,需要提供 DataStore 所必需的数据库驱动程序、连接地址、数据库登录用户名以及登录密码。

2. 配置 AuthenticationHandler

在 cas-server-support-jdbc-3.1.1.jar 包中,提供了 3 个基于 JDBC 的 AuthenticationHandler,分别为 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。其中 BindModeSearchDatabaseAuthenticationHandler 是用所给的用户名和密码去建立数据库连接,根据连接建立是否成功来判断验证成功与否;QueryDatabaseAuthenticationHandler 通过配置一个 SQL 语句查出密码,与所给密码匹配;SearchModeSearchDatabaseAuthenticationHandler 通过配置存放用户验证信息的表、用户名字段和密码字段,构造查询语句来验证。

使用哪个 AuthenticationHandler,需要在 deployerConfigContext.xml 中设置,默认情况下,CAS 使用一个简单的 username=password 的 AuthenticationHandler,在文件中可以找到如下一行:<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePassword
AuthenticationHandler" />,我们可以将其注释掉,换成我们希望的一个 AuthenticationHandler,比如,使用QueryDatabaseAuthenticationHandler 或 SearchModeSearchDatabaseAuthenticationHandler 可以分别选取清单 5 或清单 6 的配置。

清单 5. 使用 QueryDatabaseAuthenticationHandler

                
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
 <property name="dataSource" ref=" casDataSource " />
 <property name="sql" 
       value="select password from userTable where lower(userName) = lower(?)" />
</bean>

清单 6. 使用 SearchModeSearchDatabaseAuthenticationHandler

                
<bean id="SearchModeSearchDatabaseAuthenticationHandler"
      class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler"
      abstract="false" singleton="true" lazy-init="default" 
                       autowire="default" dependency-check="default">
  <property  name="tableUsers">
   <value>userTable</value>
  </property>
  <property name="fieldUser">
   <value>userName</value>
  </property>
  <property name="fieldPassword">
   <value>password</value>
  </property>
  <property name="dataSource" ref=" casDataSource " />
</bean>

另外,由于存放在数据库中的密码通常是加密过的,所以 AuthenticationHandler 在匹配时需要知道使用的加密方法,在 deployerConfigContext.xml 文件中我们可以为具体的 AuthenticationHandler 类配置一个 property,指定加密器类,比如对于 QueryDatabaseAuthenticationHandler,可以修改如清单7所示:

清单 7. 添加 passwordEncoder

                
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
  <property name="dataSource" ref=" casDataSource " />
  <property name="sql" 
           value="select password from userTable where lower(userName) = lower(?)" />
  <property  name="passwordEncoder"  ref="myPasswordEncoder"/>
</bean>

其中 myPasswordEncoder 是对清单 8 中设置的实际加密器类的引用:

清单 8. 指定具体加密器类

                
<bean id="passwordEncoder" 
            class="org.jasig.cas.authentication.handler.MyPasswordEncoder"/>

这里 MyPasswordEncoder 是根据实际情况自己定义的加密器,实现 PasswordEncoder 接口及其 encode() 方法。

3. 部署依赖包

在以上配置完成以后,需要拷贝几个依赖的包到 cas 应用下,包括:

  • 将 cas-server-support-jdbc-3.1.1.jar 拷贝到 %CATALINA_HOME%/webapps/cas/ WEB-INF/lib 目录。
  • 数据库驱动,由于这里使用 DB2,将 %DB2_HOME%/java 目录下的 db2java.zip (更名为 db2java.jar), db2jcc.jar, db2jcc_license_cu.jar 拷贝到 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目录。对于其他数据库,同样将相应数据库驱动程序拷贝到该目录。
  • DataStore 依赖于 commons-collections-3.2.jar, commons-dbcp-1.2.1.jar, commons-pool-1.3.jar,需要到 apache 网站的 Commons 项目下载以上 3 个包放进 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目录。

扩展 CAS Server 界面

CAS 提供了 2 套默认的页面,分别为“ default ”和“ simple ”,分别在目录“ cas/WEB-INF/view/jsp/default ”和“ cas/WEB-INF/view/jsp/simple ”下。其中 default 是一个稍微复杂一些的页面,使用 CSS,而 simple 则是能让 CAS 正常工作的最简化的页面。

在部署 CAS 之前,我们可能需要定制一套新的 CAS Server 页面,添加一些个性化的内容。最简单的方法就是拷贝一份 default 或 simple 文件到“ cas/WEB-INF/view/jsp ”目录下,比如命名为 newUI,接下来是实现和修改必要的页面,有 4 个页面是必须的:

  • casConfirmView.jsp: 当用户选择了“ warn ”时会看到的确认界面
  • casGenericSuccess.jsp: 在用户成功通过认证而没有目的Service时会看到的界面
  • casLoginView.jsp: 当需要用户提供认证信息时会出现的界面
  • casLogoutView.jsp: 当用户结束 CAS 单点登录系统会话时出现的界面

CAS 的页面采用 Spring 框架编写,对于不熟悉 Spring 的使用者,在修改之前需要熟悉该框架。

页面定制完过后,还需要做一些配置从而让 CAS 找到新的页面,拷贝“ cas/WEB-INF/classes/default_views.properties ”,重命名为“ cas/WEB-INF/classes/ newUI_views.properties ”,并修改其中所有的值到相应新页面。最后是更新“ cas/WEB-INF/cas-servlet.xml ”文件中的 viewResolver,将其修改为如清单 9 中的内容。

清单 9. 指定 CAS 页面

                
<bean id="viewResolver" 
     class="org.springframework.web.servlet.view.ResourceBundleViewResolver" p:order="0">
    <property name="basenames">
        <list>
            <value>${cas.viewResolver.basename}</value>
            <value> newUI_views</value>
        </list>
    </property>
</bean>

 

部署客户端应用

单点登录的目的是为了让多个相关联的应用使用相同的登录过程,本文在讲解过程中构造 2个简单的应用,分别以 casTest1 和 casTest2 来作为示例,它们均只有一个页面,显示欢迎信息和当前登录用户名。这 2 个应用使用同一套登录信息,并且只有登录过的用户才能访问,通过本文的配置,实现单点登录,即只需登录一次就可以访问这两个应用。

与 CAS Server 建立信任关系

假设 CAS Server 单独部署在一台机器 A,而客户端应用部署在机器 B 上,由于客户端应用与 CAS Server 的通信采用 SSL,因此,需要在 A 与 B 的 JRE 之间建立信任关系。

首先与 A 机器一样,要生成 B 机器上的证书,配置 Tomcat 的 SSL 协议。其次,下载http://blogs.sun.com/andreas/entry/no_more_unable_to_find 的 InstallCert.java,运行“ java InstallCert compA:8443 ”命令,并且在接下来出现的询问中输入 1。这样,就将 A 添加到了 B 的 trust store 中。如果多个客户端应用分别部署在不同机器上,那么每个机器都需要与 CAS Server 所在机器建立信任关系。

配置 CAS Filter

准备好应用 casTest1 和 casTest2 过后,分别部署在 B 和 C 机器上,由于 casTest1 和casTest2,B 和 C 完全等同,我们以 casTest1 在 B 机器上的配置做介绍,假设 A 和 B 的域名分别为 domainA 和 domainB。

将 cas-client-java-2.1.1.zip 改名为 cas-client-java-2.1.1.jar 并拷贝到 casTest1/WEB-INF/lib目录下,修改 web.xml 文件,添加 CAS Filter,如清单 10 所示:

清单 10. 添加 CAS Filter

                
<web-app>
  ...
  <filter>
    <filter-name>CAS Filter</filter-name>
    <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
      <param-value>https://domainA:8443/cas/login</param-value>
    </init-param>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
      <param-value>https://domainA:8443/cas/serviceValidate</param-value>
    </init-param>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
      <param-value>domainB:8080</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CAS Filter</filter-name>
    <url-pattern>/protected-pattern/*</url-pattern>
  </filter-mapping>
  ...
</web-app>

对于所有访问满足 casTest1/protected-pattern/ 路径的资源时,都要求到 CAS Server 登录,如果需要整个 casTest1 均受保护,可以将 url-pattern 指定为“/*”。

从清单 10 可以看到,我们可以为 CASFilter 指定一些参数,并且有些是必须的,表格 1表格 2 中分别是必需和可选的参数:

表格 1. CASFilter 必需的参数

参数名
作用

edu.yale.its.tp.cas.client.filter.loginUrl
指定 CAS 提供登录页面的 URL

edu.yale.its.tp.cas.client.filter.validateUrl
指定 CAS 提供 service ticket 或 proxy ticket 验证服务的 URL

edu.yale.its.tp.cas.client.filter.serverName
指定客户端的域名和端口,是指客户端应用所在机器而不是 CAS Server 所在机器,该参数或 serviceUrl 至少有一个必须指定

edu.yale.its.tp.cas.client.filter.serviceUrl
该参数指定过后将覆盖 serverName 参数,成为登录成功过后重定向的目的地址

表格 2. CASFilter 可选参数

参数名
作用

edu.yale.its.tp.cas.client.filter.proxyCallbackUrl
用于当前应用需要作为其他服务的代理(proxy)时获取 Proxy Granting Ticket 的地址

edu.yale.its.tp.cas.client.filter.authorizedProxy
用于允许当前应用从代理处获取 proxy tickets,该参数接受以空格分隔开的多个 proxy URLs,但实际使用只需要一个成功即可。当指定该参数过后,需要修改 validateUrl 到 proxyValidate,而不再是 serviceValidate

edu.yale.its.tp.cas.client.filter.renew
如果指定为 true,那么受保护的资源每次被访问时均要求用户重新进行验证,而不管之前是否已经通过

edu.yale.its.tp.cas.client.filter.wrapRequest
如果指定为 true,那么 CASFilter 将重新包装 HttpRequest,并且使 getRemoteUser() 方法返回当前登录用户的用户名

edu.yale.its.tp.cas.client.filter.gateway
指定 gateway 属性

传递登录用户名

CAS 在登录成功过后,会给浏览器回传 Cookie,设置新的到的 Service Ticket。但客户端应用拥有各自的 Session,我们要怎么在各个应用中获取当前登录用户的用户名呢?CAS Client 的 Filter 已经做好了处理,在登录成功后,就可以直接从 Session 的属性中获取,如清单 11 所示:

清单 11. 在 Java 中通过 Session 获取登录用户名

                
// 以下两者都可以
session.getAttribute(CASFilter.CAS_FILTER_USER);
session.getAttribute("edu.yale.its.tp.cas.client.filter.user");

在 JSTL 中获取用户名的方法如清单 12 所示:

清单 12. 通过 JSTL 获取登录用户名

                
<c:out value="${sessionScope[CAS:'edu.yale.its.tp.cas.client.filter.user']}"/>

另外,CAS 提供了一个 CASFilterRequestWrapper 类,该类继承自HttpServletRequestWrapper,主要是重写了 getRemoteUser() 方法,只要在前面配置 CASFilter 的时候为其设置“ edu.yale.its.tp.cas.client.filter.wrapRequest ”参数为 true,就可以通过 getRemoteUser() 方法来获取登录用户名,具体方法如清单 13 所示:

清单 13. 通过 CASFilterRequestWrapper 获取登录用户名

                
CASFilterRequestWrapper  reqWrapper=new CASFilterRequestWrapper(request);
out.println("The logon user:" + reqWrapper.getRemoteUser());


效果

在 casTest1 和 casTest2 中,都有一个简单 Servlet 作为欢迎页面 WelcomPage,且该页面必须登录过后才能访问,页面代码如清单 14 所示:

清单 14. WelcomePage 页面代码

                
public class WelcomePage extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException
  {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Welcome to casTest2 sample System!</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Welcome to casTest1 sample System!</h1>");
    CASFilterRequestWrapper  reqWrapper=new CASFilterRequestWrapper(request);
    out.println("<p>The logon user:" + reqWrapper.getRemoteUser() + "</p>");
    HttpSession session=request.getSession();
    out.println("<p>The logon user:" + 
                   session.getAttribute(CASFilter.CAS_FILTER_USER)  + "</p>");
    out.println("<p>The logon user:" + 
         session.getAttribute("edu.yale.its.tp.cas.client.filter.user") + "</p>");
    out.println("</body>");
    out.println("</html>");
    }
}

在上面所有配置结束过后,分别在 A, B, C上启动 cas, casTest1 和 casTest2,按照下面步骤来访问 casTest1 和 casTest2:

  1. 打开浏览器,访问 http://domainB:8080/casTest1/WelcomePage ,浏览器会弹出安全提示,接受后即转到 CAS 的登录页面,如图 2 所示:

图 2. CAS 登录页面
CAS 登录页面

  1. 登录成功后,再重定向到 casTest1 的 WelcomePage 页面,如所示:

图 3. 登录后访问 casTest1 的效果
登录后访问 casTest1 的效果

可以看到中地址栏里的地址多出了一个 ticket 参数,这就是 CAS 分配给当前应用的 ST(Service Ticket)。

  1. 再在同一个浏览器的地址栏中输入 http://domainC:8080/casTest2/WelcomePage ,系统不再提示用户登录,而直接出现如图 4 所示的页面,并且显示在 casTest1 中已经登录过的用户。

图 4. 在 casTest1 中登录过后访问 casTest2 的效果
在 casTest1 中登录过后访问 casTest2 的效果

  1. 重新打开一个浏览器窗口,先输入 http://domainC:8080/casTest2/WelcomePage ,系统要求登录,在登录成功过后,正确显示 casTest2 的页面。之后再在地址栏重新输入 http://domainB:8080/casTest1/WelcomePage ,会直接显示 casTest1 的页面而无需再次登录。

Java 3D 已经开源了

Javae 3D API是作为复杂三维图形和声音渲染系统的接口的一系列层次的JAVA类的统称。开发员可以用Java3D开发创建和操纵3D图形对象的高端应用。
Java3D项目由多个子项目组成主要包括:j3d-core(Java3D API的核心), vecmath(3D矢量数学包)与j3d-core-utils(Java3D核心utilitie),Java3D VRML97 Loader等,现在j3d-core和vecmath已经开源了,将采用GPLv2 with the Classpath exception许可授权。

官方网址:https://java3d.dev.java.net/

FourByFour is a three dimensional game of tic-tac-toe on a 4x4x4 cube.
A simple rotating cube HelloUniverse a simple rotating cube.

A program to test off-screen rendering and printingPrintCanvas3D a program to test off-screen rendering and printing.
Displays a list of 3D properties in a text panelQueryProperties displays a list of 3D properties in a text panel.

A simple moving sphereSphereMotion a simple moving sphere.

    Advanced Texture Mapping Examples

    The following examples use advanced texture mapping features. They should run on most graphics cards, although they may not run on some older cards:

    A bump mapping exampleDOT3Demo a bump mapping example.
    A non-power-of-two texture exampleTextureImageNPOT a non-power-of-two texture example.

    Sound Examples using JOALMixer

    The following examples use JOALMixer to render Java 3D Sound nodes. You will need a sound card and speakers or headphones in order to hear the sound for these examples. JOALMixer is supported on Windows, Linux, and Mac OS X.

    BackgroundSoundTestBackgroundSoundTest a simple background sound test.
    PointSoundTestPointSoundTest a simple point sound test.

    Programmable Shader Examples

    Programmable shader examples using OpenGL’s GLSL shading language. Note that the following examples require a shader-capable graphics card (for example, an NVidia 6600 or ATI X200).

    An environment mapping exampleEnvironmentMappingGLSL an environment mapping example.
    An example that loads in a .obj file and applies a shaderObjLoadGLSL an example that loads in a .obj file and applies a shader.

    A per-pixel lighting (Phong shading) examplePhongShadingGLSL a per-pixel lighting (Phong shading) example.
    A program illustrating multiple shaders with shader attributesShaderTestGLSL a program illustrating multiple shaders

    基于FireFox的测试插件

    今天无意中看到了一个测试大牛的博客,第一次看到有人把测试作得这么精,让我颠覆了测试人员的概念.如果有人想成为一个优秀的测试人员可以看看他的文章.

    博客地址:http://blog.csdn.net/testing_is_believing/

    两个可用于浏览器兼容性测试的Firefox插件(转载)

    IEView是Mozilla Firefox浏览器的一个简单的插件。它允许在Firefox浏览器的当前页面中打开IE浏览器进行当前页面的浏览,或者把当前页面的链接在IE浏览器中打开。

    可到http://ieview.mozdev.org下载IEView。

    下载后用Mozilla Firefox浏览器打开插件文件进行安装,安装完并重启Mozilla Firefox浏览器后,可在Mozilla Firefox浏览器中的当前页面单击右键,选择菜单“View this Page in IE”,在IE浏览器中打开相同的页面,从而比较两个浏览器对同一个页面进行浏览时的差异,包括布局、颜色、界面元素的显示等的差异。

    IEView可在Mozilla Firefox浏览器中打开独立的IE窗口浏览相同的页面,但是毕竟是独立的窗口,不便于切换对比两个浏览器加载的页面效果。而IETab则更进了一步,直接在Mozilla Firefox浏览器中以Tab页的方式显示IE浏览器。

    可到http://ietab.mozdev.org下载IETab。

    基于FireFox的测试插件 – Selenium IDE(转载)

    基于FireFox的测试插件中,Selenium IDE是其中的佼佼者。

    Selenium IDE是一个基于FireFox的Web测试开发环境,可以录制、编辑和调试测试。Selenium IDE包含了Selenium Core,因此可以轻易地在浏览器中录制和回放测试。

    Selenium IDE不仅仅是一个测试录制工具,而是一个IDE,可以录制测试,也可以手工编辑测试,可设置断点进行调试,可把测试保存到HTML、Ruby、C#、Java等其他脚本格式,然后使用Selenium RC来实现并运行更加灵活和强大的测试。

    Selenium IDE目前的最新版本是0.8.7 ,下载地址:
    http://selenium-ide.openqa.org/download.jsp

    下载后,在FireFox中打开插件文件selenium-ide-0.8.7.xpi进行安装,重新启动FireFox后,可选择菜单“Tools | Selenium IDE”打开Selenium IDE的界面。

    录制测试脚本的过程可以用“傻瓜式”来形容,手工编辑脚本是通过选择和插入Selenium命令(Command)的方式来实现的,结合其在线命令帮助(Reference)还是比较容易上手的。可直接在FireFox中运行测试脚本,也可调出TestRunner界面来执行测试脚本。

    Selenium IDE目前仅支持FireFox浏览器,IE中类似的Web测试录制工具目前找到一个“WatiN Test Recorder”,支持在IE中录制WatiN的测试脚本。

    Netbeans 6.0发布,支持Ruby、移动开发和集成的剖析器

    Netbeans团队今天发布了Netbeans 6.0。6.0几个月前就已经采用了GPL和CDDL双重许可。6.0版花费了稍多于一年的时间,在5.5版的基础上做出了许多重大的改进,其中包括:

    编辑器的改进

    更智能的代码完成
    语法高亮
    更方便的导航和检查
    随时插入模板代码和环绕代码的功能
    Ruby/JRuby/Ruby on Rails支持

    项目支持,包括Gems和RSpec
    高级的Ruby编辑
    ActiveRecord代码完成
    Ruby调试器
    Ruby on Rails支持
    剖析

    集成进NetBeans IDE的剖析器
    比较内存快照
    观察堆内存(Heap Walker)
    集成JMeter
    动态挂接JDK 1.6
    Web和Java EE

    内建Web应用的视觉化设计器
    视觉化的页面流编辑
    增强的JavaScript支持
    增强的Web Service支持
    支持具备Ajax功能的JSF组件
    移动开发

    新集成的CLDC/MIDP和CDC开发用户界面
    新的游戏构建程序
    新的移动程序视觉化设计器
    重写的JSR-172 stub编译器
    SOA
    服务复合和组装所用的工件(Artifacts)
    图形化的WSDL编辑器
    XSLT编辑器
    组件绑定的工具支持
    Java EE Web Service项目支持
    PDF格式的Netbeans Magazine也发表了一期62页的Netbeans 6.0专刊。(InfoQ)

    Spring+Struts整合问题整理

    在整合的时候遇到了一些小问题,整理出来希望可以方便跟我一样的菜鸟级SSH们.

    问题1现象:

    2008-02-23   10:31:07,078   WARN   [org.apache.struts.action.RequestProcessor]   –   Unhandled   Exception   thrown:   class   org.springframework.beans.factory.BeanCreationException

    2008-02-23   10:31:07,078   ERROR   [org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/myssh].[action]]   –   Servlet.service()   for   servlet   action   threw   exception

    org.springframework.beans.factory.BeanCreationException:   Error   creating   bean   with   name   ‘sessionFactory’   defined   in   class   path   resource   [applicationContext.xml]:   Initialization   of   bean   failed;   nested   exception   is   org.hibernate.HibernateException:   could   not   configure   from   URL:   file:src/hibernate.cfg.xml

    org.hibernate.HibernateException:   could   not   configure   from   URL:   file:src/hibernate.cfg.xml

    问题一解决:

    自动生成的applicationContext.xml文件配置如下:
    <bean   id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property   name="configLocation">
    <value> file:src/hibernate.cfg.xml </value>
    </property>
    </bean>

    改动后的配置文件为:

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>classpath:/hibernate.cfg.xml</value>
        </property>
    </bean>

    问题2现象:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘sessionFactory’ defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/hibernate/cfg/HbmBinder$SecondPass

    问题2解决:

    是hibernate-a*这个包和spring有冲突,删掉hibernate-a*包就OK了

    我就遇到这两个问题,希望大家不遇到问题!

    问题3现象:
    java.lang.IllegalStateException:   No   WebApplicationContext   found:   no   ContextLoaderListener   registered?

    问题3解决:

    在   web.xml中加上
    <context-param>
    <param-name> contextConfigLocation </param-name>
    <param-value>
    /WEB-INF/classes/applicationContext.xml
    </param-value>
    </context-param>
    <servlet>
    <servlet-name> context </servlet-name>
    <servlet-class>
    org.springframework.web.context.ContextLoaderServlet
    </servlet-class>
    <load-on-startup> 1 </load-on-startup>
    </servlet>