随笔:93 文章:11 评论:22 引用:0
首页 发新随笔
发新文章 联系 聚合管理

摘自http://blog.csdn.net/dl88250/archive/2007/10/25/1843813.aspx
Java Logging API是sun公司于2002年5月正式发布的。它是自J2SE 1.4版本开始提供的一个新的应用程序接口。它能够很方便地控制和输出日志信息到文件,控制台或其它用户定义的地方,如数据库,电子邮件等。所以它是为最 终用户,系统管理员,软件服务工程师和开发人员提供的一种捕捉安全漏洞,检查配置正确性,跟踪调查系统运行瓶颈和调查系统运行错误的工具。
Java Logging API的设计目标是要:
1. 能够在运行时启动或关闭日志功能;
2. 能够非常精密地控制日志,即能够启动或关闭日志的某个个别功能;
3. 能够在运行时注册日志服务,当然也可以注册新的第三方日志服务;
4. 能够提供连接服务,使Java Logging API能与现存的日志系统(如操作系统的日志功能)连接;
5. 能够支持显示高优先度的信息给最终用户。

输出日志
由于Java Logging API提供了非常方便的接口,你可以在下面的例子里看到它的使用有多方便。
例1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jdk14logger;
import java.util.logging.Logger; // <= (1)
public class HelloLogWorld
{

private static String name = HelloLogWorld.class.getName();
private static Logger log = Logger.getLogger(name);// <= (2)

public void sub()
{
log.info("Hello Logging World");// <= (3)
}

public static void main(String[] args)
{
HelloLogWorld logWorld = new HelloLogWorld();
logWorld.sub();
}
}

说明:
1. Logger是Java Logging API中的一个类。在此之前,你必须确认你所使用的J2SE是1.4或更高版本。
2. Logger.getLogger方法创建了一个Logger实例。每一个Logger实例都必须有个名称,通常的做法是使用类名称定义Logger实例。后面还会讲到这样做的原因。
3. log.info方法用来输出日志信息。
执行例1你可以看到控制台上输出了日期时间,类名,方法名和Hello Logging World的信息。

输出的种类
Java Logging API提供了七个级别用来控制输出。这七个级别分别是:
SEVERE (最高级别)
WARNING
INFO
CONFIG
FINE
FINER
FINEST (最低级别)
与之对应,在Logger类中也为你预备好了这七个级别的输出方法。下面是使用这几种方法输出日志信息的例子。
例2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package jdk14logger;
import java.util.logging.Logger;

public class LevelTest
{

private static String name = HelloLogWorld.class.getName();
private static Logger log = Logger.getLogger(name);

public void sub()
{
log.severe("severe level");// <= (1)
log.warning("warning level");// <= (2)
log.info("info level");// <= (3)
log.config("config level");// <= (4)
log.fine("fine level");// <= (5)
log.finer("finer level");// <= (6)
log.finest("finest level");// <= (7)
}

public static void main(String[] args)
{
LevelTest test = new LevelTest();
test.sub();
}
}


执行例2你可能看到控制台上只输出了(1)-(3)的信息,(4)-(7)的信息并没有如想象的那样被输出。这不要紧,继续看下面的内容你就知道原因了。

控制输出
上面例2中info以下的级别信息没有被输出是因为缺省日志输出级别的设置是info,也就是说只有info或它以上的级别被输出,它以下的级别不被输 出。通过变更设置可以使输出级别改变。变更输出级别的方法有两种,一是使用外部配置文件,二是使用程序编码。通常都是使用第一种方法。缺省的外部配置文件 是JRE中lib/logging.properties文件。你可以打开这个文件,修改以下两行为:
.level= ALL
java.util.logging.ConsoleHandler.level = ALL
修改完后,再运行一次例2,这次(1)-(7)的内容就都输出出来了。你可以修改输出级别为以下任何值,试一试输出有什么变化。
OFF
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
ALL

自定义的配置文件
如果你不想使用系统提供的缺省配置文件lib/logging.properties,那么也可以使用自己定义的配置文件。使用自定义配置文件的方法有很 多种,比较方便的方法是通过定义系统属性值java.util.logging.config.file来设置自定义配置文件。例如在执行例2时,使用下 面的命令:
java -Djava.util.logging.config.file=mylogging.properties LevelTest
其中mylogging.properties是你自定义的配置文件。如果需要,你还可以加上文件的路径名。

更多的输出控制
除了前面讲到的七个输出级别外,Logger类中还提供了以下三个便于程序员调试时使用的输出信息方法:
entering
exiting
throwing
它们是与FINER相同级别的输出,分别用于程序入口,出口和例外时的输出。除此之外Logger类中还准备了一些输出信息的方法,这些留待以后详细介绍。

输出内容的本地化
Java Logging API已经考虑到了国际化对应问题。在输出信息上你可以使用ResourceBundle提供本地化的输出信息。下面举个例子说明。
例3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jdk14logger;
import java.util.logging.Logger;
public class LocalTest {
private static String name = HelloLogWorld.class.getName();
private static Logger log = Logger.getLogger (name, "jdk14logger/LocalTest");<= (1)
public void sub() {
log.severe("level.severe");<= (2)
log.warning("level.warning");<= (3)
log.info("level.info");<= (4)
log.config("level.config");<= (5)
log.fine("level.fine");<= (6)
log.finer("level.finer");<= (7)
log.finest("level.finest");<= (8)
}
public static void main(String[] args) {
LocalTest test = new LocalTest();
test.sub();
}
}

你可以比较一下例2和例3。可以看到例3的Logger.getLogger 方法调用中增加了一个传参,并且(2)-(8)中的输出内容也改变了。(1)中增加的字符串传参就是使用ResourceBundle配置时的属性文件 名。下面就需要建立这个属性文件jdk14logger/LocalTest.properties,内容如下:
level.severe=severe level
level.warning=warning level
level.info=info level
level.config=config level
level.fine=fine level
level.finer=finer level
level.finest=finest level
现在运行例3可以看到输出结果并不是(2)-(8)中定义的内容。或许你已经想到了,(2)-(8)中定义的实际上是local.properties文 件中的属性键名,而输出是这些属性键名所对应的键值。那么或许你要问如果属性键名在属性文件中不存在怎么办,答案很简单,如果它不是属性键名就一定是要输 出的内容,所以就照原样输出了事。 
posted @ 2009-02-19 23:00 redcoatjk 阅读(1806) | 评论 (0)编辑 收藏
 
