??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品无码永久中文字幕,亚洲七七久久精品中文国产,亚洲最大AV网站在线观看http://www.tkk7.com/aojilee/category/5108.htmlzh-cnFri, 02 Mar 2007 06:52:08 GMTFri, 02 Mar 2007 06:52:08 GMT60利用反射机制实现XML-RPChttp://www.tkk7.com/aojilee/articles/47763.html奥吉奥吉Wed, 24 May 2006 02:08:00 GMThttp://www.tkk7.com/aojilee/articles/47763.htmlhttp://www.tkk7.com/aojilee/comments/47763.htmlhttp://www.tkk7.com/aojilee/articles/47763.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/47763.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/47763.html 动态回调基于XML的远E过E调?/span>

摘要

Java 反射机制Z用XML-RPCQXML-based Remote Procedure Call,ZXML的远E过E调用)q程q程调用提供了一U简便又高效的实现方法,q种Ҏ(gu)隐蔽掉了一些远E过E调用过E中的复杂操作。在q篇文章里, Stephan Maier展示l你如何从反包中用一些类d装XML-RPC去调用远E接口:Proxyc,Arrayc? 和BeanInfocR这文章也要讨论q种Ҏ(gu)的多重实现和在RMIQRemote Method InvocationQ远E方法调用)中可反射Ҏ(gu)的用?br />
因ؓ它作E方法调用的一个简单协议,Z偶尔xZXML的远E过E调用(XML-RPCQ。它易于使用Q又着可以q用的实?Apache XML-RPC?br />
如果是一个小应用E序或应用程序中使用有限数量的远E过E,那么不应该趋向于正式地定义远E过E的名字和方法声明,取而代之,应该直接使用XML-RPC。甚臻I应用E序规模增大和远E接口数量增加,可发现对远E方法和数据对象必要的约定必定是一U莫名的一致。在q篇文章里,展CJava提供的所有需要去实现的定义远E接口和讉Kq程Ҏ(gu)Q过E,使用Java接口定义的过E签名,和用XML-RPC的远E过E调?q种调用把一个通信信道的两侧封装成仅仅是接口和相对的数据对象?br />
本文也展C当l定的描q远E过E和数据的Java接口构徏?JavaBean规范一_可以使用Java反射机制Q把反射机制和JavaBean整合使用可以透明地调用远E方法,L地在XML-RPC数据cd和Java数据cd之间q行转换?br />

实际中隐藏复杂性是个好的事情。无需_不是所有的复杂性能或者应该被隐藏。针对分布式计算Q这个观点已l在“分布式计算W记”有了个著名的论著。(Sun MicrosystemsQ?994.11Q。本文中展现的框架不Ҏ(gu)去隐藏分布式计算的复杂性,但这个框架帮助用者减在调用q程q程时的J琐。简单点_本文只讨论ƈ发远E过E调用,热心的读者可以自己去研究觳皆d痰饔谩?

XML-RPC可以被看作RPC跨SOAP协议的一个简化。扩展点_本文所讨论的这个简易框架必被认ؓSOAP引擎的简化版本,像Axis。本文主要以教学位目标:希望展示在目前的XML-RPC框架上层是怎样通过反射来徏立一个简化的XML-RPC引擎。这些帮助读者理解相g更复杂的其他协议的引擎的内部实现机理Q或怎样应用反射去解军_杂问题。一个RPC引擎必须在SOAP引擎可实现的环境中用,好比中间g控g不可用,那么应用E序׃能通过Web服务器发布给q大用户。Roy Miller’s “XML-RPC Java ~程”对q个作了很好的解释?br />
在本文中Q用XML-RPC的Apachelgd装这个框架。读者不需奥区知道XML-RPCQ也不需要理解Apache XML-RPC框架Q就是只有一个基本的了解都能使你理解下面的讲q。本文重Ҏ(gu)在框架内部精的q作机理Q但不涉及协议的l节?br />
版权声明QQ何获得Matrix授权的网站,转蝲时请务必保留以下作者信息和链接
作?steven_guo(作者的blog:http://blog.matrix.org.cn/page/steven_guo)
原文:http://www.matrix.org.cn/resource/article/44/44437_XML-RPC.html
关键?XML-RPC;Reflective

消除?fn)?/span>

有时候,我更喜欢非传l的~程。谈到这点,我必M你确信,我不是一个L破旧?fn)俗的hQ我不反对好的编E习(fn)惯;恰恰与此完全相反。“非传统”在q里主要表明我喜Ƣ去避免E序中到处的定义字符Ԍ而且q些代码可以在可~程的API里定义。考虑下面代码片断?br />
代码1. 调用q程q程
Vector paras = new Vector();
paras.add("Herbert");
Object result = client.execute("app.PersonHome.getName", paras);


代码1展示了通过Apzche XML-RPC的实现如何调用远E过E。可以注意到Q用者需要去指导q程q程和传递到q程Ҏ(gu)中参数的名字。也必须知道q程q程q回的对象类型。除非你已经实现了一个类去验证你使用的这些名字(app.PersonHome ?getNameQ是否正,那么你局需要去查找q些名字和声明,通常q些信息保存在文本文件或帔R接口中(一个接口提供所有参数名字)。也可能攄?Javadoc中适当的地斏V大家可以发玎ͼq种U定有造成q行旉误的隐?zhn)Q因些错误只在运行时才能昄出来Q而在~译时不能显现?br />
现在Q对比考虑下面一D代码:

代码2调用q程q程
Person person = ((PersonHome)Invocator.getProxy(PersonHome.class)).getPerson("Herbert");


在这Q我们调用Invocatorcȝ静态方法getProxy()L索PersonHome接口的实现。在q个接口里,可以调用getPerson()Q得到Person对象?br />
代码2相对于代?是一个较z的方式。在代码2U,使用z的定义在接口中的方法,在接口里可以把可用的Ҏ(gu)Q方法声明,q回cd都一起定义。因Z需要强制{换对象,所以也是类型安全。因Z需要额外的像Vectorcȝ构造函敎ͼ代码可读性也较好?br />
而且Q如果你使用了一个功能强大的IDEQ代码助手将|列所有可用的Ҏ(gu)和他们的实现。因此,在类型安全远E方法调用上从IDE获得支持?br />
我必L认,没有规范我们不能作Q何事。我们必d持(除非我们准备接受高昂的成本和复杂化)的一个规则就是:假设所有的数据对象都遵从JavaBean规范。简单地_对象的属性操作必通过getter/setterҎ(gu)。在我们讨论把XML-RPC数据l构转换成Java对象Ӟq个假设的重要性将昄出来?br />
把所有数据对象遵从JavaBean规约是比在XML-RPC应用E序中的规约更高U一些,因ؓ后者是一个通用规范。它也是所有Java E序员的的通用规范。在本文l尾部分Q我讨论XML-RPC的限Ӟq要其他一些有用的规范Q而且可以更好的让你理解那些限制?br />
随后的部分,一h览Invocatorcȝ实现和一个提供框枉信信道的一个本地服务器?br />
实现调用

让我们首先看看提供一个接口实现的Ҏ(gu)?br />
代码3  创徏代理
public static Object getProxy(Class ifType) {
   if (!ifType.isInterface()) {
      throw new AssertionError("Type must be an interface");
   }
   return Proxy.newProxyInstance(Invocator.class.getClassLoader(),
      new Class[]{ifType}, new XMLRPCInvocationHandler(ifType));
}


所有的实现逻辑隐藏在了Proxy.newProxyInstance()Ҏ(gu)中。ProxycMJava1.3开始已l是Java Reflection包的一部分。经由newProxyInstance()Ҏ(gu)Q一些列的接口可以自动被实现。当Ӟ一个proxycM知道怎样处理Ҏ(gu)调用。因此,它必L调用传送给一个合适的处理??一个实?java.lang.reflect.InvocationHandlercȝ作业中。在q里Q我已经选择取调用这个实现类 XMLRPCInvocationHandler。InvocationHandler接口定义单一的方法,如代?所C?br />
代码4 InvocationHandler
public interface InvocationHandler {
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}


当一个proxy实例调用了一个方法,proxy实例传递这个方法和他的参数叨处理器cȝinvokeQ)Ҏ(gu)Q同时要识别它。让我们看看处理器的实现Q?br />
代码5 InvocationHandler
private static class XMLRPCInvocationHandler implements InvocationHandler {

   private Class type;

   public XMLRPCInvocationHandler(Class ifType) {
      this.type = ifType;
   }

   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      XmlRpcClient client = getClient(); // Get a reference to the client
      Vector paras = null; // This will hold the list of parameters
      if (args != null){
         paras = new Vector();
         for (int i = 0; i < args.length; i++) {
               paras.add(ValueConverter.convertFromType(args[i]));
            }
         }
         else{
            paras = new Vector(); // The vector holding the parameters must not be null
         }
         Class retType = method.getReturnType();
         Object ret = client.execute(type.getName() + '.' + method.getName(), paras);
         return ValueConverter.convertToType(ret, retType);
   }
}


在创E中QXMLRPCInvocationHandler是有远E接口的实现cR我们用这个类仅仅是ؓ了获得远E接口的名字和可供调用的Ҏ(gu)名。可以观察到q程Ҏ(gu)的调用L动态的Q我们既不需要在桩类里调用方法,也不需要从外部获得M接口的信息?br />
ClientcMgetClient()Ҏ(gu)获得:

代码6. 获得clientc?br />
protected static XmlRpcClient getClient() throws MalformedURLException {
   return new XmlRpcClient("localhost", 8080);
}