载自http://kuangbaoxu.javaeye.com/blog/192804
1. 代理模式主要有两种:静态代理和动态代理

2. 静态代理:

比如要在输出“HelloWorld”前打印一个字符串“Welcome”

A:先定义一个接口类
1package ttitfly.proxy;    
2   
3public interface HelloWorld {    
4    public void print();    
5//  public void say();    
6}
 
B: 定义一个该接口的实现类

java 代码
 1package ttitfly.proxy;    
 2   
 3public class HelloWorldImpl implements HelloWorld{    
 4   
 5    public void print(){    
 6        System.out.println("HelloWorld");    
 7    }
    
 8//  public void say(){    
 9//      System.out.println("Say Hello!");    
10//  }    
11}
    
C:定义一个静态代理类
 1package ttitfly.proxy;    
 2   
 3public class StaticProxy implements HelloWorld{    
 4   
 5    public HelloWorld helloWorld ;    
 6    public StaticProxy(HelloWorld helloWorld){    
 7        this.helloWorld = helloWorld;    
 8    }
    
 9        
10    public void print(){    
11        System.out.println("Welcome");    
12        //相当于回调    
13        helloWorld.print();    
14    }
    
15        
16//  public void say(){    
17//      //相当于回调    
18//      helloWorld.say();    
19//  }    
20}
    
D: 一个测试类:
 1package ttitfly.proxy;    
 2   
 3public class TestStaticProxy {    
 4   
 5    public static void main(String[] args){    
 6        HelloWorld helloWorld = new HelloWorldImpl();    
 7        StaticProxy staticProxy = new StaticProxy(helloWorld);    
 8        staticProxy.print();    
 9            
10//      staticProxy.say();    
11    }
    
12}
    
可以看出静态代理类有一个很不爽的缺点:当如果接口加一个方法(把上面所有的代码的注释给去掉),所有的实现类和代理类里都需要做个实现。这就增加了代码的复杂度。动态代理就可以避免这个缺点。 
3 。动态代理

动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类

代理类: 
 1package ttitfly.proxy;        
 2       
 3import java.lang.reflect.InvocationHandler;        
 4import java.lang.reflect.Method;        
 5import java.lang.reflect.Proxy;        
 6//动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类        
 7public class DynamicProxy implements InvocationHandler{        
 8            
 9    private Object object;         
10    //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。    
11    //Proxy.newProxyInstance的第三个参数是表明这些被拦截的方法执行时需要执行哪个InvocationHandler的invoke方法    
12    public Object bindRelation(Object object){         
13        this.object = object;        
14        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);         
15    }
         
16    //拦截关联的这个实现类的方法被调用时将被执行        
17    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         
18        System.out.println("Welcome");        
19        Object result = method.invoke(object, args);         
20        return result;        
21    }
        
22       
23}
        

测试类:
 1package ttitfly.proxy;        
 2       
 3public class TestDynamicProxy {        
 4    public static void main(String[] args){        
 5        HelloWorld helloWorld = new HelloWorldImpl();        
 6        DynamicProxy dp = new DynamicProxy();        
 7        //在这里绑定的是HelloWorld,也就是HelloWorld是被代理接口。所以绑定关系时,需要传递一个HelloWorld的实现类的实例化对象。        
 8        HelloWorld helloWorld1 = (HelloWorld)dp.bindRelation(helloWorld);         
 9        helloWorld1.print();         
10        helloWorld1.say();        
11            
12        //helloWorld2将不被拦截    
13        HelloWorld helloWorld2 = new HelloWorldImpl();    
14        helloWorld2.print();         
15        helloWorld2.say();    
16            
17    }
        
18}
        
在测试类里调用实现类的print和say方法,因为代理类里代理了HelloWorld的所有方法。所以就不需要像静态代理类那样一一实现了。
[本来想自己写个类似的东西,不过发现javaeye的这篇写的已经很好了.转载过来学习一下.
 javaeye的代码copy功能真好用!.]





posted @ 2009-02-17 18:40 redcoatjk 阅读(370) | 评论 (1)编辑 收藏
 
载自http://blog.csdn.net/icecityman/archive/2008/11/08/3256281.aspx

Java程序在定义类时,除了使用class关键字标识之外,还可以在class之前增加若干类的修饰符来修饰限定所定义的类的特性。类的修饰符分为访问控制符和非访问控制符两大类。修饰符之间的先后排列次序对类的性质没有任何影响。