q里Q我们能使用Apache XML-RPC去获得处理远E调用的ClientcR可以看到我们返回一个Clientc而没有考虑我们所有调用的Ҏ(gu)的接口?br />
更重要的代码是在ValueConvertercM用静态方法调用。在那个Ҏ(gu)里反提供了q种方式的魅力所在。在下面部分我们分析q些代码Q?br />
XML-RPC 和Java之间的{?/span>

q部分解释XML-RPC架构的核心。这个框枉要作两g事:转换Java对对象成能被XML-RPC所理解的数据结构和一个反向的转换处理?br />
我开始展C如何把一个Java对象转换被XML-RPC理解的数据结构:

代码7. Java ?XML-RPC转换
public static Object convertFromType(Object obj) throws IllegalArgumentException, 
      IllegalAccessException, InvocationTargetException, IntrospectionException {
   if (obj == null) {
      return null;

   }
   Class type = obj.getClass();
   if (type.equals(Integer.class)
      || type.equals(Double.class)
      || type.equals(Boolean.class)
      || type.equals(String.class)
      || type.equals(Date.class)) {
      return obj;
   else if (type.isArray() && type.getComponentType().equals(byte.class)) {
      return obj;
   }
   else if (type.isArray()) {
      int length = Array.getLength(obj);
      Vector res = new Vector();
      for (int i = 0; i < length; i++) {
         res.add(convertFromType(Array.get(obj, i)));
      }
      return res;
   }
   else {
      Hashtable res = new Hashtable();
      BeanInfo info = Introspector.getBeanInfo(type, Object.class);
      PropertyDescriptor[] props = info.getPropertyDescriptors();
      for (int i = 0; i < props.length; i++) {
         String propName = props[i].getName();
         Object value = null;
         value = convertFromType(props[i].getReadMethod().invoke(obj, null));
         if (value != null) res.put(propName, value);
      }
      return res;
   }
}


转换Java对对象成能被XML-RPC所理解的数据结构,需要考虑如上面代码展C的5U情况:
1. NullQ如果要转换的对象是Null|我们必须q回一个Null?br />2. 原始cdQ如果要转换的对象是原始cdQ或q些原始cȝ包装c)-- int、double、Boolean、string或dateQ?那么p回该对象卛_?br />3. base64Q如果对象是一个字节数l,那么可以认ؓq个数组是base64cd数据。只需把数l直接返回即可?br />4. ArrayQ如果对象不是一个字节数l,我们能从Java Reflection包中使用Array工具c获得数l长度。用这个长度|在一个@环中Ll的每个数据单元。把每个数据单元的数据传入ValueConverter装q入一个Vector中?br />5Q复杂类型:如果对象不是上面所叙述的类型,我们可以假定它是一个JavaBean ?在程序开始我们可以设立这么一个共同遵守的假定原则。我们把属性插入HashTable内。要讉Kq些属性,可以使用JavaBean框架自D的机Ӟ使用工具cIntrospector去获得封装在BeanInfo对象里的信息。特别,我们可以循环讉KPropertyDescriptor对象数组获得 Bean的属性。从q样一个属性描q器里,可以索到属性的名字Q这些名字也是访问HashTable的键。我们通过d性描q器获得q些键|例如属性倹{?br />
看到如此Ҏ(gu)C用JavaBean框架从Bean里提取信息。我不需要知道所惌{换的cdQ只需知道q个Bean卛_。这个假设是我们的框架完地q行其俩的先x件?br />
现在Q让我们来看看相反的转换 ?把XML-RPCl构数据转换为Java对象Q?br />
代码8. 从XML-RPC转换到Java对象
public static Object convertToType(Object object, Class type) throws IllegalArgumentException, 
      IllegalAccessException, InvocationTargetException, IntrospectionException, InstantiationException {
   if (type.equals(int.class)
      || type.equals(double.class)
      || type.equals(boolean.class)
      || type.equals(String.class)
      || type.equals(Date.class)) {
      return object;
   }
   else if (type.isArray() && type.getComponentType().equals(byte.class)) {
      return object;
   }
   else if (type.isArray()) {
      int length = ((Vector) object).size();
      Class compType = type.getComponentType();
      Object res = Array.newInstance(compType, length);
      for (int i = 0; i < length; i++) {
         Object value = ((Vector) object).get(i);
         Array.set(res, i, convertToType(value, compType));
      }
      return res;
   }
   else {
      Object res = type.newInstance();
      BeanInfo info = Introspector.getBeanInfo(type, Object.class);
      PropertyDescriptor[] props = info.getPropertyDescriptors();
      for (int i = 0; i < props.length; i++) {
         String propName = props[i].getName();
         if (((Hashtable) object).containsKey(propName)) {
            Class propType = props[i].getPropertyType();
            props[i].getWriteMethod().
               invoke(res, new Object[]
                  { convertToType(((Hashtable) object).get(propName), propType)});
         }
      }
      return res;
   }


}


转换成一个Javacd需要更多的了解q个我们所要{换的|我们也必M解那个D转换到这个Javacd。这个解释了在代??convertToType()Ҏ(gu)的第二个参数的存在性。知道了cdQ我们用Java的自举机Ӟ把XML-RPC数据cd转换成Javacd。下面的列表展示了完成多U{换的U定Q?br />1QNullQXML-RPC不传递空|q个限制在稍后又更详l说明。我们不需要考虑q种情况?br />2Q原始类型:如果对象是原始类型(或原始类型的包装c)- int, double, Boolean, string, ?date Q那么我们可以把对象本社q回Q作为XML-RPC可以识别的原始类型?br />3Qbase64Q如果对象是一个二q制数组Q可以认Z表一个base64cd的实例。我们可以再ơ把数组本书q回?br />4Q数l:如果对象是一个数l,但不是一个二q制数组Q我们首先要在数l类定所存项目的cd。我们可以根据对象断定类型。可以?getComponentTypeQ)。下一步,我们使用Array工具cd于给定的lgcd创徏一个新的数l。我们可以用Array工具cd@环遍历数l,讄各个域,使用ValueConveter从每个数l项中获得正的倹{在XML-RPC框架中,可以发现我们所期望的数l数据结构是一?Vector?br />5.复杂cdQ如果一个对象不是上面所q的cdQ我们假讑֮是一个JavaBeanQ依照我们的基本U定Q。再ơ,我们使用 Introspector查找Bean的属性描q器Q用属性描q器讄实际的属性通过讉KwriteQ)Ҏ(gu)。需要注意的是,框架l了我们一个储存在 HashTable的属性。当Ӟ属性类型可能是复杂cdQ我们必M用ValueConverter去获得正的Java对象?br />
理解了数据{换的U定Q我们可以看看处理服务是如何实现的?br />
实现服务处理

已经解释了一个远E服务是如何被调用和在XML-RPC和Java对象之间转换时包含什么。我了解了所qh不解的问题的剩下部分Q在一个服务端如何处理h

q里是一个ؓq篇文章所实现单的服务器实C码:

代码9. 服务?br />
public class Server {
   private WebServer webserver = null;

   public void start() {
      webserver = new WebServer(8080);
      webserver.addHandler
          (PersonHome.class.getName(),
         new Handler(PersonHome.class,
         new PersonHomeImpl()));
      webserver.setParanoid(false);
      webserver.start();
   }

   public void stop() {
         webserver.shutdown();
         webserver = null;
   }

   private static class Handler implements XmlRpcHandler {
      private Object instance;
      private Class type;

      public Handler(Class ifType, Object impl) {
         if (!ifType.isInterface()) {
            throw new AssertionError("Type must be an interface");
         }
         if (!ifType.isAssignableFrom(impl.getClass())) {
            throw new AssertionError("Handler must implement interface");
         }
         this.type = ifType;
         this.instance = impl;
      }

      public Object execute(String method, Vector arguments) throws Exception {
         String mName = method.substring(method.lastIndexOf('.') + 1);
         Method[] methods = type.getMethods();
         for (int i = 0; i < methods.length; i++) {
            if (methods[i].getName().equals(mName)){
               try {
                  Object[] args = new Object[arguments.size()];
                  for (int j = 0; j < args.length; j++) {
                     args[j] = ValueConverter.convertToType
                         (arguments.get(j), methods[i].getParameterTypes()[j]);

                  }
                  return ValueConverter.convertFromType(methods[i].invoke(instance,args));
               }
               catch (Exception e) {
                  if (e.getCause() instanceof XmlRpcException){
                     throw (XmlRpcException)e.getCause();
                  }
                  else{
                     throw new XmlRpcException(-1, e.getMessage());
                  }
               }
            }
         }
         throw new NoSuchMethodException(mName);
      }
   }

   public static void main(String[] args){
      Server server = new Server();
      System.out.println("Starting server...");
      server.start();
      try {
         Thread.sleep(30000);
      }
      catch (InterruptedException e) {
         e.printStackTrace();      
      }
      System.out.println("Stopping server...");
      server.stop();
   }
}


关键cLApacheXML-RPC包中的WebServercR黑体字代码展示了我们主要的需求:我们必须注册一个服务句柄。这个句柄经?XmlRpcHandler接口定义Q这个接口就像代理机制中InvocationHandler接口Q有个方法对应方法调用的委派。在q里Q叫?executeQ)Ҏ(gu)Q有着和InvocationHandler接口相同的实现精髓。最大的不同是,我们L册联pL口和他的实现的一个句柄,不需要提供服务接口的实现Q一桩程序Ş式)。然而,在服务器里,我们需要定义那块代码负责处理到来的h。最后,可以看到Q通过循环遍历接口Ҏ(gu)调用服务Ҏ(gu)Q我们用普通的方式dC争取的方法。这里,我们不依靠标准的自DJavaBeanQ因为服务方法不是仅仅有setter和getterҎ(gu)?br />
后记

在这个部分,主要讨论在先前讨Z所处想的以下问题。我看到XML-RPC协议和这个文章所q的框架的局限性,但我也考虑q些方式的一定先q性?br />
局限?/b>
XML-RPC是一个简单协议,很明昑֮不能Z表面向对象系l特色的q程q程调用实现可编EAPI。特别地Q这样一个API不支持以下的一些实玎ͼ
&#8226;l承QXML-RPC没能携带充的信息决定那U类型可以沿着l承的层U结构传递。在q程q程调用和对象传递参C都存在这U情c因此,x所有的cMؓfinalcd是一个好的编E习(fn)?br />& #8226;重蝲QXML-RPC不允许方法重载。依据这条规则,可以重蝲那些有原始类型声明的Ҏ(gu)Q但实际q个选择是不能满的。当我们需要从Ҏ(gu)的声明去推断l构cd是,我们不允?dng)R载。我仅仅允许同一个方法有不同参数个数q种情况除向Q因为所有的Ҏ(gu)在远E过E调用期间是可用的。我么有以这个方式实玎ͼ而是使用了不同的Ҏ(gu)名。注意:Web服务在这斚w也不提供更多的灵zL。即使灵zL个那个靠的框架Axis也对重蝲有限制?br />&#8226; 集合QXML-RPC不允许结合类型出现。和重蝲相同的原因,我们必须从被l定的集合类型推断集合中目的类型,q是不可能的。(JDK1.5之前版本Q。取而代之,我们使用数组Q可以查询组件类型。虽ӞW(xu)eb服务在远E方法调用方面比XML-RPC更强大,但更多的意见是反对用集合类型。参?“Web Services Programming Tips and Tricks: Use Collection Types with SOAP and JAX-RPC?Russell Butek and Richard Scheuerle, JrQ?002.4Q?br />& #8226;Null|XML-RPC不支持空倹{这可能是这个协议中最令h尬的瑕疵,因ؓq个意味着在数l里不能保存I倹{在XML-RPC有过关于Null值得提议Q但大多数的实现不支持Null倹{无需去说Q如果通信q接的两边均是与JavaE序交互Q通过手动方式在消息里加入一些元数据可以克服q个~点。而且Q这意味着滥用协议Q不是一个好的徏议?br />
序列化控?/b>
序列化在下面的场景中出现。特别地Q文中所提议的框架在发现属性去自动序列化。有Ӟ你可以在序列化中L一些属性值得传递?br />
设想一个Person对象引用多个不同cd的Address对象。特别地Q这些Address对象之一是邮件地址Q而其他对象在其他的上下文环境中有意义。你可能希望通过PersoncȝPerson.getMailingAddress()Ҏ(gu)可以获得邮g地址Q这样增Z的PersoncR标准的自D机制看到的是一个新的属?mailingAddressQ这个属性在序列化的时候可使用众多的地址列表中初始化。在q种情况下,一个对应的 Person.setMailingAddress()Ҏ(gu)执行这L(fng)操作Q不地址序列化的序如何Q反序列化将q回一个对应的AddresscR当Ӟ你的Ҏ(gu)应该如何序列化是无关竟要的,但即使你写的Ҏ(gu)是正的Q在其程序接口编E的有些人可能不清楚你想的是什么,增加了发生问题的可能性。在M情况下,你应该容忍两ơ序列化邮g地址?br />
但是Q这里有个帮助,Introspector可能告诉你,要查找一个类的属性时要去使用反射Q而要使用l定的信息。这些信息可以在BeanInfoc里扑ֈQ如果你的类名是MyClassQ那么你的BeanInfocd该叫?MyClassBeanInfo。BeanInfocd该在MyClasscȝ相同包里Q或者在BeanInfo的搜索\径里。搜索\径可以在 Introspector里设|。作Z个BeanInfoc,应该提供如下的属性:

代码10. BeanInfo 例子 1
public class MyClassBeanInfo extends SimpleBeanInfo {
   public PropertyDescriptor[] getPropertyDescriptors() {
      try {

         BeanInfo superInfo = Introspector.getBeanInfo(MyClass.class.getSuperclass());
         List list = new ArrayList();
         for (int i = 0; i < superInfo.getPropertyDescriptors().length; i++) {
            list.add(superInfo.getPropertyDescriptors()[i]);
         }
         //
         list.add(new PropertyDescriptor("myProperty", MyClass.class));
         //
         return (PropertyDescriptor[])list.toArray(new PropertyDescriptor[list.size()]);
      } catch (IntrospectionException e) {
         return null;
      }
   }
}


getPropertyDescriptors()Ҏ(gu)必须q回属性描q器所代表的属性。首先,在你的超c里增加q个属性,增加q个你希望发布的q个属性到你的c里Q如_体部分昄?br />
q是一个严重的~陷Q上面的提议包含了很多固定代码,而这些是~程的时候应量避免的。正好,增加的这些被序列化的属性是比罗列显C些属性能更好的运作。当Ӟ一个方式是使用Introspector通过反射机制调用Introspector.getBeanInfo(MyClass.class, Introspector.IGNORE_ALL_BEANINFO)获得所有的属性。你能增加一个过滤器在你的返回结果时。这U方式看h象如下展C:

代码11. BeanInfo例子 2
public class MyClassBeanInfo extends SimpleBeanInfo {
   public PropertyDescriptor[] getPropertyDescriptors() {
      try {
            BeanInfo infoByReflection = Introspector.getBeanInfo(MyClass.class,
            Introspector.IGNORE_ALL_BEANINFO); PropetyDescriptor allProperies =
            infoByReflection.getPropertyDescriptors();
            return filter(allProperies);
      } catch (IntrospectionException e) {
         return null;

      }
   }

   protected PropertyDescriptor[] filter(PropertyDescriptor[] props){
      // Remove properties which must not be exposed
   }
}


一个好的方法是使用接口定义语言QIDLQ构造一个框Ӟq样允许你手动去产生Bean和扩阿占属性和Ҏ(gu)。这个生器负责提供通过IDLqo属性的BeanInfocRl看一个这样实现的例子?br />
增加?/b>
当我们隐藏了实际的传送机Ӟ很容易在收到和发送的消息中增加信息。假若我们需要在每个q程Ҏ(gu)调用中传送Session信息。这个信息就可以在调用者那里增加上Q处理者把它作为第一个参敎ͼ包装所有必需的信息成一个适当德BeanQ。在其他的调用里Q这些信息能从参数Vector里删除,在方法调用里分别处理。在文后的资源引用中扑ֈ更多的可用代码,可以更好的用这个框架?br />
其他语言
如果你正视弱点,它可能变成支炏VXML-RPC的简易导致了上面所描述的限制。然而,XML-RPC已有了多U语a的实玎ͼ例如RubyQPythonQ或函数性怨言 Haskell。不是所有的语言支持面向对象pȝ中所支持的承,不是所有的语言支持重蝲。有些语aQ例如HaskellQ有灉|的列表类型,从Java 语言的角度看Q它的这U类型介于数l和列表之间。因此,XML-RPC内在的限制它适宜于跨语言通信?br />
当选择XML-RPC作ؓ跨越 Java和其他语a的桥梁时Q你仍可以用这个框Ӟ但你仅仅能在与Java通信的一侧用。而且Q可以扩展这个框架去覆盖其他语言。例如,你可以用其他语言重写q个框架Q增加对Java接口和数据对象与其他语言对应对象之间转换的支持。另外的方式Q我已在上面暗示q,是写一个编译器把IDL的适当形式转换到其他多U语a的Ş式,Java是其中之一。在下面Q我l出一个例子?br />
无需M诉说Q这U方式扩展文中所提的框架是比框架更手的事Q但它们协同运行?br />
删除或替换XML-RPC实现
一个有效率的系l更愿意避免使用XML-RPC中间框架Q反而通过把XML-RPC的XML数据直接转换成适当的对象。你可能认ؓQ在潜藏在后面的接口里的抽象Ҏ(gu)调用能用多种XML-RPC实现。当我认Z需d什么事Ӟ那就不能实现q些功能。再者,你是被吸引,而去适应q个框架Q以满你的需要?br />
q程Ҏ(gu)调用
伴随着J2SE1.5QRMI用代理机制。将不再需要用RMI~译器生桩c(除非你要与一些旧的系l协作)。因此,如果不能夹在一个桩c,那么q程对象的桩p认ؓ是一个java.lang.reflect.Proxy实例?br />
接口定义语言
d要查看大两Bean实现规约和XML-RPC限制的麻烦,正如上面所qͼ是避免写接口和Bean。取而代之,适用适当的IDLd建它们。这L(fng)语言看v来就像下面的代码Q?br />
代码12 . IDL
module partner;

exception NoPartnerException < 123 : "No partner found" >;


struct Partner {
   int id;
   string name;
   int age;
   date birthday;
};

interface PartnerHome {
   Partner getPartner(int id) throws NoPartnerException;
   Partner[] findPartner(string name, date bday) throws NoPartnerException;
};


ZIDL~写一个解析器和代码生器Q得交叉语a通信更加易?br />
ȝ

在这片文章里Q展CZ如何使用Java反射机制透明地包装经由XML-RPC实现q程Ҏ(gu)调用。已l重点展CZ已经整合在Proxyc,Arraycd IntrospectorcM的实现机制。基于这些工L(fng)Q一个可适用于多U用途的q程Ҏ(gu)调用的中间g框架已经实构造出来?br />
关于作?/b>
Stephan Maier 拥有数学博士学位Q超q五q的软g开发经验。他也是一位职业生涯中艺术U的导师。除了编E,他喜Ƣ唱歌和q动。现在,他在~写一个编译器Q这个编译器可以单地转换IDL定义到其他适当的数据结构和其他语言的远E接口,例如JavaQRubyQ或PythonQ在q些接口里潜在的调用协议都是XML-RPC?br />
参考资?/b>
Matrix:http://www.matrix.org.cn
Javaworld:http://www.Javaworld.com
"Web Services Programming Tips and Tricks: Roundtrip Issues in Java Coding Conventions," Russell Butek, Richard Scheuerle, Jr. (developerWorks, April 2004):
http://www-106.ibm.com/developerworks/xml/library/ws-tip-roundtrip2.html
"XML-RPC in Java Programming," Roy Miller (developerWorks, January 2004):
http://www-106.ibm.com/developerworks/library/j-xmlrpc.html
"Web Services Programming Tips and Tricks: Use Collection Types with SOAP and JAX-RPC" by Andre Tost and Tony Cowan (developerWorks, May 2004):
http://www-106.ibm.com/developerworks/library/ws-tip-coding.html?ca=dnx-420
"A Note on Distributed Computing," Jim Waldo, Geoff Wyant, Ann Wollrath, and Sam Kendall (Sun 1994):
http://research.sun.com/techrep/1994/smli_tr-94-29.pdf
XML-RPC homepage:
http://www.xmlrpc.com
Apache XML-RPC implementation:
http://ws.apache.org/xmlrpc

奥吉 2006-05-24 10:08 发表评论
]]>
JAVA反射(reflection)基本概念(译和ȝ)http://www.tkk7.com/aojilee/articles/47733.html奥吉奥吉Tue, 23 May 2006 16:17:00 GMThttp://www.tkk7.com/aojilee/articles/47733.htmlhttp://www.tkk7.com/aojilee/comments/47733.htmlhttp://www.tkk7.com/aojilee/articles/47733.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/47733.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/47733.html

奥吉 2006-05-24 00:17 发表评论
]]>
什么是AspectJ http://www.tkk7.com/aojilee/articles/46652.html奥吉奥吉Wed, 17 May 2006 09:00:00 GMThttp://www.tkk7.com/aojilee/articles/46652.htmlhttp://www.tkk7.com/aojilee/comments/46652.htmlhttp://www.tkk7.com/aojilee/articles/46652.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/46652.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/46652.html  What is AspectJ
|上出现了很多讲解AspectJ的资料,但大多是从讲解AspectJ语法开?本文从另一个角度讲解AspectJQ作者着重介l了AspectJ的设计思\和运行原理?

1. ?/span>
Aspect Oriented Programming (AOP)是近来一个比较热门的话题?

AspectJ是AOP的Java语言的实玎ͼ获得了JavaE序员的q泛x?

关于AspectJ和AOP的具体资料,请从下列链接中查找:

http://www.eclipse.org/aspectj/
http://www.parc.com/research/csl/projects/aspectj/
http://aosd.net/