一. 非访问修饰符。
 1. 抽象类:
    凡是用abstract修饰符修饰的类被称为抽象类。抽象类就是没有具体对象的概念类。
    抽象类是一种经过优化的概念组织方式:把共同特点抽象出来;其后在描述和处理某一种具体对象时,就只需描述不同的特殊之处。这种组织方式使得所有的概念层次分明,简洁洗练,非常符合人们日常的思维习惯。
    由于抽象类是它的所有子类的公共属性的集合,所以使用抽象类的一个优点就是可以充分利用这些公共属性来提高开发和维护程序的效率。
    值得一提的是,面向对象技术是要用更接近于人类思维方式的方法来处理实际问题,抽象类的设立就是这种思想的具体体现之一,它是模仿人类的思维模式的产物。

 2. 最终类:
    如果一个类被final修饰符所修饰和限定,说明这个类不可能有子类。
    被定义为final的类通常是一些有固定作用、用来完成某种标准功能的类。如Java系统定义好的用来实现网络功能的InterAddress、Socket等类都是final类。
       abstract和final修饰符不能同时修饰一个类,因为abstract类自身没有具体对象,需要派生出子类后在创建子类的对象;而final类不可能有子类。这样放在一起修饰就没有意义了。

 3. 有些类的修饰符也可以用来修饰类中的成员变量或方法:
 (1)成员变量:是类和对象的静态属性,定义成员变量的操作就是说明变量或创建对象的操作。
   <1> 静态成员变量:用static修饰符修饰的成员变量是仅属于类的静态成员变量。静态成员变量是类中每个对象共享的成员变量。他们是类的成员变量,不属于任何一个类的具体对象。是一个公共的存储单元,任何一个类的对象访问它时,取到的都是相同的数值。
   <2> 静态初始化器:静态初始化器是由关键字static引导的一对大括号括起的语句组。作用是:在加载时,初始化类的静态成员变量。
      与构造函数相同,他们都是用来完成初始化的工作,但是静态初始化器与构造函数有三点不同:
       ①构造函数是对每个新创建的对象初始化,而静态初始化器是对类自身进行初始化。
       ②构造函数是在用new运算符产生新对象时由系统自动执行,而静态初始化器则是在它所属的类加载到内存时由系统调用执行。
       ③不同于构造函数,静态初始化器不是方法,没有方法名、返回值和参数列表。
   <3> 最终成员变量:用final修饰的成员变量,实际上就是Java中的常量。
      用final修饰符说明常量时,需要注意以下几点:
      ①需要说明常量的数据类型。
      ②需要同时指出常量的具体取值。
      ③因为所有类对象的常量成员,其数值都固定一致,为了节省空间,常量通常声明为static。
   <4> 易失成员变量:如果一个成员变量被volatile修饰符所修饰,说明这个成员变量可能同时被几个线程所控制和修改,即这个成员变量不仅仅被当前程序所掌握,在运行过程中可能在其他未知的程序操作影响和改变该成员变量的取值。在使用当中应该特别注意。
    通常,volatile用来修饰接受外部输入的成员变量。如表示当前时间的变量将系统的后台线程随时修改,以保证程序中取到的总是最新的当前系统时间,所以可以把它定义为易失成员变量。

 (2)方法:是类的动态属性,标志了类所具有的功能和操作。小括号是方法的标志。
   <1> 抽象方法:修饰符abstract修饰的抽象方法是一种仅有方法头,而没有具体的方法体和操作实现的方法。使用抽象方法的目的是使所有的子类,对外都呈现一个相同名字的方法,是一个统一的接口。所有的抽象方法,都必须存在于抽象类之中。
   <2> 静态方法:用static修饰符修饰的方法,是属于整个类的类方法,不用的是对象或实例的方法。调用这种方法时,应该使用类名作前缀;这种方法在内存中的代码段将随着类的定义而分配和装载,不被任何一个对象专有;只能处理属于整个类的成员变量。
   <3> 最终方法:用final修饰符修饰的类方法。功能和内部语句不能再更改的方法,不能再被继承。
    注意:所有已被private修饰符限定为私有的方法,以及所有包含在final类中的方法,都被缺省地认为是final的。
   <4> 本地方法:用native修饰符声明其他语言书写方法体并具体实现方法功能的特殊的方法。这里的其他语言包括C/C++/FROTRAN/汇编等。由于native的方法的方法体使用其他语言在程序外部写成,所以所有的native方法都没有方法体,而用一个分号代替。
   <5> 同步方法:如果synchronized修饰的方法是一个类的方法(即static的方法),那么在被调用执行前,将把系统类Class中对应当前类的对象加锁。如果synchronized修饰的是一个对象的方法(未用static修饰的方法),则这个方法在被调用执行前,将把当前对象加锁。Synchronized修饰符主要用于多线程共存的程序中的协调和同步。


二. 访问控制符。
    访问控制符是一组限定类、成员变量或方法是否可以被程序里的其他部分访问和调用的修饰符。类的访问控制符只有一个public,成员变量和方法的访问控制符有四个,分别是public、private、protected、private protected,另外还有一种没有定义专门的访问控制符的缺省情况。
 1. 公有访问控制符public:
      Java的类是通过包的概念来组织的,包氏类的一个松散的集合。处于同一个包中的类可以不需要任何说明而方便的互相访问和引用,而对于不同包中的类,则不行。但当一个类被声明为public时,他就具有了被其他包中的类访问的可能性,只要这些其他包中的类在程序中使用import语句引入public类,就可以访问和引用这个类。
    类中被设定为public的方法是这个类对外的接口部分,避免了程序的其他部分直接去操作类内的数据,这实际就是数据封装思想的体现。
    每个Java程序的主类都必须是public类,也是基于相同的原因。
    用public修饰的类的成员变量称为公共成员变量。如果公共成员变量属于公共类,则它能被所有的其他类所引用。public修饰符会造成安全性的数据封装性下降,所以一般应减少public成员变量的使用。

 2. 缺省访问控制符:
    缺省访问控制权规定,该类只能被同一个包中的类访问和引用,而不可以被其他包中的类使用,这种访问特性又称为包访问性。
    同样道理,类内的成员变量或方法如果美育访问控制符来限定,也就具有包访问性。
    简单说,定义在同一个程序中的所有类属于一个包。

 3. 私有访问控制符private:
    用private修饰得成员变量或方法只能被该类自身所访问和修改,而且不能被任何其他类(包括该类的子类)来获取和引用。private修饰符用来声明那些类的私有成员,它提供了最高的保护级别。

 4. 保护访问控制符protected:
    用protected修饰的成员变量可以被三种类所引用:该类自身、与它在同一个包中的其它类、在其他包中的该类的子类。使用protected修饰符的主要作用是允许其他包中该类的子类来访问父类的特定属性。

 5. 私有保护访问控制符 private protected :
    用private protected修饰的成员变量可以被两种类访问和引用,一种是该类本身,一种是该类的所有子类。把同一个包内的非子类排除在可访问的范围之外,使得成员变量更专于具有明确继承关系的类,而不是松散地组合在一起的包。

posted @ 2009-02-10 12:50 redcoatjk 阅读(515) | 评论 (0)编辑 收藏
 

一、拦截器的实现

     实现一个拦截器非常简单。实际上,一个拦截器就是一个普通的类,只是这个类必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。Interceptor接口有如下三个方法:


public interface Interceptor extends Serializable 
{
    
void destroy();
    
void init();
    String intercept(ActionInvocation invocation
throws Exception;
}


 

其中initdestroy方法只在拦截器加载和释放(都由Struts2自身处理)时执行一次。而intercept方法在每次访问动作时都会被调用。Struts2在调用拦截器时,每个拦截器类只有一个对象实例,而所有引用这个拦截器的动作都共享这一个拦截器类的对象实例,因此,在实现Interceptor接口的类中如果使用类变量,要注意同步问题。

下面我们来实现一个简单的拦截器,这个拦截器通过请求参数action指定一个拦截器类中的方法,并调用这个方法(我们可以使用这个拦截器对某一特定的动作进行预处理)。如果方法不存在,或是action参数不存在,则继续执行下面的代码。如下面的URL

http://localhost:8080/struts2/test/interceptor.action?action=test

访问上面的url后,拦截器会就会调用拦截器中的test方法,如果这个方法不存在,则调用invocation.invoke方法,invoke方法和Servlet过滤器中调用FilterChain.doFilter方法类似,如果在当前拦截器后面还有其他的拦截器,则invoke方法就是调用后面拦截器的intercept方法,否则,invoke会调用Action类的execute方法(或其他的执行方法)。

下面我们先来实现一个拦截器的父类ActionInterceptor。这个类主要实现了根据action参数值来调用方法的功能,代码如下:


 

package interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import javax.servlet.http.*;
import org.apache.struts2.*;

public class ActionInterceptor implements Interceptor
{
    
protected final String INVOKE = "##invoke";
   
    
public void destroy()
    {
        System.out.println(
"destroy");
    }

    
public void init()
    {
        System.out.println(
"init");
    }

    
public String intercept(ActionInvocation invocationthrows Exception
    {    
        HttpServletRequest request 
= ServletActionContext.getRequest();
        String action 
= request.getParameter("action");
        System.out.println(
this.hashCode());
        
if (action != null)
        {
            
try
            {
                java.lang.reflect.Method method 
= this.getClass().getMethod(action);
                String result 
= (String)method.invoke(this);
                
if(result != null)
                {
                    
if(!result.equals(INVOKE))
                        
return result;
                }
                
else
                    
return null;
            }
            
catch (Exception e)
            {
            }
        }
        
return invocation.invoke();
    }
}


 

从上面代码中的intercept方法可以看出,在调用action所指定的方法后,来判断返回值。可能发生的情况有三种:

1.        返回值为null,执行return null

2.        返回值为INVOKE,执行return invockation.invoke()

3.        其他情况,执行return result result表示指定方法的返回值,如上面代码所示。

    在实现完上面的拦截器父类后,任何继承于ActionInterceptor类的拦截器都可以自动根据action的参数值调用自身的相应方法。下面我们来实现一个拥有两个动作方法testprint的拦截器类。代码如下:


package interceptor;

import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;

public class MultiMethodInterceptor extends ActionInterceptor
{
    
public String test() throws Exception
    {
        HttpServletResponse response 
= ServletActionContext.getResponse();
        response.getWriter().println(
"invoke test");
        
return this.INVOKE;
    }

    
public String print() throws Exception
    {
        HttpServletResponse response 
= ServletActionContext.getResponse();
        response.getWriter().println(
"invoke print");

        
return null;
    }
}


 

test方法返回了INVOKE,因此,在执行完这个方法后,Struts2会接着调用其他拦截器的intercept方法或Action类的execute方法。而print方法在执行完后,只是返回了null,而不再调用其他的方法了,也就是访问如下的url时,动作的execute方法将不会执行:

    http://localhost:8080/struts2/test/ddd.action?action=print

    下面我们来实现一个Action类,代码如下:

package action;

import org.apache.struts2.*;
import com.opensymphony.xwork2.ActionSupport;

public class InterceptorAction extends ActionSupport
{
    
public String abcd() throws Exception
    {
        ServletActionContext.getResponse().getWriter()
                .println(
"invoke abcd");
        
return null;
    }
}


 

在这个Action类中,只有一个abcd方法,实际上,这个方法相当于execute方法,在下面会设置动作的method属性为abcd。下面我们来在struts.xml中定义拦截器类和动作,代码如下:


 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"
>
<struts>
    
<package name="demo" extends="struts-default" namespace="/test">
        
<interceptors>
            
<interceptor name="method" class="interceptor.MultiMethodInterceptor" />
                
<interceptor-stack name="methodStack">
                    
<interceptor-ref name="method" />
                    
<interceptor-ref name="defaultStack" />
                
</interceptor-stack>
        
</interceptors>

        
<action name="interceptor" class="action.InterceptorAction" method="abcd">
            
<interceptor-ref name="methodStack" />
        
</action>
    
</package>
</struts>


 

在配置上面的methodStack拦截器时要注意,最好在后面引用defaultStack,否则很多通过拦截器提供的功能将失去。

OK,现在访问如下的URL

    http://localhost:8080/struts2/test/ddd.action?action=test

在浏览器中将会出现如下的字符串:

    invoke test

invoke abcd

而如果访问http://localhost:8080/struts2/test/ddd.action?action=print,将会只出现如下的字符串:

    invoke print

大家可以看出,访问这个url时并没有调用abcd方法。如果随便指定的action值的话,则只调用abcd方法,如访问http://localhost:8080/struts2/test/ddd.action?action=aaa,就只会输出invoke abcd


二、拦截器的参数

   
我们在使用很多Struts2内置的拦截器时会发现有很多拦截器都带参数,当然。我们自己做的拦截器也可以加上同样的参数。有两个参数比较常用,这两个参数是includeMethodsexcludeMethods,其中includeMethods指定了拦截器要调用的Action类的执行方法(默认是execute),也就是说,只有在includeMethods中指定的方法才会被Struts2调用,而excludeMethods恰恰相反,在这个参数中指定的执行方法不会被Struts2调用。如果有多个方法,中间用逗号(,)分隔。在Struts2中提供了一个抽象类来处理这两个参数。这个类如下:

com.opensymphony.xwork2.interceptor.MethodFilterInterceptor

   
如有继承于这个类的拦截器类都会自动处理includeMethodsexcludeMethods参数,如下面的拦截器类所示:

package interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.*;

public class MyFilterInterceptor extends MethodFilterInterceptor
{
    
private String name;
    
public String getName()
    {
        
return name;
    }
    
public void setName(String name)
    {
        
this.name = name;
    }
    @Override
    
protected String doIntercept(ActionInvocation invocationthrows Exception
    {
        System.out.println(
"doIntercept");
        System.out.println(name);
        
return invocation.invoke();
    }
}


    MethodFilterInterceptor的子类需要实现doIntercept方法(相当于Interceptorintercept方法),如上面代码所示。在上面的代码中还有一个name属性,是为了读取拦截器的name属性而设置的,如下面的配置代码所示:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"
>
<struts>
    
<package name="demo" extends="struts-default" namespace="/test">
        
<interceptors>
            
<interceptor name="method" class="interceptor.MultiMethodInterceptor" />
                
<interceptor name="filter"
                    class
="interceptor.MyFilterInterceptor">
                    
<param name="includeMethods">abcd</param>
                    
<param name="name">中国</param>
                
</interceptor>
                
<interceptor-stack name="methodStack">
                    
<interceptor-ref name="method" />
                    
<interceptor-ref name="filter" />
                    
<interceptor-ref name="defaultStack" />
                
</interceptor-stack>
        
</interceptors>

        
<action name="interceptor" class="action.InterceptorAction" method="abcd">
            
<interceptor-ref name="methodStack" />
        
</action>
    
</package>
</struts>