|上出现了很多讲解AspectJ的资料,但大多是从讲解AspectJ语法开始,然后讲解如何应用AspectJQ如何分Y件开发过E的不同斚wQAspectQ?-LogQSessionQAuthentication and AuthorizationQTransactionQ等{?

初次接触AspectJ的读者看到这些资料(或者语法手册)Q会感到AspectJ有些秘。他们想知道QAspectJ是如何做到这些的QAspectJ是怎样工作的?AspectJ需要特D的q行环境吗?

本文从另一个角度讲解AspectJQ本文从讲解AspectJ的设计思\、运行原理入手,回答上述问题?

本文讲解的主要内容,按照概念的重要程度,排列如下Q?

  1. AspectJ是一个代码生成工PCode GeneratorQ?
  2. AspectJ语法是用来定义代码生成规则的语法。?zhn)如果使用qJava Compiler Compiler (JavaCC)Q?zhn)会发玎ͼ两者的代码生成规则的理忉|人相伹{?
  3. AspectJ有自q语法~译工具Q编译的l果是Java Class文gQ运行的时候,classpath需要包含AspectJ的一个jar文gQRuntime libQ?
  4. AspectJ和xDoclet的比较。AspectJ和EJB Descriptor的比较?

本文的原则是Q只l讲其他资料没有讲到的东西,其他资料讲过的东西,不讲或略讌Ӏ以节省|络资源Q更Z节省大家宝贵的时间。J

2QAspect Oriented Programming (AOP)
本节单介lAOP的概念,解释我们Z么需要AOP?

AOP是Object Oriented ProgrammingQOOPQ的补充?/p>

OOP能够很好地解军_象的数据和封装的问题Q却不能很好的解决AspectQ?斚w"Q分ȝ问题。下面D例具体说明?/p>

比如Q我们有一个BankQ银行)cRBank有两个方法,depositQ存钱)和withdrawQ取钱)?

cdҎ(gu)的定义如下:

														
Code 2.1 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 增加account账户的钱敎ͼq回账户里当前的钱数
}

public float withdraw(AccountInfo account, float money){
  // 减少account账户的钱敎ͼq回取出的钱?
}
};

												

q两个方法涉及到用户的̎戯金等重要信息Q必要非常心Q所以编写完上面的商业逻辑之后Q项目负责h又提Z新的要求--lBankcȝ每个重要Ҏ(gu)加上安全认证Ҏ(gu)?

于是Q我们不得不分别在上面的两个Ҏ(gu)中加入安全认证的代码?

cdҎ(gu)的定义如下:Q新增加的代码用不同的背景标出)

														
Code 2.2 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 验证account是否为合法用?
  // 增加account账户的钱敎ͼq回账户里当前的钱数
}

public float withdraw(AccountInfo account, float money){
  // 验证account是否为合法用?
  // 减少account账户的钱敎ͼq回取出的钱?
}
};

												

q两个方法都需要操作数据库Qؓ了保持数据完整性,目负责人又提出了新的要?-lBankcȝ每个操作数据库的Ҏ(gu)加上事务控制?

于是Q我们不得不分别在上面的两个Ҏ(gu)中加入安全认证的代码?

cdҎ(gu)的定义如下:Q新增加的代码用不同的背景标出)

														
Code 2.3 Bank.java
class Bank{
public float deposit(AccountInfo account, float money){
  // 验证account是否为合法用?
  // Begin Transaction
  // 增加account账户的钱敎ͼq回账户里当前的钱数
  // End Transaction
}

public float withdraw(AccountInfo account, float money){
  // 验证account是否为合法用?
  // Begin Transaction
  // 减少account账户的钱敎ͼq回取出的钱?
  // End Transaction
}
};

												

我们看到Q这些与商业逻辑无关的重复代码遍布在整个E序中。实际的工程目中涉及到的类和函敎ͼq远不止两个。如何解册U问题?

我们首先来看看OOP能否解决q个问题?

我们利用Design Pattern的Template PatternQ可以抽Z个框Ӟ改变上面的例子的整个设计l构?

cdҎ(gu)的定义如下:

														
Code 2.4 Base.java
abstract class Base{
public float importantMethod(AccountInfo account, float money){
  // 验证account是否为合法用?
  // Begin Transaction
  
  float result = yourBusiness(account, money)

  // End Transaction
  return result;	
}

protected abstract float yourBusiness(AccountInfo account, float money);
};

Code 2.5 BankDeposit.java
class BankDeposit extends Base{ 
protected float yourBusiness(AccountInfo account, float money){
  // 增加account账户的钱敎ͼq回账户里当前的钱数
}
};

Code 2.6 BankWithdraw.java
class BankWithdraw extends Base{ 
protected float yourBusiness(AccountInfo account, float money){
  // 减少account账户的钱敎ͼq回取出的钱?
}
};

												

q里我们用一U很勉强的方法实C认证和事务代码的重用。而且Q有心的读者可能会注意刎ͼq种Ҏ(gu)的前提是Q强制所有的Ҏ(gu)都遵守同L(fng)signature?

如果有一个{账方法transfer(AccountInfo giver, AccountInfo receiver, float money)Q由于transferҎ(gu)的signature不同于yourBusiness的signatureQ这个方法无法用上面的框架?

q个例子中提到的认证Q事务等斚wQ就是AOP所兛_的Aspect?

AOP是Z解决q种问题而出现的。AOP的目的就?-Separation of Aspects (or Separation of Concerns).

下面的章节,解释EJB DescriptorQAspectJQxDoclet{工具如何解决Separation of Aspects的问题?

3QEJB Descriptor
如果我们使用EJB实现上面的例子,Bankcd以作Z个Stateless Session Bean实现?

在Bank的代码中只用考虑商业逻辑Q不用考虑认证和事务等斚w?

认证和事务等斚w在EJB Descriptor中定义,由EJB Container提供q些斚w的实现?

我们来看一下,如何使用EJB Descriptor描述上面的例子?

EJB Descriptor包括一个ejb-jar.xml文g。ejb-jar.xml文g包含两大部分Qenterprise-beans?assembly-descriptor部分。enterprise-beans部分包含EJB的定?-JNDI NameQEJB Home, Interface, Bean Class Path{;assembly-descriptor部分包括配置信息的定?-安全角色Q事务控制等{?

下面l出上面例子对应的模拟EJB Descriptor?

														
<ejb-jar>
<enterprise-beans>
  <session>
     <ejb-name>Bank</ejb-name>
     ?
     <ejb-class>example.Bank</ejb-class>
     <session-type>Stateless</session-type>
     <transaction-type>Container</transaction-type>
<security-role-ref>
<role-name>bank-account</role-name>
</security-role-ref>
  </session>
</enterprise-beans>

<assembly-descriptor>
  <security-role>
    <role-name>bank-account</role-name>
  </security-role>

<method-permission>
<role-name>employee</role-name>
<method>
<ejb-name>Bank</ejb-name>
<method-name>deposit</method-name>
</method>
<method>
<ejb-name>Bank</ejb-name>
<method-name>withdraw</method-name>
</method>
</method-permission>

<container-transaction>
<method>
<ejb-name>Bank</ejb-name>
<method-name>deposit</method-name>
</method>
<method>
<ejb-name>Bank</ejb-name>
<method-name>withdraw</method-name>
</method>

<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

												

本文后面会讲到如何用AspectJ实现上例中的Separation of Aspects?

读者可以比较一下AspectJ语法和EJB Descriptor定义之间的对应关pR?

两者都提供了类名、方法名的匹配规则,能够把类的方法映到认证Q事务等AspectQ方面)?

4QAspectJ
q一节我们来看看AspectJ如何实现上例中的Separation of Aspects?

使用AspectJQ我们不用对原有的代码做M修改Q就可以Z码提供不同的AspectQ方面)--比如Q认证,事务{?

我们只需要提供两个不同的Aspect--认证Aspect和事务Aspect?

														
Code 4.1 AuthAspect.java
aspect AuthAspect{
  pointcut bankMethods() : execution (* Bank.deposit(?) || execution (* Bank. withdraw (?);

  Object around(): bankMethods(){
  // 验证account是否为合法用?

  return proceed();
  }
};

Code 4.2 TransactionAspect.java
aspect TransactionAspect{
  pointcut bankMethods() : execution(* Bank.deposit(?) || execution (* Bank. withdraw (?);

  Object around(): bankMethods(){
  // Begin Transaction
  Object result = proceed();
  // End Transaction
  return result;
  }
};

												

如果(zhn)暂时不能理解这D代码,没有关系Q后面会讲到Q这些aspect的定义,不过是定义了一些代码生成规则?

我们用AspectJ~译器编译B(ti)ank文g和含有aspect的这个文Ӟ出来的结果就是带有安全认证和事务处理的BankcR编译出来的q个 Bankc调用了AspectJ Runtime LibQ所以,如果你要q行q个Bankc,你需要把AspectJ Runtime Lib讄在你的classpath里面?

我们来看看,AspectJ~译器ؓ我们做了什么事情?

  1. 首先QAspectJ从文件列表里取出所有的文g名,然后dq些文gQ进行分析?
  2. AspectJ发现一些文件含有aspect的定义,在这个例子里Q就是AuthAspect和TransactionAspect的定义;q些aspect是代码生成规则?
  3. AspectJҎ(gu)q些aspect代码生成规则Q修Ҏ(gu)加你的源代码。在q个例子里,是修改dBank文g?
  4. AspectJdAuthAspect的定义,发现了一个pointcut--bankMethods()Q这个pointcut的定义是execution(* Bank.deposit(?) || execution(* Bank. withdraw (?)Q表C所有对Bankcȝdeposit和withdrawҎ(gu)的执行点?
  5. AspectJl箋dAuthAspect的定义,发现了一个around()Q这在AspectJ中叫做AdviceQ我不明白ؓ什么叫q个名字Q不q没关系Q我们只要知道它是干什么的p了。Advice允许你在某个cȝҎ(gu)的调用之前或调用之后Q加入另外的代码。Code 4.1所CZ码中的around()? // 验证account是否为合法用?部分Q就是要加入的代码。这D代码要加在哪里呢?around()后面跟了一个pointcut-- bankMethods()。根据这个pointcutQAspectJ会把q段代码加入到Bank.deposit和Bank.withdraw两个Ҏ(gu)的执行之前。达到的效果如同Code 2.2所C?
  6. AspectJdTransactionAspect的定义,象第Q?Q步一P发现了发C一个pointcut--bankMethods()?
  7. AspectJl箋dAuthAspect的定义,发现了一个around()。这ơAspectJ?Begin Transaction"?End Transaction"两段代码加在Bank.deposit和Bank. withdraw两个Ҏ(gu)的执行前后。达到的效果如同Code 2.3所C?

如何验证q一点?(zhn)可以到http://www.eclipse.org/aspectj/下蝲安装AspectJQ编译里面的SampleQ把~译l果反编译一下,可以看到AspetJ自动生成的代码?

我们看到QAspectJ是一U代码自动生成工兗你~写一D通用的代码,比如认证斚w的代码,事务斚w的代码,然后Ҏ(gu)AspectJ语法定义一套代码生成规则(aspect定义Q,AspectJ׃帮助你自动把q段通用代码分布到对应的代码里面去,单快P无遗策?

无独有偶Q一个著名的~译器生成工?-Java Compiler Compiler (JavaCC)Q也采用了非常相似的代码生成机制。JavaCC允许你在语法定义规则文g中,加入你自qJava代码Q用来处理读入的各种语法元素?

AspectJ令你的代码更_Q结构更良好。AspectJ的好处,我就不多说了Q网上很多精彩的文章探讨AspectJ的各U用途?

下面介绍一个著名的代码自动生成?-xDocletQ和EJB DescriptorQAspectJ之间的联pd比较?

5QxDoclet
我们知道QDoclet用来生成JavadocQxDoclet是Doclet的扩展,不仅仅能生成JavadocQ还能够生成源代码和配置信息{?

Doclet和xDoclet的工作原理,是处理源代码中的注释中的tagQ生成相应的信息。这些tag都以@开_你可以自己定义tag和对tag的处理,生成自定义的信息?

Q这里提一下Apache Maven Project。Maven是一UProject Build工具。用Mavenq行理的项目,能够同时生成Javadoc和XRef。XRef是Source Code Cross Reference?

JBoss利用xDoclet为EJB自动生成EJB Home和EJB Object Interface源文Ӟ和EJB Descriptor文g?

在Sourceforge.net上看C个叫做Barter的开源项目,利用xDoclet为类Ҏ(gu)生成AspectJ代码?

h意,EJB Descriptor和AspectJ都是把方斚w面的Aspects集中在一处进行管理,而xDoclet的思想是处理散布在源代码中的各Utag?

xDoclet在生成EJB Descriptor和AspectJ{方面的应用Q正应了中国的一句古?-分久必合Q合久必分?

6Qȝ
开源项目的出现Q打破了软g技术领域的众多壁垒Q推动Y件技术进E的日新月异?

同时Q一些新名词Q新概念也层ZIP令hD~ؕQ无所适从。其实,很多东西都是换汤不换药,我们理解应用q些新技术的时候,要抓住本质,要破除迷信,破除MZؓ的神U感?

举个例子Q现在炒作的很热的一些概念,"Web Service"Q还?Grid Computation"Q网D)Q都是基于原有的各种技术发展出来的。媒体和技术文章不应该Zؓ地制造Q何神U感?

互联|时代的权威Q不是说出来的,而是做出来的?

另外Q围l着一些有前途的新技术,M出现大量?快速入门手?Q有些简直就是对该技术帮助文档的译Q而且Q有隑ֺ的地Ҏ(gu)有翻译出来,大家都明白的地方译得非常详,详尽C没有必要的地步。这U因为市场需求而生的应景时文Q大量地出现在技术文章领域?

W者对本文的期望是Q决不迷信,决不重复。ƈ试图引入一U洁净的,毫无废话的文风。笔者期待一针见血的驳斥和批评?




奥吉 2006-05-17 17:00 发表评论
]]>
jsp防止表单的重复提?/title><link>http://www.tkk7.com/aojilee/articles/45056.html</link><dc:creator>奥吉</dc:creator><author>奥吉</author><pubDate>Mon, 08 May 2006 09:50:00 GMT</pubDate><guid>http://www.tkk7.com/aojilee/articles/45056.html</guid><wfw:comment>http://www.tkk7.com/aojilee/comments/45056.html</wfw:comment><comments>http://www.tkk7.com/aojilee/articles/45056.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/aojilee/comments/commentRss/45056.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/aojilee/services/trackbacks/45056.html</trackback:ping><description><![CDATA[ <p>1.javascript Q设|一个变量,只允许提交一ơ?br /><script language="javascript"> <br />    var checkSubmitFlg = false; <br />        function checkSubmit() { <br />               if (checkSubmitFlg == true) { <br />                   return false; <br />                }<br />               checkSubmitFlg = true; <br />               return true; <br />          }<br />         document.ondblclick = function docondblclick() { <br />                window.event.returnValue = false; <br />          }<br />          document.onclick = function doconclick() { <br />                if (checkSubmitFlg) { <br />                    window.event.returnValue = false; <br />                } <br />          } <br /></script> </p> <p> <br /> </p> <p> <br />  <html:form action="myAction.do" method="post" onsubmit="return checkSubmit();">   </p> <p> <br />  2 q是javascriptQ将提交按钮或者image|ؓdisable   </p> <p>      <html:form action="myAction.do" method="post" onsubmit="getElById('submitInput').disabled = true; return true;">    <br />   <html:image styleId="submitInput" src="images/ok_b.gif" border="0" />  <br />   </html:form></p> <p>      <br />  3 利用struts的同步o牌机制   <br />  利用同步令牌QTokenQ机制来解决Web应用中重复提交的问题QStruts也给Z一个参考实现?<br />  基本原理Q  <br />  服务器端在处理到辄h之前Q会请求中包含的o牌g保存在当前用户会话中的o牌D行比较,看是否匹配。在处理完该h后,且在{复发送给客户端之前,会产生一个新的o牌,该o牌除传给客户端以外,也会用户会话中保存的旧的o牌进行替换。这样如果用户回退到刚才的提交面q再ơ提交的话,客户端传q来的o牌就和服务器端的令牌不一_从而有效地防止了重复提交的发生。  <br />  if (isTokenValid(request, true)) { <br />   // your code here <br />   return mapping.findForward("success"); <br />  } else { <br />   saveToken(request); <br />   return mapping.findForward("submitagain"); <br />  }  <br />  StrutsҎ(gu)用户会话ID和当前系l时间来生成一个唯一Q对于每个会话)令牌的,具体实现可以参考TokenProcessorcM的generateToken()Ҏ(gu)。   <br />  1. //验证事务控制令牌,<html:form >会自动根据session中标识生成一个隐含input代表令牌Q防止两ơ提?<br />  2. 在action中:<br />//<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" <br />   // value="6aa35341f25184fd996c4c918255c3ae"> <br />   if (!isTokenValid(request)) <br />   errors.add(ActionErrors.GLOBAL_ERROR, <br />   new ActionError("error.transaction.token")); <br />   resetToken(request); //删除session中的令牌  </p> <p>   <br />    <br />  3. action有这L(fng)一个方法生成o牌   <br />  <br /> protected String generateToken(HttpServletRequest request) {   <br />   HttpSession session = request.getSession(); <br />   try { <br />     byte id[] = session.getId().getBytes(); <br />     byte now[] = <br />     new Long(System.currentTimeMillis()).toString().getBytes(); <br />     MessageDigest md = MessageDigest.getInstance("MD5"); <br />     md.update(id); <br />     md.update(now); <br />     return (toHex(md.digest())); <br />   } catch (IllegalStateException e) { <br />     return (null); <br />   } catch (NoSuchAlgorithmException e) { <br />     return (null); <br />   } <br />   } </p> <p> </p> <img src ="http://www.tkk7.com/aojilee/aggbug/45056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/aojilee/" target="_blank">奥吉</a> 2006-05-08 17:50 <a href="http://www.tkk7.com/aojilee/articles/45056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>强大的javascript表单验证http://www.tkk7.com/aojilee/articles/45054.html奥吉奥吉Mon, 08 May 2006 09:49:00 GMThttp://www.tkk7.com/aojilee/articles/45054.htmlhttp://www.tkk7.com/aojilee/comments/45054.htmlhttp://www.tkk7.com/aojilee/articles/45054.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/45054.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/45054.html表单的验证一直是|页设计者头痛的问题Q表单验证类 Validator是册个问题而写的,旨在使设计者从UL(fng)复杂的表单验证中解放出来Q把_֊集中于网늚设计和功能上的改q上?


Validator是基于JavaScript技术的伪静态类和对象的自定义属性,可以对网中的表单项输入q行相应的验证,允许同一面中同旉证多个表单,熟?zhn)接口之后也可以对特定的表单项甚至仅仅是某个字W串q行验证。因为是伪静态类Q所以在调用时不需要实例化Q直接以"cd+.语法+属性或Ҏ(gu)?来调用。此外,Validatorq提?U不同的错误提示模式Q以满不同的需要?


Validator目前可实现的验证cd有:
[JavaScript] ?br />Validator目前可实现的验证cd有:
1.是否为空Q?br />2.中文字符Q?br />3.双字节字W?br />4.英文Q?br />5.数字Q?br />6.整数Q?br />7.实数Q?br />8.Email地址Q?br />9.使用HTTP协议的网址Q?br />10.?sh)话L(fng)Q?br />11.货币Q?br />12.手机L(fng)Q?br />13.邮政~码Q?br />14.w䆾证号?1.05增强)Q?br />15.QQL(fng)Q?br />16.日期Q?br />17.W合安全规则的密码;
18.某项的重复|
19.两数的关pL较;
20.判断输入值是否在(n, m)区间Q?br />21.输入字符长度限制(可按字节比较)Q?br />22.对于h相同名称的单选按钮的选中判断Q?br />23.限制h相同名称的多选按钮的选中数目Q?br />24.自定义的正则表达式验证;
25.文g上传格式qo(1.04)
q行环境(客户?Q?
在Windows Server 2003下用IE6.0+SP1和Mozilla Firefox 1.0试通过Q?br />在Lunix RedHat 9下的Netscape试通过Q?


对于客户端的表单验证Q这个基于JavaScript~写的Validator基本上都可以满Q具体可以下载CHM文gQValidator.CHM下蝲
 
 <title>表单验证c?Validator v1.05</title>
 <style>
 body,td{font:normal 12px Verdana;color:#333333}
 input,textarea,select,td{font:normal 12px Verdana;color:#333333;border:1px solid #999999;background:#ffffff}
 table{border-collapse:collapse;}
 td{padding:3px}
 input{height:20;}
 textarea{width:80%;height:50px;overflow:auto;}
 form{display:inline}
 </style>
 <table align="center">
  <form name="theForm" id="demo" method="get" onSubmit="return Validator.Validate(this,2)">
  <tr>
   <td>w䆾证号Q?lt;/td><td><input name="Card" dataType="IdCard" msg="w䆾证号错误"></td>
  </tr>
    <tr>
   <td>真实姓名Q?lt;/td><td><input name="Name" dataType="Chinese" msg="真实姓名只允怸?></td>
  </tr>
  <tr>
   <td>IDQ?lt;/td><td><input name="username" dataType="Username" msg="ID名不W合规定"></td>
  </tr>
  <tr>
   <td>英文名:</td><td><input name="Nick" dataType="English" require="false" msg="英文名只允许英文字母"></td>
  </tr>
    <tr>
   <td>主页Q?lt;/td><td><input name="Homepage" require="false" dataType="Url"   msg="非法的Url"></td>
  </tr>
  <tr>
   <td>密码Q?lt;/td><td><input name="Password" dataType="SafeString"   msg="密码不符合安全规? type="password"></td>
  </tr>
  <tr>
   <td>重复Q?lt;/td><td><input name="Repeat" dataType="Repeat" to="Password" msg="两次输入的密码不一? type="password"></td>
  </tr>
  <tr>
   <td>信箱Q?lt;/td><td><input name="Email" dataType="Email" msg="信箱格式不正?></td>
  </tr>
    <tr>
   <td>信箱Q?lt;/td><td><input name="Email" dataType="Repeat" to="Email" msg="两次输入的信׃一?></td>
  </tr>
  <tr>
   <td>QQQ?lt;/td><td><input name="QQ" require="false" dataType="QQ" msg="QQL(fng)不存?></td>
  </tr>
    <tr>
   <td>w䆾证:</td><td><input name="Card" dataType="IdCard" msg="w䆾证号码不正确"></td>
  </tr>
  <tr>
   <td>q龄Q?lt;/td><td><input name="Year" dataType="Range" msg="q龄必须?8~28之间" min="18" max="28"></td>
  </tr>
   <tr>
   <td>q龄1Q?lt;/td><td><input name="Year1" require="false" dataType="Compare" msg="q龄必须?8以上" to="18" operator="GreaterThanEqual"></td>
  </tr>
   <tr>
   <td>?sh)话Q?lt;/td><td><input name="Phone" require="false" dataType="Phone" msg="?sh)话L(fng)不正?></td>
  </tr>
   <tr>
   <td>手机Q?lt;/td><td><input name="Mobile" require="false" dataType="Mobile" msg="手机L(fng)不正?></td>
  </tr>
     <tr>
   <td>生日Q?lt;/td><td><input name="Birthday" dataType="Date" format="ymd" msg="生日日期不存?></td>
  </tr>
   <tr>
   <td>邮政~码Q?lt;/td><td><input name="Zip" dataType="Custom" regexp="^[1-9]\d{5}$" msg="邮政~码不存?></td>
  </tr>
  <tr>
   <td>邮政~码Q?lt;/td><td><input name="Zip1" dataType="Zip" msg="邮政~码不存?></td>
  </tr>
  <tr>
   <td>操作pȝQ?lt;/td><td><select name="Operation" dataType="Require"  msg="未选择所用操作系l? ><option value="">选择(zhn)所用的操作pȝ</option><option value="Win98">Win98</option><option value="Win2k">Win2k</option><option value="WinXP">WinXP</option></select></td>
  </tr>
  <tr>
   <td>所在省份:</td><td>q东<input name="Province" value="1" type="radio">陕西<input name="Province" value="2" type="radio">江<input name="Province" value="3" type="radio">江西<input name="Province" value="4" type="radio" dataType="Group"  msg="必须选定一个省? ></td>
  </tr>
  <tr>
   <td>爱好Q?lt;/td><td>q动<input name="Favorite" value="1" type="checkbox">上网<input name="Favorite" value="2" type="checkbox">听音?lt;input name="Favorite" value="3" type="checkbox">看书<input name="Favorite" value="4" type="checkbox"" dataType="Group" min="2" max="3"  msg="必须选择2~3U爱?></td>
  </tr>
   <td>自我介绍Q?lt;/td><td><textarea name="Description" dataType="Limit" max="10"  msg="自我介绍内容必须?0个字之内">中文是一个字</textarea></td>
  </tr>
     <td>自传Q?lt;/td><td><textarea name="History" dataType="LimitB" min="3" max="10"  msg="自传内容必须在[3,10]个字节之?>中文是两个字节t</textarea></td>
  </tr>
    <tr>
   <td>相片上传Q?lt;/td><td><input name="up" dataType="Filter" msg="非法的文件格? type="file" accept="jpg, gif, png"></td>
  </tr>
  <tr>
   <td colspan="2"><input name="Submit" type="submit" value="定提交"><input onClick="Validator.Validate(document.getElementById('demo'))" value="验模?" type="button"><input onClick="Validator.Validate(document.getElementById('demo'),2)" value="验模?" type="button"><input onClick="Validator.Validate(document.getElementById('demo'),3)" value="验模?" type="button"></td>
  </tr>
  </form>
 </table>
<script>
  /*************************************************
 Validator v1.05
 code by 我佛(jng)׃h
 wfsr@msn.com
*************************************************/
 Validator = {
 Require : /.+/,
 Email : /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
 Phone : /^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/,
 Mobile : /^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$/,
 Url : /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/,
 IdCard : "this.IsIdCard(value)",
 Currency : /^\d+(\.\d+)?$/,
 Number : /^\d+$/,
 Zip : /^[1-9]\d{5}$/,
 QQ : /^[1-9]\d{4,8}$/,
 Integer : /^[-\+]?\d+$/,
 Double : /^[-\+]?\d+(\.\d+)?$/,
 English : /^[A-Za-z]+$/,
 Chinese :  /^[\u0391-\uFFE5]+$/,
 Username : /^[a-z]\w{3,}$/i,
 UnSafe : /^(([A-Z]*|[a-z]*|\d*|[-_\~!@#\$%\^&\*\.\(\)\[\]\{\}<>\?\\\/\'\"]*)|.{0,5})$|\s/,
 IsSafe : function(str){return !this.UnSafe.test(str);},
 SafeString : "this.IsSafe(value)",
 Filter : "this.DoFilter(value, getAttribute('accept'))",
 Limit : "this.limit(value.length,getAttribute('min'),  getAttribute('max'))",
 LimitB : "this.limit(this.LenB(value), getAttribute('min'), getAttribute('max'))",
 Date : "this.IsDate(value, getAttribute('min'), getAttribute('format'))",
 Repeat : "value == document.getElementsByName(getAttribute('to'))[0].value",
 Range : "getAttribute('min') < (value|0) && (value|0) < getAttribute('max')",
 Compare : "this.compare(value,getAttribute('operator'),getAttribute('to'))",
 Custom : "this.Exec(value, getAttribute('regexp'))",
 Group : "this.MustChecked(getAttribute('name'), getAttribute('min'), getAttribute('max'))",
 ErrorItem : [document.forms[0]],
 ErrorMessage : ["以下原因D提交p|Q\t\t\t\t"],
 Validate : function(theForm, mode){
  var obj = theForm || event.srcElement;
  var count = obj.elements.length;
  this.ErrorMessage.length = 1;
  this.ErrorItem.length = 1;
  this.ErrorItem[0] = obj;
  for(var i=0;i<count;i++){
   with(obj.elements[i]){
    var _dataType = getAttribute("dataType");
    if(typeof(_dataType) == "object" || typeof(this[_dataType]) == "undefined")  continue;
    this.ClearState(obj.elements[i]);
    if(getAttribute("require") == "false" && value == "") continue;
    switch(_dataType){
     case "IdCard" :
     case "Date" :
     case "Repeat" :
     case "Range" :
     case "Compare" :
     case "Custom" :
     case "Group" :
     case "Limit" :
     case "LimitB" :
     case "SafeString" :
     case "Filter" :
      if(!eval(this[_dataType])) {
       this.AddError(i, getAttribute("msg"));
      }
      break;
     default :
      if(!this[_dataType].test(value)){
       this.AddError(i, getAttribute("msg"));
      }
      break;
    }
   }
  }
  if(this.ErrorMessage.length > 1){
   mode = mode || 1;
   var errCount = this.ErrorItem.length;
   switch(mode){
   case 2 :
    for(var i=1;i<errCount;i++)
     this.ErrorItem[i].style.color = "red";
   case 1 :
    alert(this.ErrorMessage.join("\n"));
    this.ErrorItem[1].focus();
    break;
   case 3 :
    for(var i=1;i<errCount;i++){
    try{
     var span = document.createElement("SPAN");
     span.id = "__ErrorMessagePanel";
     span.style.color = "red";
     this.ErrorItem[i].parentNode.appendChild(span);
     span.innerHTML = this.ErrorMessage[i].replace(/\d+:/,"*");
     }
     catch(e){alert(e.description);}
    }
    this.ErrorItem[1].focus();
    break;
   default :
    alert(this.ErrorMessage.join("\n"));
    break;
   }
   return false;
  }
  return true;
 },
 limit : function(len,min, max){
  min = min || 0;
  max = max || Number.MAX_VALUE;
  return min <= len && len <= max;
 },
 LenB : function(str){
  return str.replace(/[^\x00-\xff]/g,"**").length;
 },
 ClearState : function(elem){
  with(elem){
   if(style.color == "red")
    style.color = "";
   var lastNode = parentNode.childNodes[parentNode.childNodes.length-1];
   if(lastNode.id == "__ErrorMessagePanel")
    parentNode.removeChild(lastNode);
  }
 },
 AddError : function(index, str){
  this.ErrorItem[this.ErrorItem.length] = this.ErrorItem[0].elements[index];
  this.ErrorMessage[this.ErrorMessage.length] = this.ErrorMessage.length + ":" + str;
 },
 Exec : function(op, reg){
  return new RegExp(reg,"g").test(op);
 },
 compare : function(op1,operator,op2){
  switch (operator) {
   case "NotEqual":
    return (op1 != op2);
   case "GreaterThan":
    return (op1 > op2);
   case "GreaterThanEqual":
    return (op1 >= op2);
   case "LessThan":
    return (op1 < op2);
   case "LessThanEqual":
    return (op1 <= op2);
   default:
    return (op1 == op2);           
  }
 },
 MustChecked : function(name, min, max){
  var groups = document.getElementsByName(name);
  var hasChecked = 0;
  min = min || 1;
  max = max || groups.length;
  for(var i=groups.length-1;i>=0;i--)
   if(groups[i].checked) hasChecked++;
  return min <= hasChecked && hasChecked <= max;
 },
 DoFilter : function(input, filter){
return new RegExp("^.+\.(?=EXT)(EXT)$".replace(/EXT/g, filter.split(/\s*,\s*/).join("|")), "gi").test(input);
 },
 IsIdCard : function(number){
  var date, Ai;
  var verify = "10x98765432";
  var Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
  var area = ['','','','','','','','','','','','北京','天|','沛_','p','内蒙?,'','','','','','辽宁','吉林','黑龙?,'','','','','','','','上v','江苏','江','安微','徏','江西','׃','','','','沛_','湖北','湖南','q东','q西','南','','','','重庆','四川','贵州','云南','西藏','','','','','','','陕西','甘肃','青v','宁夏','新疆','','','','','','台湾','','','','','','','','','','香港','澳门','','','','','','','','','国外'];
  var re = number.match(/^(\d{2})\d{4}(((\d{2})(\d{2})(\d{2})(\d{3}))|((\d{4})(\d{2})(\d{2})(\d{3}[x\d])))$/i);
  if(re == null) return false;
  if(re[1] >= area.length || area[re[1]] == "") return false;
  if(re[2].length == 12){
   Ai = number.substr(0, 17);
   date = [re[9], re[10], re[11]].join("-");
  }
  else{
   Ai = number.substr(0, 6) + "19" + number.substr(6);
   date = ["19" + re[4], re[5], re[6]].join("-");
  }
  if(!this.IsDate(date, "ymd")) return false;
  var sum = 0;
  for(var i = 0;i<=16;i++){
   sum += Ai.charAt(i) * Wi[i];
  }
  Ai +=  verify.charAt(sum%11);
  return (number.length ==15 || number.length == 18 && number == Ai);
 },
 IsDate : function(op, formatString){
  formatString = formatString || "ymd";
  var m, year, month, day;
  switch(formatString){
   case "ymd" :
    m = op.match(new RegExp("^((\\d{4})|(\\d{2}))([-./])(\\d{1,2})\\4(\\d{1,2})$"));
    if(m == null ) return false;
    day = m[6];
    month = m[5]*1;
    year =  (m[2].length == 4) ? m[2] : GetFullYear(parseInt(m[3], 10));
    break;
   case "dmy" :
    m = op.match(new RegExp("^(\\d{1,2})([-./])(\\d{1,2})\\2((\\d{4})|(\\d{2}))$"));
    if(m == null ) return false;
    day = m[1];
    month = m[3]*1;
    year = (m[5].length == 4) ? m[5] : GetFullYear(parseInt(m[6], 10));
    break;
   default :
    break;
  }
  if(!parseInt(month)) return false;
  month = month==0 ?12:month;
  var date = new Date(year, month-1, day);
        return (typeof(date) == "object" && year == date.getFullYear() && month == (date.getMonth()+1) && day == date.getDate());
  function GetFullYear(y){return ((y<30 ? "20" : "19") + y)|0;}
 }
 }
</script>

 



奥吉 2006-05-08 17:49 发表评论
]]>
操作oracle数据库的CLOB字段http://www.tkk7.com/aojilee/articles/43193.html奥吉奥吉Wed, 26 Apr 2006 01:51:00 GMThttp://www.tkk7.com/aojilee/articles/43193.htmlhttp://www.tkk7.com/aojilee/comments/43193.htmlhttp://www.tkk7.com/aojilee/articles/43193.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/43193.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/43193.html*
*操作oracle数据库的CLOB字段Q包括读和写
*作者:令少?
* */

package com.nes.common.sql.lob;

import java.sql.*;
import java.io.*;
import oracle.jdbc.OracleResultSet;
import oracle.sql.*;

public class JClob {

String tableName = null; //表名
String primaryKey = null; //表的主键?
String primaryValue = null; //表的主键?
String fieldName = null; //表的CLOB字段?
String clobValue = null; //表的CLOB字段?

Connection conn = null; //与oracle的连?

/**
*
*用于试?
*
* */
public static void main(String[] args) {
try {
JClob jc = new JClob(getConnection(),"aa","a","aaaa","c","ccc");
jc.write();
jc.read();
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}


/**
*
*构造方?
*
* */
public JClob(Connection connection,String tableName,String primaryKey,String primaryValue,String fieldName,String clobValue) {
this.conn = connection;
this.tableName = tableName;
this.primaryKey = primaryKey;
this.primaryValue = primaryValue;
this.fieldName = fieldName;
this.clobValue = clobValue;
}

/**
*
*构造方法,但不必传clobValue?
*一般构造出的实例用来读Clob字段
*
* */
public JClob(Connection connection,String tableName,String primaryKey,String primaryValue,String fieldName) {
this.conn = connection;
this.tableName = tableName;
this.primaryKey = primaryKey;
this.primaryValue = primaryValue;
this.fieldName = fieldName;
}

/**
*
*用于试
*
* */
public static Connection getConnection() throws SQLException,ClassNotFoundException {
Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@192.168.1.18:1521:portal","portal","portal");
return conn;
}

/**
*
*L据库中clob字段的内?
*@return clob字段?
*
* */
public String read() throws SQLException,IOException {
String rtn = null;
try {
String sql = "select " + fieldName + " from " + tableName + " where " + primaryKey + "=" + primaryValue;
//Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
//int v = Integer.parseInt(primaryValue);
//pstmt.setInt(1,v);
ResultSet rs = pstmt.executeQuery();

java.sql.Clob clob = null;
if (rs.next()) {
clob = rs.getCLOB(fieldName);
//clob = ((OracleResultSet)rs).getCLOB(fieldName);
//clob = ((org.apache.commons.dbcp.DelegatingResultSet)rs).getClob(fieldName);
//Reader in = clob.getCharacterStream();
InputStream input = clob.getAsciiStream();
int len = (int)clob.length();
byte[] by = new byte[len];
int i ;//= input.read(by,0,len);
while(-1 != (i = input.read(by, 0, by.length))) {
input.read(by, 0, i);
}
rtn = new String(by);
}
}
catch (SQLException e){
throw e;
}
catch (Exception ee) {
ee.printStackTrace();
}

return rtn;
}

/**
*
*葱数据库中clob字段的内?
*
* */
public void write() throws SQLException,IOException {
String sql = "update " + tableName + " set " + fieldName + "=empty_clob() where " + primaryKey + "=" + primaryValue;
//Connection conn = getConnection();
conn.setAutoCommit(false);

PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate();

sql = "select " + fieldName + " from " + tableName + " where " + primaryKey + "=" + primaryValue;
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);

java.sql.Clob clob ;
if (rs.next()) {
clob = ((oracle.jdbc.OracleResultSet)rs).getClob(fieldName);
//clob = ((org.apache.commons.dbcp.DelegatingResultSet)rs).getClob(fieldName);
oracle.sql.CLOB my_clob = (oracle.sql.CLOB)clob;
OutputStream writer = my_clob.getAsciiOutputStream();
byte[] contentStr = this.getContent().getBytes();
writer.write(contentStr);
writer.flush();
writer.close();
}

conn.commit();
rs.close();
st.close();
pstmt.close();
conn.setAutoCommit(true);
}

/**
*
*
* */
private String getContent() {
return this.clobValue;
}

/**
*
*
* */
public void setClobValue(String clobValue) {
this.clobValue = clobValue;
}
}

奥吉 2006-04-26 09:51 发表评论
]]>
Web开发工?/title><link>http://www.tkk7.com/aojilee/articles/39885.html</link><dc:creator>奥吉</dc:creator><author>奥吉</author><pubDate>Fri, 07 Apr 2006 09:35:00 GMT</pubDate><guid>http://www.tkk7.com/aojilee/articles/39885.html</guid><wfw:comment>http://www.tkk7.com/aojilee/comments/39885.html</wfw:comment><comments>http://www.tkk7.com/aojilee/articles/39885.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/aojilee/comments/commentRss/39885.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/aojilee/services/trackbacks/39885.html</trackback:ping><description><![CDATA[ <h3>1、PowerBand </h3> <p>PowerBand 是一个IE的插?同时也支持MyIE2/Maxthon)。提供了对HTML动态分析,跟踪Q编辑的功能。能够方便快L(fng)分析HTML面的结构,有助于网设计h?|站开发h员调试,分析晦ӆ的HTML代码。这是我最早用的HTML开发辅助工P现在?.1版了Q支持ASP.NET ViewState的解码,支持DebugViewQ类gVC中的WatchQ通过q个功能能够昄面中元素对象的详细内容。同Ӟ PowerBand也支持即时脚本交互功能?/p> <p> <a >下蝲PowerBand2.1</a> </p> <h3>2、HttpWatch</h3> < p>HttpWatch又是一个IE下的强劲插gQHttpWatch最主要的功能就是对通过览器进行网l通讯的数据进行监控和分析Q当你在览器的地址栏上h一个URL或者提交一份表单时QHttpWatch帮你分析httph的head信息Q访问页面的cookie信息QGet和Post 的详l数据包分析QCatch内容分析QQueryString分析。想知道GMail或者是M一个AJAX|页时如何和服务器进行数据交互的吗?用这个插件就可以一览无余了<img alt="" src="/FCKeditor/editor/images/smiley/qq/face5.gif" align="absMiddle" /><p><a >下蝲HttpWatch3.2.0.63< /A> <a >下蝲注册?/a>< /p> <h3>3、IE Developer Toolbar </h3><p>W三个插件还是基于IE下的Q不q这个可?a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d -4511-bb3e-2d5e1db91038&displaylang=en">微Y发布的Web开发IE工具?lt; /A>Q实现的功能如下Q?/a></p><ul><li>览和修改Web늚文档对象模型QDOMQ? </li><li>通过多种技术方式定位、选定Web上的特定元素? </li><li>止或激zIE讄? </li><li>查看HTML对象的类名、IDQ以及类似链接\径、tab序、快捷键{细节? </li><li>描绘表格、单元格、图片或选定标签的轮廓? </li><li>昄囄象素、大、\径、替代文字等? </li><li>x重定义浏览器H口大小?00x600或自定义大小? </li><li>清空览器缓存和cookieQ被清除可从所有对象或l定域中选择? </li><li>直接讉K兌W3C规范参考、IE开发组blog或其他来源? </li><li>昄设计时标,帮助寚w对象?</li></ul><p><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d -4511-bb3e-2d5e1db91038&displaylang=en">官方下蝲</a></p><h3>4、ViewPage</h3> < p>ViewPage是MyIE2/Maxthon览器插Ӟq个插g不算是纯_的开发辅助,它看h更像是资源提取,可以方便的提取网中的源代码Q包括所有框架的源代码,提取囑փ、Flash、媒体文件、链接,我最ƣ赏的就是能方便的查看页面中包含的所有js文g源代码和所有css源代码?</a></p><p><a >下蝲ViewPage1.2 for Maxthon</a></p><h3>5、Web Development with Mozilla Firefox</h3><p>Firefox下的开发辅助工具和插g非常多,先说Firefox自带的吧?/p><ul><li>查看源代码(查看-〉页面源代码Q,Firefox自带的查看源代码支持语法高亮昄Q这个功能很独特 </li><li>查看面信息Q工?〉页面信息)Q这是基本功能了Q不q有点简? </li><li>Javascript调试収ͼq是Firefox的一大特Ԍ是IE所没有的功? </li><li>DOM查看器,内置的DOM分析和查看工P怀疑PowerBand和IE Developer Toolbar 都是模仿Firefox的这个做?</li></ul><p>Firefox自带的开发辅助功能虽然已很丰富,但让我更加垂涎的是丰富的开发类插g</p><ul><li>最著名的就?a >Web Developer</a>了,q个插g几乎囊括了所有能实现的web开发辅助功能,微Y的那个就像是模仿于它 </li><li><a >Aardvark</a>是一个CSS debug插g </li><li><a >Add & Edit Cookies</a>Q看名字q道了Q一个专门增加和修改Cookies的插Ӟ相关的还有一?a >View Cookies</a>是用来查看Cookies的插? </li><li><a >Colorzilla< /A>可以捕获当前鼠标所指的面坐标位置和颜Ԍ以及DOM路径 <li><a >IE View</a> and <a >Opera View</a>是两个专门在Firefox中用IE和Opera中打开一个页面的工具Q方便你调试支持多浏览器的web </li><li><a >MeasureIt< /A>是一个Firefox中画坐标和度量尺的小插gQ用它测量HTML元素的宽高很是方? <li><a >Live HTTP Headers</a>是一个类gHttpWatch功能一L(fng)Firefox插gQ用来查看HTTP Header、Cookie、MIME{信息,不过HttpWatch是收费的Q这个确是免费的Q推荐下?</li></a></li></a></li></ul> < p>Firefox下的开发类插g太多了,如果你感兴趣可以<a href="https://addons.mozilla.org/extensions/showlist.php?application=firefox& numpg=10&category=Developer%20Tools">打开q个链接</a>Q这里面全是 Developer Tools。还?a > q篇文章</a>Q非常详l的一步一步介l了Mozilla Firefox的web开发工P推荐阅读?img src ="http://www.tkk7.com/aojilee/aggbug/39885.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/aojilee/" target="_blank">奥吉</a> 2006-04-07 17:35 <a href="http://www.tkk7.com/aojilee/articles/39885.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POJO ?PO?概念http://www.tkk7.com/aojilee/articles/35646.html奥吉奥吉Thu, 16 Mar 2006 06:20:00 GMThttp://www.tkk7.com/aojilee/articles/35646.htmlhttp://www.tkk7.com/aojilee/comments/35646.htmlhttp://www.tkk7.com/aojilee/articles/35646.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/35646.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/35646.html
POJO ?PO?概念

作者:robbin (MSN:robbin_fan AT hotmail DOT com)

整理人:smallduzi

版权声明Q本文严{载,如有转蝲hQ请和作者联p?/STRONG>

POJO = pure old java object or plain ordinary java object or what ever.

PO = persisent object 持久对象

是说在一些Object/Relation Mapping工具中,能够做到l护数据库表记录的persisent object完全是一个符合Java Bean规范的纯Java对象Q没有增加别的属性和Ҏ(gu)。全都是q样子的Q?/P>

public class User { 
  private long id; 
  private String name;
  public void setId(long id) {
 this.id = id;
}  
public void setName(String name) {
this.name=name;
} 
 public long getId() {
 return id;
}  
public String getName() { 
return name;
}
}  

首先要区别持久对象和POJO?/P>

持久对象实际上必d应数据库中的entityQ所以和POJO有所区别。比如说POJO是由new创徏Q由GC回收。但是持久对象是insert数据库创建,由数据库delete删除的。基本上持久对象生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库Connection之中QConnnection关闭以后Q持久对象就不存在了Q而POJO只要不被GC回收QL存在的?/P>

׃存在诸多差别Q因此持久对象PO(Persistent Object)在代码上肯定和POJO不同Qv码PO相对于POJO会增加一些用来管理数据库entity状态的属性和Ҏ(gu)。而ORMq求的目标就是要PO在用上量和POJO一_对于E序员来_他们可以把PO当做POJO来用Q而感觉不到PO的存在?/P>

JDO的实现方法是q样的:

1、编写POJO

2、编译POJO

3、用JDO的一个专门工P叫做EnhancerQ一般是一个命令行E序Q手工运行,或者在ant脚本里面q行Q对POJO的class文g处理一下,把POJO替换成同名的PO?/P>

4、在q行期运行的实际上是POQ而不是POJO?/P>

该方法有点类gJSPQJSP也是在编译期被{换成Servlet来运行的Q在q行期实际上q行的是ServletQ而不是JSP?/P>

Hibernate的实现方法比较先q:

1、编写POJO

2、编译POJO

3、直接运行,在运行期Q由Hibernate的CGLIB动态把POJO转换为PO?/P>

由此可以看出Hibernate是在q行期把POJO的字节码转换为PO的,而JDO是在~译期{换的。一般认为JDO的方式效率会E高Q毕竟是~译期{换嘛。但是Hibernate的作者Gavin King说CGLIB的效率非怹高,q行期的PO的字节码生成速度非常之快Q效率损失几乎可以忽略不计?/P>

实际上运行期生成PO的好处非常大Q这样对于程序员来说Q是无法接触到PO的,PO对他们来说完全透明。可以更加自q以POJO的概忉|UPO。另外由于是q行期生成POQ所以可以支持增量编译,增量调试。而JDO则无法做到这一炏V实际上已经有很多h在抱怨JDO的编译期Enhancer问题了,而据说JBossDO采用运行期生成PO字节码,而不采用~译期生成PO字节码?/P>

另外一个相关的问题是,不同的JDO产品的Enhancer生成的PO字节码可能会有所不同Q可能会影响在JDO产品之间的可UL性,q一Ҏ(gu)点类似EJB的可UL性难题?/P>

p个问题另外引Z个JDO的缺陗?/P>

׃JDO的PO状态管理方式,所以当你在E序里面get/set的时候,实际上不是从PO的实例中取valuesQ而是从JDO State Manager?中取出来Q所以一旦PM关闭QPO׃能进行存取了?/P>

在JDO中,也可以通过一些办法得PO可以在PM外面使用Q比如说定义PO是transient的,但是该PO在PM关闭后就没有PO identity了。无法进行跨PM的状态管理?/P>

而Hibernate是从PO实例中取values的,所以即使Session关闭Q也一样可以get/setQ可以进行跨Session的状态管理?/P>

在分多层的应用中Q由于持久层和业务层和web层都是分开的,此时Hibernate的PO完全可以当做一个POJO来用Q也是当做一个VOQ在各层间自׃递,而不用去Session是开q是兟뀂如果你把这个POJO序列化的话,甚至可以用在分布式环境中。(不适合lazy loading的情况)

但是JDO的PO在PM关闭后就不能再用了,所以必dPM关闭前把PO拯一份VOQ把VO传递给业务层和web层用。在非分布式环境中,也可以用ThreadLocal模式保PM始终是打开状态,来避免每ơ必进行PO到VO的拷贝操作。但是不怎么_qL权宜之计Q不如Hibernate的功能强?/P>

评论

 re: POJO ?PO?概念   

potian 写道:
辨别一些名词:
1。VOQ实际上很模p,通常指ValueObject和ViewObject
2. ViewObjectQ界面展现需要的对象Q如Struts的FormBean
3。Value ObjectQ早期被作ؓValueObject和Transfer Object的ȝ。实际上Value Object的真正意义在于它的内容,而不是n?
4。Transfer ObjectQ数据传输对象,在应用程序不同层ơ之间传书对象,在一个分布式应用E序中,通常可以提高整体的性能
5。POQ也许就是Persistent ObjectQ基本上是Entity?
在不同的体系l构和实现方式里面,q些对象有可能重复,也有可能不重叠。如果你要做一个对所有的体系都能够方便移植的框架Q那么每一U对象都需要严格区分。例如JDO的PO不能作ؓTOQ应为它不能qPMQ譬如你可以选择用ViewObjectQ如Struts的FOrmBean)直接作ؓTOQ但在tapestry和W(xu)ebwork里面׃合适了。但在很多时候,能够方便实用是最重要的,不要q度设计是了?

robbin写道Q?

POJO是这样一个对象,它是一个普通的Java对象Q它不同于EJBq样的带有繁重的容器控制功能的对象,它也不是那种被Enhancedq的对象Q例如JDO的静态EnhanceQ也不是cMHibernate那样被动态的byte code generationq?

也就是说POJO的概忉|相对于其他那U被人动q手脚的class而言的,它是没有被动q手脚的?

Ҏ(gu)?

其实Qؓ什么要做DAO?无非是:
1Q?理connection/transaction (hibernate的话是session/transaction)
2, 便于q行l计/log操作Q?
3Q?便于q行权限控制Q?

DAO模式中,有两cd象,一U是DAOQ一U是valueObject?在我们讨论的q个情况中,value object是hibernate对应的POJO.

那么Q按照我的理解,DAO是一个Transaction包装器,光辑l构是商业的具体事务。此处,数据库的transaction和商业的事务是统一的?

q里有一不错的关于DAO的文章?
http://www-106.ibm.com/developerworks/java/library/j-dao/

BO 包含business logic
留在q备忘?


奥吉 2006-03-16 14:20 发表评论
]]>
Java/J2EE中文问题l极解决之道http://www.tkk7.com/aojilee/articles/26723.html奥吉奥吉Thu, 05 Jan 2006 07:09:00 GMThttp://www.tkk7.com/aojilee/articles/26723.htmlhttp://www.tkk7.com/aojilee/comments/26723.htmlhttp://www.tkk7.com/aojilee/articles/26723.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/26723.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/26723.html   Java/J2EE中文问题l极解决之道
 

板桥里h http://www.jdon.com 2005/06/29

  Java中文问题一直困扰着很多初学者,如果了解了Javapȝ的中文问题原理,我们可以对中文问题能够采取Ҏ(gu)的解决之道?/P>

  最古老的解决Ҏ(gu)是用String的字节码转换Q这U方案问题是不方便,我们需要破坏对象封装性,q行字节码{换?/P>

  q有一U方式是对J2EE容器q行~码讄Q如果J2EE应用pȝq该容器,则会发生qQ而且指定容器配置不符合J2EE应用和容器分ȝ原则?/P>

  在Java内部q算中,涉及到的所有字W串都会被{化ؓUTF-8~码来进行运。那么,在被Java转化之前Q字W串是什么样的字W集Q?JavaLҎ(gu)操作pȝ的默认编码字W集来决定字W串的初始编码,而且Javapȝ的输入和输出的都是采取操作系l的默认~码?/P>

  因此Q如果能l一Javapȝ的输入、输出和操作pȝ3者的~码字符集合Q将能够使Javapȝ正确处理和显C汉字。这是处理Javapȝ汉字的一个原则,但是在实际项目中Q能够正抓住和控制住Javapȝ的输入和输出部分是比较难的。J2EE中,׃涉及到外部浏览器和数据库{,所以中文问题ؕ码显得非常突出?/P>

  J2EE应用E序是运行在J2EE容器中。在q个pȝ中,输入途径有很多种Q一U是通过面表单打包成请求(requestQ发往服务器的Q第二种是通过数据库读入;q有W?U输入比较复杂,JSP在第一ơ运行时L被编译成ServletQJSP中常常包含中文字W,那么~译使用javacӞJava根据默认的操作pȝ~码作ؓ初始~码。除非特别指定,如在Jbuilder/eclipse中可以指定默认的字符集?/P>

  输出途径也有几种Q第一U是JSP面的输出。由于JSP面已经被编译成ServletQ那么在输出Ӟ也将Ҏ(gu)操作pȝ的默认编码来选择输出~码Q除非指定输出编码方式;q有输出途径是数据库Q将字符串输出到数据库?/P>

  由此看来Q一个J2EEpȝ的输入输出是非常复杂Q而且是动态变化的Q而Java是跨q_q行的,在实际编译和q行中,都可能涉及到不同的操作系l,如果ȝJava自由Ҏ(gu)操作pȝ来决定输入输出的~码字符集,q将不可控制地出Cؕ码?/P>

  正是׃Java的跨q_Ҏ(gu),使得字符集问题必ȝ具体pȝ来统一解决Q所以在一个Java应用pȝ中,解决中文q的根本办法是明确指定整个应用pȝl一字符集?/STRONG>

  指定l一字符集时Q到底是指定ISO8859_1 、GBKq是UTF-8呢?

  Q?Q如l一指定为ISO8859_1Q因为目前大多数软g都是西方人编制的Q他们默认的字符集就是ISO8859_1Q包括操作系lLinux和数据库MySQL{。这P如果指定Jivel一~码为ISO8859_1Q那么就有下?个环节必L握:

  开发和~译代码时指定字W集为ISO8859_1?/P>

  q行操作pȝ的默认编码必LISO8859_1Q如Linux?/P>

  在JSP头部声明Q?lt;%@ page contentType="text/html;charset=ISO8859_1" %>?/P>

  Q?Q如果统一指定为GBK中文字符集,上述3个环节同样需要做刎ͼ不同的是只能q行在默认编码ؓGBK的操作系l,如中文Windows?/P>

  l一~码为ISO8859_1和GBK虽然带来~制代码的方便,但是各自只能在相应的操作pȝ上运行。但是也破坏了Java跨^台运行的优越性,只在一定范围内行得通。例如,Z使得GBK~码在linux上运行,讄Linux~码为GBK?/P>

  那么有没有一U除了应用系l以外不需要进行Q何附加设|的中文~码Ҏ(gu)解决Ҏ(gu)呢?

  Java/J2EEpȝ的统一~码定义为UTF-8。UTF-8~码是一U兼Ҏ(gu)有语a的编码方式,惟一比较ȝ的就是要扑ֈ应用pȝ的所有出入口Q然后用UTF-8厠Z结扎”它?/P>

  一个J2EE应用pȝ需要做下列几步工作Q?/P>

  1. 开发和~译代码时指定字W集为UTF-8。JBuilder和Eclipse都可以在目属性中讄?
  2. 使用qo器,如果所有请求都l过一个Servlet控制分配器,那么使用Servlet的filter执行语句Q将所有来自浏览器的请求(requestQ{换ؓUTF-8Q因为浏览器发过来的h包根据浏览器所在的操作pȝ~码Q可能是各种形式~码。关键一句:
    request.setCharacterEncoding("UTF-8")?BR>|上有此filter的源码,Jdon框架源码中com.jdon.util.SetCharacterEncodingFilter
    需要配|web.xml Ȁz该Filter?
  3. 在JSP头部声明Q?lt;%@ page contentType="text/html;charset= UTF-8" %>?
  4. 在Jsp的html代码中,声明UTF-8:
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. 讑֮数据库连接方式是UTF-8。例如连接MYSQL旉|URL如下Q?BR>jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8
    一般数据库都可以通过理讄讑֮UTF-8
  6. 其他和外界交互时能够讑֮~码时就讑֮UTF-8Q例如读取文Ӟ操作XML{?
     W者以前在Jsp/Servlet时就采取q个原则Q后来用Struts、Tapestry、EJB、Hibernate、Jdon{框架时Q从未被q困扰q,可以说适合各种架构。希望本Ҏ(gu)供更多初学者分享,减少Java/J2EE的第一个拦路虎Q也避免因ؓ采取一些(f)时解x案,D中文问题一直出现在新的技术架构中?/SPAN>

奥吉 2006-01-05 15:09 发表评论
]]>
深入Java中文问题及最优解x?/title><link>http://www.tkk7.com/aojilee/articles/26720.html</link><dc:creator>奥吉</dc:creator><author>奥吉</author><pubDate>Thu, 05 Jan 2006 06:47:00 GMT</pubDate><guid>http://www.tkk7.com/aojilee/articles/26720.html</guid><wfw:comment>http://www.tkk7.com/aojilee/comments/26720.html</wfw:comment><comments>http://www.tkk7.com/aojilee/articles/26720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/aojilee/comments/commentRss/26720.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/aojilee/services/trackbacks/26720.html</trackback:ping><description><![CDATA[<TABLE style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" cellSpacing=0 cellPadding=0 width="96%" border=0> <TBODY> <TR> <TD bgColor=#e8f0f1>深入Java中文问题及最优解x?-?/TD></TR> <TR> <TD> <TABLE cellSpacing=0 cellPadding=0 width="100%" border=0> <TBODY> <TR> <TD> <DIV align=right></DIV></TD></TR></TBODY></TABLE><span id="ikoikoe" class=oblog_text>  说明Q本文ؓ转蝲Q作者联pd址为:<A href="mailto:josserchai@yahoo.com">josserchai@yahoo.com</A>?BR>׃Java~程中的中文问题是一个老生常谈的问题,在阅M许多关于Java中文问题解决Ҏ(gu)之后Q结合作者的~程实践Q我发现q去谈的许多Ҏ(gu)都不能清晰地说明问题及解决问题,其是跨q_时的中文问题。于是我l出此篇文章Q内容包括对控制台运行的class、Servelets、JSP及EJBcM的中文问题我剖析和徏议解军_法。希望大家指教? <P>  AbstractQ本文深入分析了JavaE序设计中Java~译器对java源文件和JVM对classcL件的~码/解码q程Q通过此过E的解析透视ZJava~程中中文问题生的Ҏ(gu)原因Q最后给Z的最优化的解决Java中文问题的方法?</P> <P>  1、中文问题的来源 </P> <P>计算机最初的操作pȝ支持的编码是单字节的字符~码Q于是,在计机中一切处理程序最初都是以单字节编码的英文为准q行处理。随着计算机的发展Qؓ了适应世界其它民族的语aQ当然包括我们的汉字Q,Z提出了UNICODE~码Q它采用双字节编码,兼容英文字符和其它民族的双字节字W编码,所以,目前Q大多数国际性的软g内部均采用UNICODE~码Q在软gq行Ӟ它获得本地支持系l(多数旉是操作系l)默认支持的编码格式,然后再将软g内部的UNICODE转化为本地系l默认支持的格式昄出来。Java的JDK和JVMx如此Q我q里说的JDK是指国际版的JDKQ我们大多数E序员用的是国际化的JDK版本Q以下所有的JDK均指国际化的JDK版本。我们的汉字是双字节~码语言Qؓ了能让计机处理中文Q我们自己制定的gb2312、GBK、GBK2K{标准以适应计算机处理的需求。所以,大部分的操作pȝZ适应我们处理中文的需求,均定制有中文操作pȝQ它们采用的是GBK,GB2312~码格式以正显C我们的汉字。如Q中文Win2K默认采用的是GBK~码昄Q在中文WIN2k中保存文件时默认采用的保存文件的~码格式也是GBK的,卻I所有在中文WIN2K中保存的文g它的内部~码默认均采用GBK~码Q注意:GBK是在GB2312基础上扩充来的?/P> <P>׃Java语言内部采用UNICODE~码Q所以在JAVAE序q行Ӟ存在着一个从UNICODE~码和对应的操作pȝ及浏览器支持的编码格式{换输入、输出的问题Q这个{换过E有着一pd的步骤,如果其中M一步出错,则显C出来的汉字׃出是qQ这是我们常见的JAVA中文问题?/P> <P>同时QJava是一个跨q_的编E语aQ也x们编写的E序不仅能在中文windows上运行,也能在中文Linux{系l上q行Q同时也要求能在英文{系l上q行Q我们经常看到有人把在中文win2k上编写的JAVAE序Q移植到英文Linux上运行)。这U移植操作也会带来中文问题?/P> <P>q有Q有Z用英文的操作pȝ和英文的IE{浏览器Q来q行带中文字W的E序和浏览中文网,它们本n׃支持中文Q也会带来中文问题?/P> <P>几乎所有的览器默认在传递参数时都是以UTF-8~码格式来传递,而不是按中文~码传递,所以,传递中文参数时也会有问题,从而带来ؕ码现象?/P> <P>MQ以上几个方面是JAVA中的中文问题的主要来源,我们把以上原因造成的程序不能正运行而生的问题UCQJAVA中文问题?/P> <P>  2、JAVA~码转换的详l过E?</P> <P>我们常见的JAVAE序包括以下cdQ?BR>*直接在console上运行的c?包括可视化界面的c?<BR>*JSP代码c(注:JSP是Servletscȝ变型Q?BR>*Serveletsc?BR>*EJBc?BR>*其它不可以直接运行的支持c?/P> <P>q些cL件中Q都有可能含有中文字W串Qƈ且我们常用前三类JAVAE序和用L(fng)接交互,用于输出和输入字W,如:我们在JSP和Servlet中得到客L(fng)送来的字W,q些字符也包括中文字W。无些JAVAcȝ作用如何Q这些JAVAE序的生命周期都是这L(fng)Q?/P> <P>*~程人员在一定的操作pȝ上选择一个合适的~辑软g来实现源E序代码q以.java扩展名保存在操作pȝ中,例如我们在中文win2k中用C本编辑一个java源程序;<BR>*~程人员用JDK中的javac.exe来编译这些源代码QŞ?classc?JSP文g是由容器调用JDK来编译的)Q?BR>*直接q行q些cL这些类布v到WEB容器中去q行Qƈ输出l果?BR>那么Q在q些q程中,JDK和JVM是如何将q些文g如何~码和解码ƈq行的呢Q?BR>q里Q我们以中文win2k操作pȝZ说明JAVAcL如何来编码和被解码的?/P> <P>W一步,我们在中文win2k中用~辑软g如记事本~写一个Java源程序文?包括以上五类JAVAE序)Q程序文件在保存旉认采用了操作pȝ默认支持GBK~码格式(操作pȝ默认支持的格式ؓfile.encoding格式)形成了一?java文gQ也卻IjavaE序在被~译前,我们的JAVA源程序文件是采用操作pȝ默认支持的file.encoding~码格式保存的,java源程序中含有中文信息字符和英文程序代码;要查看系l的file.encoding参数Q可以用以下代码Q?BR>   public class ShowSystemDefaultEncoding {<BR>   public static void main(String[] args) {<BR>   String encoding = System.getProperty("file.encoding");<BR>   System.out.println(encoding);<BR>   }}</P> <P>W二步,我们用JDK的javac.exe文g~译我们的Java源程序,׃JDK是国际版的,在编译的时候,如果我们没有?encoding参数指定我们的JAVA源程序的~码格式Q则javac.exe首先获得我们操作pȝ默认采用的编码格式,也即在编译javaE序Ӟ若我们不指定源程序文件的~码格式QJDK首先获得操作pȝ的file.encoding参数(它保存的是操作pȝ默认的编码格式,如WIN2kQ它的gؓGBK)Q然后JDK把我们的java源程序从file.encoding~码格式转化为JAVA内部默认的UNICODE格式攑օ内存中。然后,javac把{换后的unicode格式的文件进行编译成.classcLӞ此时.class文g是UNICODE~码的,它暂攑֜内存中,紧接着QJDK此以UNICODE~码的编译后的class文g保存到我们的操作pȝ中Ş成我们见到的.class文g。对我们来说Q我们最l获得的.class文g是内容以UNICODE~码格式保存的类文gQ它内部包含我们源程序中的中文字W串Q只不过此时它己l由file.encoding格式转化为UNICODE格式了?/P> <P>q一步中Q对于JSP源程序文件是不同的,对于JSPQ这个过E是q样的:即WEB容器调用JSP~译器,JSP~译器先查看JSP文g中是否设|有文g~码格式Q如果JSP文g中没有设|JSP文g的编码格式,则JSP~译器调用JDK先把JSP文g用JVM默认的字W编码格?也即WEB容器所在的操作pȝ的默认的file.encoding)转化Z(f)时的Servletc,然后再把它编译成UNICODE格式的classc,q保存在临时文g夹中。如Q在中文win2k上,W(xu)EB容器把JSP文g从GBK~码格式转化为UNICODE格式Q然后编译成临时保存的Servletc,以响应用L(fng)h?/P> <P>W三步,q行W二步编译出来的c,分ؓ三种情况Q?/P> <P>A?直接在console上运行的c?BR>B?EJBcd不可以直接运行的支持c?如JavaBeanc?<BR>C?JSP代码和Servletc?BR>D?JAVAE序和数据库之间<BR>下面我们分这四种情况来看?BR>A、直接在console上运行的c?/P> <P>q种情况Q运行该c首先需要JVM支持Q即操作pȝ中必d装有JRE。运行过E是q样的:首先java启动JVMQ此时JVMd操作pȝ中保存的class文gq把内容d内存中,此时内存中ؓUNICODE格式的classc,然后JVMq行它,如果此时此类需要接收用戯入,则类会默认用file.encoding~码格式对用戯入的串进行编码ƈ转化为unicode保存入内存(用户可以讄输入的~码格式Q。程序运行后Q生的字符ԌUNICODE~码的)再回交给JVMQ最后JRE把此字符串再转化为file.encoding格式(用户可以讄输出的~码格式)传递给操作pȝ昄接口q输出到界面上?/P> <P>对于q种直接在console上运行的c,它的转化q程可用?更加明确的表C出来:</P> <P>?<BR> <IMG height=387 alt=6616_1.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6616_1.gif" width=462 border=0></P> <P>以上每一步的转化都需要正的~码格式转化Q才能最l不出现q现象?/P> <P>B、EJBcd不可以直接运行的支持c?如JavaBeanc?</P> <P>׃EJBcd不可以直接运行的支持c,它们一般不与用L(fng)接交互输入和输出Q它们常怸其它的类q行交互输入和输出,所以它们在W二步被~译后,Ş成了内容是UNICODE~码的类保存在操作系l中了,以后只要它与其它的类之间的交互在参数传递过E中没有丢失Q则它就会正的q行?BR>q种EJBcd不可以直接运行的支持c? 它的转化q程可用?更加明确的表C出来:</P> <P>?<BR> <IMG height=246 alt=6616_2.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6616_2.gif" width=443 border=0></P> <P>C、JSP代码和Servletc?/P> <P>l过W二步后QJSP文g也被转化为ServletscLӞ只不q它不像标准的Servlets一校存在于classes目录中,它存在于WEB容器的(f)时目录中Q故q一步中我们也把它做为Servlets来看?/P> <P>对于ServletsQ客L(fng)h它时QW(xu)EB容器调用它的JVM来运行ServletQ首先,JVM把Servlet的classcMpȝ中读出ƈ装入内存中,内存中是以UNICODE~码的Servletcȝ代码Q然后JVM在内存中q行该Servletc,如果Servlet在运行的q程中,需要接受从客户端传来的字符如:表单输入的值和URL中传入的|此时如果E序中没有设定接受参数时采用的编码格式,则WEB容器会默认采用ISO-8859-1~码格式来接受传入的值ƈ在JVM中{化ؓUNICODE格式的保存在WEB容器的内存中。Servletq行后生成输出,输出的字W串是UNICODE格式的,紧接着Q容器将Servletq行产生的UNICODE格式的串Q如html语法Q用戯出的串等Q直接发送到客户端浏览器上ƈ输出l用P如果此时指定了发送时输出的编码格式,则按指定的编码格式输出到览器上Q如果没有指定,则默认按ISO-8859-1~码发送到客户的浏览器上。这UJSP代码和Servletc,它的转化q程可用?更加明确地表C出来:</P> <P>?<BR> <IMG height=431 alt=6616_3.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6616_3.gif" width=422 border=0></P> <P>D、JavaE序和数据库之间</P> <P>对于几乎所有数据库的JDBC驱动E序Q默认的在JAVAE序和数据库之间传递数据都是以ISO-8859-1为默认编码格式的Q所以,我们的程序在向数据库内存储包含中文的数据ӞJDBC首先是把E序内部的UNICODE~码格式的数据{化ؓISO-8859-1的格式,然后传递到数据库中Q在数据库保存数据时Q它默认即以ISO-8859-1保存Q所以,q是Z么我们常常在数据库中d的中文数据是q?BR>对于JAVAE序和数据库之间的数据传递,我们可以用图4清晰地表C出?/P> <P>?<BR> <IMG height=167 alt=6616_4.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6616_4.gif" width=467 border=0></P> <P>3、分析常见的JAVA中文问题几个必须清楚的原?/P> <P>首先Q经q上面的详细分析Q我们可以清晰地看到QQ何JAVAE序的生命期中,其编码{换的关键q程是在于:最初编译成class文g的{码和最l向用户输出的{码过E?BR>其次Q我们必M解JAVA在编译时支持的、常用的~码格式有以下几U:<BR>*ISO-8859-1Q?-bit, ?859_1,ISO-8859-1,ISO_8859_1{编?BR>*Cp1252Q美国英语编码,同ANSI标准~码<BR>*UTF-8Q同unicode~码<BR>*GB2312Q同gb2312-80,gb2312-1980{编?BR>*GBK , 同MS936Q它是gb2312的扩?BR>及其它的~码Q如韩文、日文、繁体中文等。同Ӟ我们要注意这些编码间的兼容关体系如下Q?BR>unicode和UTF-8~码是一一对应的关pRGB2312可以认ؓ是GBK的子集,即GBK~码是在gb2312上扩展来的。同ӞGBK~码包含?0902个汉字,~码范围为:0x8140-0xfefeQ所有的字符可以一一对应到UNICODE2.0中来?/P> <P>再次Q对于放在操作系l中?java源程序文Ӟ在编译时Q我们可以指定它内容的编码格式,具体来说?encoding来指定。注意:如果源程序中含有中文字符Q而你?encoding指定为其它的~码字符Q显然是要出错的。用-encoding指定源文件的~码方式为GBK或gb2312Q无论我们在什么系l上~译含有中文字符的JAVA源程序都不会有问题,它都会正地中文{化ؓUNICODE存储在class文g中?BR><BR>然后Q我们必L楚,几乎所有的WEB容器在其内部默认的字W编码格式都是以ISO-8859-1为默认值的Q同Ӟ几乎所有的览器在传递参数时都是默认以UTF-8的方式来传递参数的。所以,虽然我们的Java源文件在出入口的地方指定了正的~码方式Q但其在容器内部q行时还是以ISO-8859-1来处理的?BR><BR>4、中文问题的分类及其最优解军_?</P> <P>了解以上JAVA处理文g的原理之后,我们可以提Z一套徏议最优的解决汉字问题的办法?BR>我们的目标是Q我们在中文pȝ中编辑的含有中文字符串或q行中文处理的JAVA源程序经~译后可以移值到M其它的操作系l中正确q行Q或拿到其它操作pȝ中编译后能正运行,能正地传递中文和英文参数Q能正确地和数据库交中英文字符丌Ӏ?BR>我们的具体思\是:在JAVAE序转码的入口和出口及JAVAE序同用h输入输出转换的地斚w制编码方法之正即可?/P> <P>具体解决办法如下Q?/P> <P>1?针对直接在console上运行的c?BR>对于q种情况Q我们徏议在E序~写Ӟ如果需要从用户端接收用L(fng)可能含有中文的输入或含有中文的输出,E序中应该采用字W流来处理输入和输出Q具体来_应用以下面向字符型节Ҏ(gu)cdQ?BR>Ҏ(gu)ӞFileReaderQFileWrieter <BR>其字节型节点类型ؓQFileInputStreamQFileOutputStream<BR>对内存(数组Q:CharArrayReaderQCharArrayWriter<BR>其字节型节点类型ؓQByteArrayInputStreamQByteArrayOutputStream<BR>对内存(字符ԌQStringReaderQStringWriter<BR>对管道:PipedReaderQPipedWriter<BR>其字节型节点类型ؓQPipedInputStreamQPipedOutputStream<BR>同时Q应该用以下面向字符型处理流来处理输入和输出Q?BR>BufferedWriterQBufferedReader<BR>其字节型的处理流为:BufferedInputeStreamQBufferedOutputStream<BR>InputStreamReaderQOutputStreamWriter<BR>其字节型的处理流为:DataInputStreamQDataOutputStream<BR>其中InputStreamReader和InputStreamWriter用于字节流按照指定的字W编码集转换到字W流Q如Q?BR>InputStreamReader in = new InputStreamReader(System.inQ?GB2312")Q?BR>OutputStreamWriter out = new OutputStreamWriter (System.outQ?GB2312")Q?BR>例如Q采用如下的CZJAVA~码pC要求Q?/P> <P>//Read.java<BR>import java.io.*;<BR>public class Read {<BR>public static void main(String[] args) throws IOException {<BR>String str = "n中文试Q这是内部硬~码的串"+"ntest english character";<BR>String strin= "";<BR>BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in,"gb2312")); //讄输入接口按中文编?BR>BufferedWriter stdout = new BufferedWriter(new OutputStreamWriter(System.out,"gb2312")); //讄输出接口按中文编?BR>stdout.write("误?");<BR>stdout.flush();<BR>strin = stdin.readLine();<BR>stdout.write("q是从用戯入的Ԍ"+strin);<BR>stdout.write(str);<BR>stdout.flush();<BR>}}<BR>同时Q在~译E序Ӟ我们用以下方式来q行Q?BR>javac -encoding gb2312 Read.java<BR>其运行结果如?所C:<BR> <IMG height=185 alt=6617_1.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6617_1.gif" width=424 border=0></P> <P>?</P> <P></P> <P>2?针对EJBcd不可以直接运行的支持c?如JavaBeanc? </P> <P>׃q种cd们本w被其它的类调用Q不直接与用户交互,故对q种cL_我们的徏议的处理方式是内部程序中应该采用字符来处理E序内部的中文字W串Q具体如上面一节中一PQ同Ӟ在编译类时用-encoding gb2312参数指示源文件是中文格式~码的即可?BR></P> <P>3?针对Servletc?/P> <P>针对ServletQ我们徏议用以下Ҏ(gu)Q?/P> <P>在编译Servletcȝ源程序时Q用-encoding指定~码为GBK或GB2312Q且在向用户输出时的~码部分用response对象的setContentType("text/html;charset=GBK");或gb2312来设|输出编码格式,同样在接收用戯入时Q我们用request.setCharacterEncoding("GB2312")Q这h论我们的servletcȝ植到什么操作系l中Q只有客L(fng)的浏览器支持中文昄Q就可以正确昄。如下是一个正的CZQ?/P> <P>//HelloWorld.java<BR>package hello;<BR>import java.io.*;<BR>import javax.servlet.*;<BR>import javax.servlet.http.*;<BR>public class HelloWorld extends HttpServlet<BR>{<BR>public void init() throws ServletException { }<BR>public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException<BR>{<BR>request.setCharacterEncoding("GB2312"); //讄输入~码格式<BR>response.setContentType("text/html;charset=GB2312"); //讄输出~码格式<BR>PrintWriter out = response.getWriter(); //使用PrintWriter输出<BR>out.println("<hr>");<BR>out.println("Hello World! This is created by Servlet!试中文!");<BR>out.println("<hr>");<BR>}<BR>public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException<BR>{<BR>request.setCharacterEncoding("GB2312"); //讄输入~码格式<BR>response.setContentType("text/html;charset=GB2312"); //讄输出~码格式<BR>String name = request.getParameter("name");<BR>String id = request.getParameter("id");<BR>if(name==null) name="";<BR>if(id==null) id="";<BR>PrintWriter out = response.getWriter(); //使用PrintWriter输出<BR>out.println("<hr>");<BR>out.println("你传入的中文字串是:" + name);<BR>out.println("<hr>你输入的id是:" + id);<BR>out.println("<hr>");<BR>}<BR>public void destroy() { }<BR>}<BR>L(fng)javac -encoding gb2312 HelloWorld.java来编译此E序?BR>试此Servlet的程序如下所C:<BR><%@page contentType="text/html; charset=gb2312"%><BR><%request.setCharacterEncoding("GB2312");%><BR><html><head><title></title><BR><Script language="JavaScript"><BR>function Submit() {<BR>//通过URL传递中文字W串值给Servlet<BR>document.base.action = "./HelloWorld?name=中文";<BR>document.base.method = "POST";<BR>document.base.submit();<BR>}<BR></Script><BR></head></P> <P></P> <P><body bgcolor="#FFFFFF" text="#000000" topmargin="5"><BR><form name="base" method = "POST" target="_self"><BR><input name="id" type="text" value="" size="30"><BR><a href = "JavaScript:Submit()">传给Servlet</a><BR></form></body></html><BR>其运行结果如?所C:<BR><IMG height=328 alt=6617_2.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6617_2.gif" width=407 border=0><BR></P> <P>?<BR>4?JAVAE序和数据库之间</P> <P>为避免JAVAE序和数据库之间数据传递出Cؕ码现象,我们采用以下最优方法来处理Q?BR>1?对于JAVAE序的处理方法按我们指定的方法处理?BR>2?把数据库默认支持的编码格式改为GBK或GB2312的?/P> <P>如:在mysql中,我们可以在配|文件my.ini中加入以下语句实玎ͼ<BR>在[mysqld]区增加:<BR>default-character-set=gbk<BR>q增加:<BR>[client]<BR>default-character-set=gbk<BR>在SQL Server2K中,我们可以数据库默认的语a讄为Simplified Chinese来达到目的?/P> <P>5?针对JSP代码</P> <P>׃JSP是在q行Ӟ由WEB容器q行动态编译的Q如果我们没有指定JSP源文件的~码格式Q则JSP~译器会获得服务器操作系l的file.encoding值来对JSP文g~译的,它在UL时最Ҏ(gu)出问题,如在中文win2k中可以很好运行的jsp文g拿到英文linux中就不行Q尽客L(fng)都是一L(fng)Q那是因为容器在~译JSP文g时获取的操作pȝ的编码不同造成的(在中文wink中的file.encoding和在英文Linux中file.encoding是不同的Q且英文Linux的file.encoding对中文不支持Q所以编译出来的JSPcd会有问题Q。网l上讨论的大多数是此c问题,多是因ؓJSP文gULq_时不能正显C的问题Q对于这c问题,我们了解了JAVA中程序编码{换的原理Q解册v来就Ҏ(gu)多了。我们徏议的解决办法如下Q?/P> <P>1、我们要保证JSP向客L(fng)输出时是采用中文~码方式输出的,x论如何我们首先在我们的JSP源代~中加入以下一行:</P> <P><%@page contentType="text/html; charset=gb2312"%><BR>2、ؓ了让JSP能正获得传入的参数Q我们在JSP源文件头加入下面一句:<BR><%request.setCharacterEncoding("GB2312");%><BR>3、ؓ了让JSP~译器能正确地解码我们的含有中文字符的JSP文gQ我们需要在JSP源文件中指定我们的JSP源文件的~码格式Q具体来_我们在JSP源文件头上加入下面的一句即可:<BR><%@page pageEncoding="GB2312"%>?lt;%@page pageEncoding="GBK"%><BR>q是JSP规范2.0新增加的指o?BR>我们使用此方法来解JSP文g中的中文问题Q下面的代码是一个正做法的JSP文g的测试程序:</P> <P></P> <P>//testchinese.jsp<BR><%@page pageEncoding="GB2312"%><BR><%@page contentType="text/html; charset=gb2312"%><BR><%request.setCharacterEncoding("GB2312");%><BR><%<BR>String action = request.getParameter("ACTION");<BR>String name = "";<BR>String str = "";<BR>if(action!=null && action.equals("SENT"))<BR>{<BR>name = request.getParameter("name");<BR>str = request.getParameter("str");<BR>}<BR>%><BR><html><BR><head><BR><title></title><BR><Script language="JavaScript"><BR>function Submit()<BR>{<BR>document.base.action = "?ACTION=SENT&str=传入的中?;<BR>document.base.method = "POST";<BR>document.base.submit();<BR>}<BR></Script><BR></head><BR><body bgcolor="#FFFFFF" text="#000000" topmargin="5"><BR><form name="base" method = "POST" target="_self"><BR><input type="text" name="name" value="" size="30"><BR><a href = "JavaScript:Submit()">提交</a><BR></form><BR><%<BR>if(action!=null && action.equals("SENT"))<BR>{<BR>out.println("<br>你输入的字符为:"+name);<BR>out.println("<br>你通过URL传入的字WؓQ?+str);<BR>}<BR>%><BR></body><BR></html><BR>如图7是此E序q行的结果示意图Q?BR></P> <P><IMG height=351 alt=6617_3.gif src="http://www.tkk7.com/images/blogjava_net/aojilee/article_image/6617_3.gif" width=506 border=0></P> <P>?</P> <P>5、ȝ</P> <P>在上面的详细分析中,我们清晰地给ZJAVA在处理源E序q程中的详细转换q程Qؓ我们正确解决JAVA~程中的中文问题提供了基。同Ӟ我们l出了认为是最优的解决JAVA中文问题的办法?/P> <P>6、参考资?BR>1、段明辉.Java ~程技术中汉字问题的分析及解决.<BR>http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml<BR>2?周竞?关于Java中文问题的几条分析原?BR>http://www-900.ibm.com/developerWorks/cn/java/l-javachinese/index.shtml<BR></P> <P>作者介l:abnerchaiQ高U程序员Q联pL法:<A href="mailto:josserchai@yahoo.com">josserchai@yahoo.com</A></P></SPAN></TD></TR></TBODY></TABLE><img src ="http://www.tkk7.com/aojilee/aggbug/26720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/aojilee/" target="_blank">奥吉</a> 2006-01-05 14:47 <a href="http://www.tkk7.com/aojilee/articles/26720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>servlet 和jsp qo?/title><link>http://www.tkk7.com/aojilee/articles/26715.html</link><dc:creator>奥吉</dc:creator><author>奥吉</author><pubDate>Thu, 05 Jan 2006 06:32:00 GMT</pubDate><guid>http://www.tkk7.com/aojilee/articles/26715.html</guid><wfw:comment>http://www.tkk7.com/aojilee/comments/26715.html</wfw:comment><comments>http://www.tkk7.com/aojilee/articles/26715.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/aojilee/comments/commentRss/26715.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/aojilee/services/trackbacks/26715.html</trackback:ping><description><![CDATA[     摘要: 或许Qservlet API?.3版本中最重要的一个新功能是能够为servlet和JSP面定义qo器。过滤器提供了某些早期服务器所支持的非标准“servlet链接”的一U功能强大且标准的替代品。过滤器是一个程序,它先于与之相关的servlet或JSP面q行在服务器上。过滤器可附加到一个或多个servlet或JSP面上,q且可以查进入这些资源的h信息。在q之后,qo器可以作?..  <a href='http://www.tkk7.com/aojilee/articles/26715.html'>阅读全文</a><img src ="http://www.tkk7.com/aojilee/aggbug/26715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/aojilee/" target="_blank">奥吉</a> 2006-01-05 14:32 <a href="http://www.tkk7.com/aojilee/articles/26715.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Servletqo?filter)http://www.tkk7.com/aojilee/articles/26713.html奥吉奥吉Thu, 05 Jan 2006 06:13:00 GMThttp://www.tkk7.com/aojilee/articles/26713.htmlhttp://www.tkk7.com/aojilee/comments/26713.htmlhttp://www.tkk7.com/aojilee/articles/26713.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/26713.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/26713.html什么是Servletqo?filter)Q?/STRONG>
Servlet qo器是型?Web lgQ可以链在Servlet容器的处理过E中Q拦截请求和响应Q检查和修在客户机和W(xu)eb应用E序之间交换的数据。这意味着qo器会在Servlet处理之前讉K一个进入的hQƈ在外发的响应回到客户前访问这些信息?
qo器可以被d到请?响应链中Q或者在无需影响应用E序中其?Web lg的情况下删除它们。过滤器仅只是改动请求和响应的运行时处理Q因而不应该它们直接嵌?Web 应用E序框架?
Servlet可以与一个或者多个过滤器相关联,后者将形成一个过滤器链?

~写一?Servlet qo?/B>
实现一?Servlet qo器需要三个步骤:首先要编写过滤器实现cȝE序Q然后要把该qo器添加到 Web 应用E序中(通过?Web 部v描述W?web.xml 中声明它Q,最后要把过滤器与应用程序一h包部|Ӏ?

1. ~写实现cȝE序
qo?API 一共包?3 个简单的接口QFilter、FilterChain ?FilterConfig。过滤器cd需要实?Filter 接口Q?

init()Q这个方法在容器实例化过滤器时被调用Q它主要设计用于使过滤器为处理做准备。容器ؓq个Ҏ(gu)传递一个FilterConfig对象Q其中包含着配置信息?
doFilter()Q过滤器拥有单个用于处理h和响应的Ҏ(gu)——doFilter()。这个方法接受三个输入参敎ͼ一?ServletRequest、response 和一?FilterChain 对象。FilterChain对于正确的过滤操作至关重要。doFilter()Ҏ(gu)必须调用FilterChain的doFilter()Ҏ(gu)Q除非该Ҏ(gu)用来拦截以后的下游处理。注意:qo器的一个实例可以同时服务于多个hQ意味着M׃n的变量都必须通过同步?synchronized block)来访问?
destroy()Q该Ҏ(gu)由容器在销毁过滤器实例之前调用?
? 演示了一个简单的qo器,用来计算一个客h?Web h所q大致旉?
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package cc.ejb.examples;
import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class PageTimerFilter implements Filter 
{
 private FilterConfig config = null;
 public void init(FilterConfig config) throws ServletException 
 {  
  this.config = config;
 }
 public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException
 {
  Date startTime, endTime;
  double duration;
  startTime = new Date();
  // Forward the request to the next resource in the chain
  chain.doFilter(request, response);
  // Calculate the duration between the start time and end time
  endTime = new Date();
  duration = (endTime.getTime() - startTime.getTime())/1000;//Convert from milliseconds to seconds
  StringWriter sw = new StringWriter();
  PrintWriter writer = new PrintWriter(sw);
  writer.println();
  writer.println("===============");
  writer.println("Total elapsed time is: " + duration + " seconds.");
  writer.println("===============");
  // Log the resulting string
  writer.flush();
  config.getServletContext().log(sw.getBuffer().toString());
 }
 public void destroy() {
  this.config=null;
 }
}

在doFilter()Ҏ(gu)实现中,出现在FilterChain的doFilter()Ҏ(gu)调用之前的代码都被看成是预处理,W(xu)eb资源Q包括其他过滤器、Servlet{等Q所做的处理q没有发生。而在该方法之后的代码则是后期处理Q这时外发的响应信息已经包含了Web资源的完整响应。也是_FilterChain的doFilter()调用接下来的过滤器Q在有链式关pȝ时候)或者其他Web资源?/B>

2. 配置 Servlet qo?/B>和配|ServletcMQ过滤器通过 web.xml 文g中的两个 XML 标签<filter>?lt;filter-name>来声明?lt;filter>标签负责把一个过滤器名和一个特定的cd联v来,q种兌是通过<filter-name>?lt;filter-class>元素指定。其 DTD定义如下Q?
1
(((description*,display-name*,icon*)),filter-name,filter-class,init-param*)

可以滤器指定初始化参敎ͼ和ServletcMQ参数是使用<inti-param>和成对的<param-name>?lt;param-value>来指定的Q如下所C:
1
2
3
4
<init-param>
    <param-name>counter</param-name>
       <param-value>100</param-value>
</init-param>

?2 昄?web.xml 文gQ它展示了如何声明过滤器的包含关p:
1
2
3
4
5
6
7
8
 <filter>
  <filter-name>Page Timers</filter-name>
  <filter-class>cc.ejb.examples.PageTimerFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>Page Timers</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

<filter>必须有一?lt;ulr-pattern>或?lt;servlet-name>元素。我们可以通过<ulr-pattern>来指定通配W,过滤器应用到Web资源范围Q在上面的例子中QPage Timerqo器被应用到每个Web资源。也可以通过<servlet-name>过滤器指定到某一个特定的Servlet上。应该注意这些声明的序Q所引用的过滤器名必d前面的过滤器定义l出?

3. 部v Servlet qo?/B>事实上, 部vqo器是非常单的事情。只需把过滤器cd其他 Web lgcd括在一Pq像通常所做的那样?web.xml 文gQ连同过滤器定义和过滤器映射声明Q放q?Web 应用E序l构中,servlet 容器处理之后的其他所有事情?

Servlet 2.4中的新特?/B>
我们通过下面的例子来研究Servlet 2.4的新Ҏ(gu)。例3和例4是两个很单的E序片断QJSPE序来自客L(fng)hforward到Thank.html?
1
2
3
4
5
6
<%@ page language="java" %>
<html>  
<body>
<jsp:forward page="/Thank.html"/>
</body>
</html>

1
2
3
4
5
<html>
  <body>
    Thank you for coming Filter worlds<br>
  </body>
</html>

这两个E序和上面的qo器一h包部|ƈq行Test.jspQ我们发现控制台只有一行而不是两行输出:
1
2
3
4
11:06:57,045 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 0.0 seconds.
===============

因ؓQ在Servlet 2.3 规范中的qo器只能过?Web 客户机和其所讉K的指?Web 资源之间的内宏V如果该资源然将h调度l其?Web 资源Q这里是Thank.htmlQ,׃能向q后委托的Q何请求应用过滤器?

2.4 规范消除了这个限Ӟ通过增强filter和request dispatcher的配合,qo器可以根据请求分发器(request dispatcher)所使用的方法有条g地对Webhq行qo。该功能是通过中的元素来实现的Q?

只有当request直接来自客户Q过滤器才生效,对应为REQUEST条g?
只有当request被一个请求分发器使用forward()Ҏ(gu)转到一个Web构g?采用或定?Q对应称为FORWARD条g?
cM圎ͼ只有当request被一个请求分发器使用include()Ҏ(gu)转到一个Web构g?采用或定?Q对应称为INCLUDE条g?
只有当request被一个请求分发器使用“错误信息页”机制方法{C个Web构gӞ对应UCؓERROR条g?
以上四种条g的组合用?
修改之后web.xml的如下所C:
1
2
3
4
5
6
7
8
9
10
 <filter>
  <filter-name>Page Timers</filter-name>
  <filter-class>cc.ejb.examples.PageTimerFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>Page Timers</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
 </filter-mapping>

再次部vq行q个Web应用Q结果如下:
1
2
3
4
5
6
7
8
11:17:51,165 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 0.0 seconds.
===============
11:17:51,165 INFO  [Engine] StandardContext[/Test]
===============
Total elapsed time is: 10.0 seconds.
===============

qo器的q用
在适合使用装饰qo器模式或者拦截器模式的Q何地方,(zhn)都可以使用qo器。过滤器的一些最普遍的应用如下:

加蝲Q对于到辄l的所有请求,qo器收集诸如浏览器cd、一天中的时间、{?URL {相关信息,q对它们q行日志记录?
性能Q过滤器在内定w过U\传来q在到达 servlet ?JSP 面之前解压~该内容Q然后再取得响应内容Qƈ在将响应内容发送到客户机机器之前将它{换ؓ压羃格式?
安全Q过滤器处理w䆾验证令牌的管理,q当地限制安全资源的讉KQ提C用戯行n份验证和/或将他们指引到第三方q行w䆾验证。过滤器甚至能够理讉K控制列表QAccess Control ListQACLQ,以便除了w䆾验证之外q提供授权机制。将安全逻辑攑֜qo器中Q而不是放?servlet 或?JSP 面中,q样提供了巨大的灉|性。在开发期_qo器可以关闭(?web.xml 文g中注释掉Q。在生应用中,qo器又可以再次启用。此外还可以d多个qo器,以便Ҏ(gu)需要提高安全、加密和不可拒绝的服务的{?
会话处理Q将 servlet ?JSP 面与会话处理代码؜杂在一起可能会带来相当大的ȝ。用过滤器来管理会话可以让 Web 面集中_֊考虑内容昄和委托处理,而不必担心会话管理的l节?
XSLT 转换Q不是使用Ud客户端还是用基?XML ?Web 服务Q无需把逻辑嵌入应用E序在 XML 语法之间执行转换的能力都l对是无L(fng)?

奥吉 2006-01-05 14:13 发表评论
]]>
struts单实?? http://www.tkk7.com/aojilee/articles/20974.html奥吉奥吉Tue, 22 Nov 2005 07:47:00 GMThttp://www.tkk7.com/aojilee/articles/20974.htmlhttp://www.tkk7.com/aojilee/comments/20974.htmlhttp://www.tkk7.com/aojilee/articles/20974.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/20974.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/20974.html3.JPG 
需要注意的是web-inf里面的配|文件web.xml和struts-config.xml?BR>至于详细配置先不l究。不如自动动手,看看能不能自׃西写个action出来。能惛_的只有登陆系l了。ؓ了不陷入数据库配|的泥潭。就先饶q数据库拉,假设有一个用P用户名:aoji Q密码:apple?BR>

奥吉 2005-11-22 15:47 发表评论
]]>
struts单实??http://www.tkk7.com/aojilee/articles/20965.html奥吉奥吉Tue, 22 Nov 2005 06:47:00 GMThttp://www.tkk7.com/aojilee/articles/20965.htmlhttp://www.tkk7.com/aojilee/comments/20965.htmlhttp://www.tkk7.com/aojilee/articles/20965.html#Feedback0http://www.tkk7.com/aojilee/comments/commentRss/20965.htmlhttp://www.tkk7.com/aojilee/services/trackbacks/20965.html前提条gQ已l正的安装jdk1.4 pd版本Q正的讄了jdk环境变量。正的安装了jboss3Q?pd版本。jboss能够正常的启动?BR>所需工具Q?eclipse3或?.1?BR>
1. 下蝲struts包。下载地址和项目主:http://struts.apache.org/

2.  解压~struts包到L文g夏V?BR>
3.  到解压羃的struts目录下找到webapps\struts-blank.war

4.  可以直接struts-blank.war目录Ud到jboss的部|目录下面,如:E:\jboss-403SP1\server\default\deploy\
      或者通过winrar{解压羃文gQ打开q解压羃C指定的目录,如teststruts.warQ然后将此目录拷贝到
      E:\jboss-403SP1\server\default\deploy\
      目录l构如下Q?BR>
1.jpg
      5. 启动jboss
   6. 在网上q行试.
      2.JPG
     7. 到此基本上成功了大半.


奥吉 2005-11-22 14:47 发表评论
]]>
վ֩ģ壺 ޾Ʒҹ| ձ߲| ߹ۿվ| ޾Ʒ97þĻ| һѹۿƵ| պһ| aëƬȫƵ18| ޸Ƶ߹ۿ| ĻѸ| 1234| Ʒһ߹ۿ| һձaѲ| aרav| ëƬڵ߳| Av뾫Ʒһ| ԺԺҳ| Ļ| þþþþ޾Ʒ| ߹ۿվ| þ޾Ʒgv| ձػػƴ̼Ƭ| һһ| ޳avƬ߹ۿ | ɫӰɫԴ| AVһ| ͵޾Ʒ| Ʒþһ | yellowƵ߹ۿ| ˵þþþƷ| ۺպ| պƵ| þֻоƷ10| ӰƬһѹۿ| ɫַ| mm1313޹ƷԿ| ޹˾Ʒվ| ɫŮһ˿| ƷѲ| ƹƵ߿ | ޹뾫ƷŮ˾þþò | ˳ɫ7777߹ۿ |