    再次访问http://localhost:8080/struts2/test/ddd.action?action=test, Struts2就会调用MyFilterInterceptordoIntercept方法来输出name属性值。如果将上面的includeMethods参数值中的abcd去掉,则Action类的abcd方法不会被执行。

posted @ 2008-12-28 22:37 redcoatjk 阅读(344) | 评论 (0)编辑 收藏
 
 WebWork截获Action请求,在Action执行之前或之后调用拦截器方法。这样,可以用插拔的方式将功能注入Action中。WebWork框架的很多功能都是以拦截器的形式提供出来。例如:参数组装,验证,国际化,文件上传等等。

1. 一个拦截器就是在xwork.xml文件中定义的一个无状态Java类,它至少要实现XWork的com.opensymphony.xwork.interceptor.Interceptor接口。代码如下:

public interface Interceptor extends Serializable {

void destroy();

void init();

String intercept(ActionInvocation invocation) throws Exception;

}

2. 实现Interceptor接口的拦截器,代码部分在intercept方法中实现。在intercept方法中,可以直接返回一个Result字符串,这样整个执行直接“短路”,这时Action的execute方法也不会执行(一般很少会这么用)。所以,一般都会在这个方法里调用参数对象invocation的invoke方法,并返回这个方法执行的结果。这样会持续执行后面的拦截器方法以及Action的execute方法等。

3. 大部分的时候,拦截器直接继承WebWork的抽象类 com.opensymphony.xwork.interceptor.AroundInterceptor就可以了。这时,需要实现它的before 和after方法。Before方法会在Action执行之前调用,after方法在Action执行之后调用。

4. 拦截器的执行顺序。我们可将多个拦截器放一起组装成一个拦截器栈。这样拦截器会按照栈的顺序由上而下执行before方法,所有before方法执行结束,再执行Action的方法,执行Result的方法,再返回执行结果,最后再从下而上执行拦截器的after方法


5. 拦截器的过滤功能。我们通常会在应用中使用一个通用的定义多个拦截器的拦截器栈。但有些Action方法在调用的时候,不需要要其中的部分拦截器。这时,我们就可以使用拦截器过滤功能。如果拦截器要拥有过滤功能,必须实现抽象类 com.opensymphony.xwork.interceptor.MethodFilterInterceptor。这样,拦截器在定义的时候或者在Action引用拦截器栈的时候,我们就可以指定哪些Action方法是需要过滤的,哪些Action是不需要过滤的。
  拦截器可以将任意代码包含在调用栈中活动执行前或之后, 它可以极大的简化代码同时提供增强代码复用能力. XWork和WebWork的许多特性多作为拦截器实现, 可以和你自己的拦截器一起通过外部配置任意指定顺序并配置在任意活动上.
  换言之, 当你访问一个*.action的地址, WebWork的 class="monospaced">ServletDispatcher执行一个活动调用. 在活动执行前, 这一调用可以被另一个对象截取, 这个对象就称为拦截器. 要想在一个活动执行之前(或之后)设置一个拦截器, 只需正确配置xwork.xml, 如下例所示:

拦截器配置:
<action name="formProcessing" class="lesson04_01_01.FormProcessingAction">
<result name="input" type="dispatcher">ex01-index.jsp</result>
<result name="success" type="dispatcher">ex01-success.jsp</result>
<interceptor-ref name="validationWorkflowStack" />
</action>
  名为formProcessing的Action使用了validationWorkflowStack. 它是一个截取器栈, 栈中按照截取器的执行顺序进行组织. 这个截取器栈定义在webwork-default.xml, 这样我们需要做的就是在活动配置的<interceptor-ref />或包配置中的<default-interceptor-ref />中声明, 就像:

拦截器配置:
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-1.0.dtd">


<xwork>
<!-- Include webwork defaults (from WebWork JAR). -->
<include file="webwork-default.xml" />

<!-- Configuration for the default package. -->
<package name="default" extends="webwork-default">
<!-- Default interceptor stack. -->
<default-interceptor-ref name="defaultStack" />

<!-- Action: HelloWebWorldAction. -->
<action name="helloWebWorld" class="lesson03.HelloWebWorldAction">
<result name="success" type="dispatcher">ex01-success.jsp</result>
</action>
</package>
</xwork>

-------------------------------------------------------
写个示例,实现在interceptor中判断当前时间,返回问候语句,比如“Good afternoon”
1.xwork_interceptor.xml
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">

<xwork>

<package name="hello1" extends="webwork-default">
<!-- 在action和result code之间建立了联系-->
<interceptors>
<interceptor name="greetingInterceptor" class="com.vstsoft.action.GreetingInterceptor" />
</interceptors>
<action name="greeting" class="com.vstsoft.action.GreetingAction">
<interceptor-ref name="greetingInterceptor" />
<result name="success">/success.jsp</result>
<result name="input">/error.jsp</result>
</action>
</package>
</xwork>
2.GreetingAction
package com.vstsoft.action;

import com.opensymphony.xwork.Action;

public class GreetingAction implements Action {

public String execute(){
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println(i);
}
return SUCCESS;//INPUT对应于xwork.xml中的resultcode='success'
}

}
3.GreetingInterceptor
package com.vstsoft.action;

import java.util.Calendar;
import com.opensymphony.xwork.interceptor.Interceptor;
import com.opensymphony.xwork.ActionInvocation;

public class GreetingInterceptor implements Interceptor {
public void init() { }
public void destroy() { }
public String intercept(ActionInvocation invocation) throws Exception {
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
String greeting = (hour < 6) ? "Good evening" :
((hour < 12) ? "Good morning":
((hour < 18) ? "Good afternoon": "Good evening"));

invocation.getInvocationContext().getSession().put("greeting", greeting);

String result = invocation.invoke();

return result;
}
}
4.success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="ww" uri="/webwork"%>
<%String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>


<html>
<head>
<title>Say Hello</title>
</head>
<body>
<font color="red"><%=session.getAttribute("greeting")%></red>
</body>
</html>
posted @ 2008-12-28 22:16 redcoatjk 阅读(713) | 评论 (0)编辑 收藏
 

摘自http://dev.rdxx.com/NET/NETOther/2005-7/27/120335366.shtml
WML教程1:从第一个实际应用全面了解WML

学习自然语言的最好方法就是溶入相应的语言环境在交流中学习,学习一种编程语言的最好方法就是看例程。为了帮助大家建立WML应用的第一印象,所以请大家先看第一个例子:

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
 <template>
   <do type="prev" label="back">
     <prev/>
     <!--provide a button you can clink to back a step-->
   </do>
 </template>
<card id="friends" title="Hot link">
 <p>
   <a href="Sina'>http://wap.sian.com.cn/">Sina WAP</a><br/>
   <a href="#nextcard">Next Card</a>
 </p>
</card>
<card id="nextcard">
 <p>
  this is the second card.
 </p>
</card>
</wml>

通过以上示例大家应该了解到以下内容:

1、语法:WML的语法与HTML相似,仍然是一种标记语言,而且延续了xML语法规则

2、元素:在XML和WML 语言中,语言的基本元素称之为"标签"
  标签必须被 < 和 > 括起来。
  大多数标签都包括"起""止"两部分,例如:<p>…</p>
  某些特殊标签可以只有一个标签,但是必须有结束标记,例如:<prev/>

3、属性:XML语言的标签可以包含很多属性,给标签提供必要的附加信息
  属性内容通常在起始标签内使用
  属性只作为参数为标签提供必要的信息,不会被浏览器显示
  属性的值需要被引号括起来,可以是单引号或者双引号,引号可以成对嵌套使用
  例如:<card id="friends" title="Hot link">

4、注释
  注释内容是方便制作者阅读源代码,不会被浏览器显示
  WML不支持注释嵌套
  例如:<!-- This is a comment. -->

5、文档结构
  WML文档是由Card和Deck构成的,一个Deck是一个或多个Card的集合。在得到客户终端的请求之后,WML从网络上把Deck发送到客户的浏览器,访问者可以浏览Deck内包含的所有Card,而不必从网上单独下载每一个Card。

其他一些示例中没有涉及到的基本内容:

6、大小写敏感
  无论是标签元素还是属性内容都是大小写敏感的,这一点继承了XML的严格特性,任何大小写错误都可能导致访问错误,这是WML制作者必须注意的问题。


7、躲避语法检查的方法-CDATA
  CDATA内的数据内容都会被当作文本来处理,从而避开语法检查,直接作为文本显示。
  示例:
  < ! [ CDATA [ this ia <b> a test ] ] >
  显示结果为
  this ia <b> a test

8、定义变量
  WML可以使用变量供浏览器和Script使用,通过在Deck中的一个Card上设置变量,其他Card不必重新设置就可以直接调用。

  变量的语法如下:
  $identifier
  $(identifier)
  $(identifier:conversion)

  如果变量内容包含空格就需要用圆括号括起来。由于变量在语法中有最高的优先级,包含变量声明字符的字符串会被当作变量对待,所以如果要显示$,就一定要连续使用两个$。

  示例:
  <p> Your account has $$15.00 in it.</p>
  显示结果为:Your account has $15.00 in it

  XML是一种语法非常严格的语言,WML也继承了这种规则,任何地不规范语法都会导致错误。

posted @ 2008-12-16 17:29 redcoatjk 阅读(242) | 评论 (0)编辑 收藏
 
    这个笔记做的不错.摘自javaeye:  http://chineseoa.javaeye.com/blog/127282 作者chineseoa
---------------------------------------------------------------
第4章: 实现WebWork action

action是WebWork编程的核心部分,负责:
. 封装和传递数据;
. 逻辑处理

一.  Action接口

     要求action实现com.opensymphony.xwork.Action接口,该接口有一唯一方法需要实现:

     String execute() throws Exception;

     该接口内置很多静态属性,可作为execute()方法的返回值;

二.  ActionSupport基类

     该类包含了action能够提供的许多可选服务的默认实现(实现了很多可选的接口),让你更容易地开发自己的action类:

     1. action验证:(com.opensymphony.xwork.Validateable接口)

        该接口有一个唯一的方法,在该方法中可放入验证代码:

        void validate()

        该方法会被合适的intereceptor调用。调用过程如下:
        . 执行validate()方法;
  . 如校验action出错(有错误消息增加至action),返回INPUT,否则执行这个action;

        示例:

    @Override
    public void validate() {
        if(name==null||name.trim().length()<1) {
            addFieldError("name","Invalid name, please input again!");
        }
        if(password==null||password.trim().length()<1) {
            addFieldError("password","Invalid password, please input again!");
        }       
    }

     2. 显示错误信息:(com.opensymphony.xwork.ValidationAware接口)

        收集错误信息并将这些信息显示给用户。错误信息能够依据class(action->actionErrors属性)级别
        (放入一个Collection->fieldErrors属性)和字段级别(放入一个Map)进行收集。

        一些常见方法:

        void     addActionError(String anErrorMessage)
                Add an Action-level error message to this Action.
        void     addActionMessage(String aMessage)
                Add an Action-level message to this Action.
        void     addFieldError(String fieldName, String errorMessage)        

     3. 获取用户的locale: (public interface LocaleProvider接口)

        该接口中拥有唯一的一个方法:

Locale getLocale();

        通过该方法获得客户端的语言和地区;

     4. 显示本地化文本:(com.opensymphony.xwork.TextProvider接口)

        该接口基本上由多个不同参数的getText()方法组成,getText()方法用于查找本地化信息文本。
        默认情况下, 本地化信息存于和action同一个包下,同名的.properties结尾的文本。

        示例:

        cho4.LoginAction.java
        ---------------------------------------------------------------------------
    @Override
    public void validate() {
        if(name==null||name.trim().length()<1) {
            addFieldError("name",getText("invalid.name"));     //通过getText获取本地化信息
        }
        if(password==null||password.trim().length()<1) {
            addFieldError("password",getText("invalid.password"));
        }       
    }

        ch04/LoginAction.properties
        ---------------------------------------------------------------------------
        invalid.name=Invalid name, please input again\!
        invalid.password=Invalid password, please input again\!

三.  使用ModelDriven action

     1. ???????????????????????/

 
四.  通过ActionContext访问数据

     1. 获得HttpSession;

        方法一:
        Map session = ActionContext.getContext().getSession();
        session.put("user",user);



        方法二:(推荐使用)
        public class Login extends ActionSupport implements SessionAware {
               Map session;
    
               public void setSession(Map session) {
                      this.session = session;
               }
               ...
        }

        实现SessionAware接口,该接口告知WebWork在action执行之前需要设置session Map。

     2. 访问request和response

        方法一:
        ActionContext ctx = ActionContext.getContext();
        HttpServletRequest req = ctx.get(ServletActionContext.HTTP_REQUEST);
        HttpSession sessio = req.getSession();

        方法二:
        HttpServletRequest req = ServletActionContext.getRequest(); 
        HttpSession sessio = req.getSession();

        方法三:(推荐使用)
        public class Login extends ActionSupport implements ServletRequestAware {
               HttpServletRequest req;
    
               public void setServletRequest(HttpServletRequest req) {
                      this.req = req;
               }
               ...
        }     

五.  处理文件上传

     1. 使用request封装类访问上传文件

        使用MultiPartRequestWrapper对象,该对象会从request的余下部分中把文件正确地解析出来。

        a. JSP页面

      
       
         
      

        b. action

        public class FileUpload extends ActionSupport implements ServletRequestAware {
            private HttpServletRequest req;
           
            @Override
            public String execute() {
                MultiPartRequestWrapper wrapper = (MultiPartRequestWrapper)req;
                File doc = null;
                try {
                                        //获得File对象
                    doc = wrapper.getFiles("doc")[0];
//获得内容类型
                    System.out.println("content type: "+ wrapper.getContentTypes("doc")[0]);
                                        //获得初始文件名
                    System.out.println("name: "+wrapper.getFileSystemNames("doc")[0]);
                }catch(Exception e) {
                    e.printStackTrace();
                }finally {
                    doc.delete();
                }
                return SUCCESS;
            }

            public HttpServletRequest getReq() {
                return req;
            }

            public void setServletRequest(HttpServletRequest req) {
                this.req = req;
            }   
           
        }

     2. 自动文件上传

        WebWork提供了一个interceptor: FileUploadInterceptor, 它封装了上传文件的获取和清理工作:
        . 自动获得request对象;
        . 自动获得request封装对象;
        . 自动清除File对象;

        FileUploadInterceptor在webwork-default.xml中自动设好。通过使用FileUploadInterceptor, 可以把
        上传的文件(以及内容类型和文件名)看做是一般的表单参数。

        html表单的input元素命名为doc, File字段也必须命名为doc,如多个文件则类型是 File[];
        内容类型命名为[element]ContentType, 如多个文件则类型是 String[];
        文件名命名为[element]FileName, 如多个文件则类型是 String[];

    import java.io.File;
    import com.opensymphony.xwork.ActionSupport;

    public class FileUpload extends ActionSupport {
        private File doc;
        private String docContentType;
        private String docFileName;
       
        @Override
        public String execute() {
            System.out.println("doc: "+doc.getName());
            System.out.println("docContentType: "+docContentType);
            System.out.println("docFileName: "+docFileName);
            return SUCCESS;
        }

        public void setDoc(File doc) {
            this.doc = doc;
        }

        public void setDocContentType(String docContentType) {
            this.docContentType = docContentType;
        }

        public void setDocFileName(String docFileName) {
            this.docFileName = docFileName;
        }   
    }     


     3. 配置设定

        webwork.properties中有三个属性可以对上传文件的选项进行设定:

        . webwork.multipart.parser: 定义底层的多部分 request 的解析器,可选值为 pell, cos和jakarta.
                                    默认值为pell, 建议选用jakarta。
        . webwork.multipart.saveDir: 上传文件WebWork临时保存目录。如没设定,则存于javax.servlet.context.tempdir
                                    系统属性指定的目录中;
        . webwork.multipart.maxSize: 上传文件的大小上限,以字节为单位。默认值为2097152.
posted @ 2008-12-16 11:39 redcoatjk 阅读(247) | 评论 (0)编辑 收藏
 
OGNL使用小结(一)
最近一直使用struts2,表现层采用JSP,用的struts2标签,支持OGNLOGNL中的# $ %使用场景:
1、“#”主要有三种用途:
  • 访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:
    名称 作用 例子
    parameters 包含当前HTTP请求参数的Map #parameters.id[0]作用相当于request.getParameter("id")
    request 包含当前HttpServletRequest的属性(attribute)的Map #request.userName相当于request.getAttribute("userName")
    session 包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName")
    application 包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName")
    attr 用于按request > session > application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止
  • 用于过滤和投影(projecting)集合,如books.{?#this.price<100};
  • 构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
2、“%”符号的用途
在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:
[size=13px]<hr />
<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']"
/></p>
<p><s:url value="%{#foobar['foo1']}"
/></p>
清单6 演示%用途的代码片段
3、“$”有两个主要的用途
  • 用于在国际化资源文件中,引用OGNL表达式,例子请参考《在Struts 2.0中国际化(i18n)您的应用程序
  • 在Struts 2配置文件中,引用OGNL表达式,如 <action name="AddPhoto" class="addPhoto">
                <interceptor-ref name="fileUploadStack" />
                <result type="redirect">ListPhotos.action?albumId=${albumId}</result>
     </action>

OGNL使用小结(二)

1、OGNL除了支持所有的Java操作符外,还支持以下几种:
   1、逗号,
     与C语言中的逗号操作符类似。
   2、花括号{}
     用于创建列表,元素之间用逗号分隔。
   3、in和not in
     用于判断一个值是否在集合中。
2、访问静态方法和静态字段
  @class@method(args)     //调用静态方法
  @class@field         //调用静态字段
  其中class必须给出完整的类名(包括包名),如果省略class,那么默认使用的类是java.util.Math,如:
  @@min(5,3)
  @@max(5,3)
  @@PI
3、索引访问
  OGNL支持多种索引方式的访问。
   1、数组和列表索引
     在OGNL中,数组和列表可以大致看成是一样的。
     如:array[0]、list[0]。表达式:{’zhangsan’,'lisi’,'wangwu’}[1]等。
   2、JavaBean的索引属性
     要使用索引属性,需要提供两对setter和getter方法,一对用于数组,一对用于数组中的元素。
     如:有一个索引属性interest,它的getter和setter如下
     public String[] interest;
     public String[] getInterest(){ return interest;}
     public void setInterest(String[] interest){ this.interest=interest;}
     public String getInterest(int i){ return interest[i]}
     public void setInterest(int i, String newInterest){ interest[i]=newInterest;}
     对于表达式interest[2],OGNL可以正确解释这个表达式,调用getInterest(2)方法。如果是设置的情况下,会调用setInterest(2,value)方法。
   3、OGNL对象的索引属性
     JavaBean的索引属性只能使用整型作为索引,OGNL扩展了索引属性的概念,可以使用任意的对象来作为索引。
4、对集合进行操作
  1、创建集合:
     创建列表
       使用花括号将元素包含起来,元素之间使用逗号分隔。如{’zhangsan’,'lisi’,'wangwu’}
     创建数组
       OGNL中创建数组与Java语言中创建数组类似。
     创建Map
       Map使用特殊的语法来创建 #{”key”:value, ……}
       如果想指定创建的Map类型,可以在左花括号前指定Map实现类的类名。如:
       #@java.util.LinkedHashMap@{”key”:”value”,….}
       Map通过key来访问,如map["key"]或map.key。
  2、投影
     OGNL提供了一种简单的方式在一个集合中对每一个元素闻调用相同的方法,或者抽取相同的属性,并将结果保存为一个新的集合,称之为投影。
     假如employees是一个包含了employee对象的列表,那么
       #employees.{name}将返回所有雇员的名字的列表。
     在投影期间,使用#this变量来引用迭代中的当前元素。
       如:objects.{#this instanceof String? #this: #this.toString()}
  3、选择
     OGNL提供了一种简单的方式来使用表达式从集合中选择某些元素,并将结果保存到新的集合中,称为选择。
      如#employees.{?#this.salary>3000}
      将返回薪水大于3000的所有雇员的列表。
       #employees.{^#this.salary>3000}
      将返回第一个薪水大于3000的雇员的列表。
       #employees.{$#this.salary>3000}
      将返回最后一个薪水大于3000的雇员的列表。
5、lambda表达式
  lambda表达式的语法是:   :[...]。OGNL中的lambda表达式只能使用一个参数,这个参数通过#this引用。
  如:
   #fact= :[ #this<=1 ? 1 : #this* #fact ( #this-1) ], #fact(30)
   #fib= :[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)
posted @ 2008-12-15 16:39 redcoatjk 阅读(3519) | 评论 (0)编辑 收藏
 

摘自http://blog.csdn.net/liuyf8688/archive/2008/02/17/2100759.aspx
1、Act.java 

//接口类
public interface Act {
    
public void go();
}

 2、Chinese.java

//实体类
public class Chinese {

    
public void getAge() {
        System.out.println(
"entity class.");
    }


}

3、Person.java

//抽象类可以实现接口,并且可以继承实体类。
public abstract class Person extends Chinese implements Act {

    
public void run() {
        System.out.println(
"run");
    }


    
public abstract void jump();

}


4、Test.java
public class Test extends Person {

    
// Act中的方法
    public void go() {
        System.out.println(
"go");
    }


    
// Person中的方法
    public void jump() {
        System.out.println(
"jump");
    }


    
public static void main(String[] args) {
        Test t 
= new Test();
        t.go();
        t.run();
        t.jump();
        t.getAge(); 
// Chinese中的方法
    }

}
posted @ 2008-12-15 15:52 redcoatjk 阅读(411) | 评论 (0)编辑 收藏
 
JSTL中的EL语言是个灾难,很难想象一个EL表达式不能去取复杂的属性还不支持显示的方法调用,类似list.get(20).getName(locale)。而且这个灾难还非常流行,唉。

幸好OGNL很好的解决了这个问题,而且在Tapestry,Webwork等框架下均已经内嵌了支持。

表达式分类:
1. 访问属性:如,user.name
2. 访问接口/方法:如,user.verify()
3. 数组游标,如:users[2]

常量:
字符串、字符:一般使用单引号,也可以使用双引号,支持所有的转义字符
数值:可以使用B表示BigDecimal,H表示BigInteger(不是十六进制)
布尔:true或者false关键字
空指针:null关键字

访问属性:
user.name

索引位置:
OGNL提供了一个很有趣的例子:array["length"],其中array作为根对象,调用其length方法是采用字符串的形式来进行的,等同于array["len" + "gth"],当然等价array.length。

带索引的属性:
someProperty[2] 可以用来getSomeProperty(2) or setSomeProperty(2, value),查找顺序先找关联数组的方法,再找带索引参数的方法如下:
public PropertyType[] getPropertyName()
public void setPropertyName(PropertyType[] anArray)
public PropertyType getPropertyName(int index)
public void setPropertyName(int index, PropertyType value)

OGNl扩展的带索引的属性:
public PropertyType getPropertyName(IndexType index)
public void setPropertyName(IndexType index, PropertyType value)
比如:session.attribute("bar")

调用方法:
method( ensureLoaded(), name ),用逗号分隔参数,由于逗号在OGNL语言中有别的用处,所以在语法上需要小心。

变量引用:
使用#标注:#var = 99
this是OGNL语言中内置的对象,用来表示当前表达式的变量。listeners.size().(#this > 100? 2*#this : 20+#this)

括号:
method( (ensureLoaded(), name) )这个表达式是调用一个参数的method方法。

链接表达式:
再看一次method( (ensureLoaded(), name) )
其中ensureLoaded(), name的意思是:调用ensureLoaded方法,再调用#this.name,method方法的参数是name。

集合构建
{ null,"Untitled" }——说明:最好看成数组,因为集合一般不会支持空元素。

集合投射
listeners.{delegate}返回所有listener对象的delegate对象。
objects.{ #this instanceof String ? #this : #this.toString()}转变为字符串对象

集合选择:
listeners.{? #this instanceof ActionListener}——注意?的位置
返回单个对象,首个:objects.{^ #this instanceof String },最后一个:objects.{$ #this instanceof String }

创建对象:
需要显式的指定java package,如:new java.util.ArrayList()

静态方法、成员:
@class@method(args),@class@field,同样要指定class的全路径

表达式赋值:
如果是AST,OGNL直接解析,如果是其他对象,则将其转化对字符串交给AST解析。

简单的功能表达式:
如递归表达式:#fact = :[#this<=1? 1 : #this*#fact(#this-1)], #fact(30H)

集合的特殊属性
Collection:size, isEmpty
List:iterator
Map:keys, values
注意:someMap["size"]可能得到someMap中对应key为"size"的对象, 而someMap.size得到someMap的大小.
Set:iterator
Iterator:next,hasNext
Enumeration:next,hasNext,nextElement,hasMoreElements

与JAVA的不同之处
逗号:类似C的语法,逗号用于分割两个不同的表达式
花括号:用于创建list,元素可以为空
in和not in:用于集合的contains测试
posted @ 2008-12-15 15:10 redcoatjk 阅读(310) | 评论 (0)编辑 收藏
仅列出标题
共8页: 上一页 1 2 3 4 5 6 7 8 下一页 
CALENDER
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(3)

随笔分类(22)

随笔档案(76)

文章分类(12)

文章档案(17)

搜索

  •  

积分与排名

  • 积分 - 249961
  • 排名 - 227

最新评论

评论排行榜


Powered By: 博客园
模板提供沪江博客