心的方向

新的征途......
posts - 75,comments - 19,trackbacks - 0

本文链接: http://blog.csdn.net/jrq/archive/2005/10/27/517428.aspx

正文:

1. 为了方便按列作外循环,想把ArrayList构造成一个二维数组,如下:

    ......

  ArrayList result=GetResult();

  int n=result.size();

  String[][] myArray=new String[n][]; //定义二维数组
 
  for (int i=0;i<n;i++)  //构造二维数组
  {
    ArrayList tempArray= (ArrayList)result.get(i);
    myArray[i]=(String[])tempArray.toArray();
  }

  ......

程序可以编译通过。

但在运行到myArray[i]=(String[])tempArray.toArray()时,出现java.lang.ClassCastException的错误,很奇怪。

花了一晚上时间,查了N多资料,总算搞定了。现把问题记录下来,以备参考。

2. 此事从头说起。  

ArrayList类扩展AbstractList并执行List接口。ArrayList支持可随需要而增长的动态数组。

    ArrayList有如下的构造函数:
  
        ArrayList( )
        ArrayList(Collection c)
        ArrayList(int capacity)

如果调用new ArrayList()构造时,其默认的capacity(初始容量)为10。

参见ArrayList源码,其中是这样定义的:

    public ArrayList() {
  this(10);
     }

默认初始化内部数组大小为10。为什么是10?不知道。可能SUN觉得这样比较爽吧。

程序编译后执行ArrayList.toArray(),把ArrayList转化为数组时,该数组大小仍为capacity(为10)。

当 装入的数据和capacity值不等时(小于capacity),比如只装入了5个数据,数组中后面的(capacity - size)个对象将置为null,此时当数组强制类型转换时,容易出现一些问题,如java.lang.ClassCastException异常等。

解决办法是:在用ArrayList转化为数组装数据后,使用trimToSize()重新设置数组的真实大小。


3. 本例修改后的代码修如下,可顺利运行:

    for (int i=0;i<n;i++)  //构造二维数组
      {
            ArrayList tempArray= (ArrayList)result.get(i);
            myArray[i]=(String[])tempArray.toArray(new String[0]);   //注意此处的写法
       }

 看看下面这些也许就明白了--

ArrayList.toArray()之一:

public Object[] toArray() {
  Object[] result = new Object[size];
  System.arraycopy(elementData, 0, result, 0, size);
  return result;
}

返回ArrayList元素的一个数组,注意这里虽然生成了一个新的数组,但是数组元素和集合中的元素是共享的,Collection接口中说这个是安全的,这是不严格的。

下面的例子演示了这个效果。
 
   ArrayList al=new ArrayList();
   al.add(new StringBuffer("hello"));
   Object[] a=al.toArray();
   StringBuffer sb=(StringBuffer)a[0];
   sb.append("changed");  //改变数组元素同样也改变了原来的ArrayList中的元素
   System.out.println(al.get(0));    

这里不要用String来代替StringBuffer,因为String是不可变的。


ArrayList.toArray()之二:

public Object[] toArray(Object a[]) {
  if (a.length < size)
    a = (Object[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
   System.arraycopy(elementData, 0, a, 0, size);
   if (a.length > size)
      a[size] = null;
   return a;
}

这个方法有可能不需要生成新的数组,注意到如果数组a容量过大,只在size处设置为null。

如果这个数组a足够大,就会把数据全放进去,返回的数组也是指向这个数组,(数组多余的空间存储的是null对象);要是不够大,就申请一个跟参数同样类型的数组,把值放进去,然后返回。


4. 网上的资料一:

  public String[] getPlatformIDList()
 
  {
        Vector result = new Vector();
        try
        {
            Statement stmt = conn.createStatement();
            String sql = "SELECT PlatformID FROM Platform";
            rs = stmt.executeQuery(sql);
            while(rs.next())
            {
                result.add(rs.getString(1));
            }       
            if (result.size() > 0)
            {
                String[] str = (String[]) result.toArray(); // 出现ClassCastException
                return str;
            }
            else
                return null;
        }
        catch(Exception e)
        {
            System.err.println(e);
            return null;
        }
        finally
        {
            try
            {
                rs.close();
                conn.close();
            }
            catch(Exception e2)
            {}
        }
    }

    程序运行后,发现不能将Vector类经过toArray()方法得到的Object[]直接转换成String[]。

    找到用另一个带有参数的 toArray(T[] a)方法才可以。

    将该语句改为:

    String[] str = (String[]) result.toArray(new String[1]);即告诉Vector,我要得到的数组的类型。

    回想一下,应该是java中的强制类型转换只是针对单个对象的,想要偷懒,将整个数组转换成另外一种类型的数组是不行的。


5. 网上的资料二:

    正确使用List.toArray()--
 
   在程序中,往往得到一个List,程序要求对应赋值给一个array,可以这样写程序:
 
    Long [] l = new Long[list.size()];
    for(int i=0;i<list.size();i++)
        l[i] = (Long) list.get(i);
 
    要写这些code,似乎比较繁琐,其实List提供了toArray()的方法。
    但是要使用不好,就会有ClassCastExceptiony异常。究竟这个是如何产生的,且看代码:

        List list = new ArrayList();
        list.add(new Long(1));list.add(new Long(2));
        list.add(new Long(3));list.add(new Long(4));
        Long[] l = (Long[])list.toArray();
        for(int i=0; i<l.length; i++)
            System.out.println(l[i].longValue());

    红色代码会抛java.lang.ClassCastException。

    当然,为了读出值来,你可以这样code:

        Object [] a =  list.toArray();
        for(int i=0;i<a.length;i++)
            System.out.println(((Long)a[i]).longValue());

    但是让数组丢失了类型信息,这个不是我们想要得。


    toArray()正确使用方式如下:

        1)  Long[] l = new Long[<total size>];
              list.toArray(l);
 
        2)  Long[] l = (Long []) list.toArray(new Long[0]);

        3)  Long [] a = new Long[<total size>];
              Long [] l = (Long []) list.toArray(a);

6. 总结补充:

      java sdk doc 上讲:
 
      public Object[] toArray(Object[] a)

      a--the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same  runtime type is allocated for this purpose.

      如果这个数组a足够大,就会把数据全放进去,返回的数组也是指向这个数组,(数组多余的空间存储的是null对象);要是不够大,就申请一个跟参数同样类型的数组,把值放进去,然后返回。
 
     需要注意的是:你要是传入的参数为9个大小,而list里面有5个object,那么其他的四个很可能是null , 使用的时候要特别注意。

7. 完毕。

 

                                                                                                              J.R.Q.

                                                                                                    2005.10.27凌晨于广州 

posted @ 2010-06-25 00:49 阿伟 阅读(1201) | 评论 (0)编辑 收藏

之前看网上有人发帖说有个解决办法是viewservlet.jar下找到org/eclipse/birt/report/utility下找到ParameterAccessor.class文件,现在要修改这个文件的源代码, 

你可以在你从CVS中签出的源代码中的org.eclipse.birt.report.viewer/birt/WEB-INF/classes/org/eclipse/birt/report/utility文件夹中找到ParameterAccessor.java文件,在这个java文件中找到这行:

public static final String UTF_8_ENCODE = "UTF-8"; //$NON-NLS-1$

将这行改为

public static final String UTF_8_ENCODE = "GBK"; //$NON-NLS-1$

然后将这个编译好的class文件压缩到viewservlets.jar的同等目录下,替换原来的文件”,本人也试了这种方法,但没见凑效,不过上面的解决方法好像是在birt2.1的环境下,这个没仔细试,也许对birt2.1有效吧。


本人使用birt版本2.3,解决办法如下:
在JSP中调用BIRT报表时,传的参数中有中文字符,即URL中包含中文字符,这时在BIRT端接收到的参数拼SQL语句后发现中文字符被转码,造成SQL中的条件不正确。
因为在JSP中调用BIRT是在一个JS脚本中,因此要想办法在JS中先将中文转成UTF-8,并且在BIRT获取参数后再将UTF-8转换回中文即可。
实现代码:
页面JS:
Var mychecktype = “中文”;
sqlWhere+="and t.CHECK_TYPE = '"+escape(encodeURI(mychecktype))+"'";

BIRT脚本:
sql+=decodeURI(mycondition);

posted @ 2009-07-02 09:56 阿伟 阅读(2524) | 评论 (1)编辑 收藏
 问题:

页面中写了一个函数a,在另一个函数中调用,页面用的是一个iframe框架,即通过iframesrc参数来刷新iframe中的页面,每次在第一次调用函数a时没问题,但第二次点击按钮调用函数a时老报“缺少函数”的错误?

function a(var1)
{
  ...
  return a;
}

第一次 alert(a(var1)) 沒有問題,第二次就出錯了

解决:
 

后来发现函数中返回值变量名和函数名定义为同一个名字,把返回值变量名改成其它名字后问题就解决了,好弱的一个问题啊,折腾了我半天,气愤!

改成 return b 就好了 -_-

posted @ 2008-11-27 14:58 阿伟 阅读(2257) | 评论 (0)编辑 收藏

经常遇到备份了一个几十M的SQL文件,还原时无法执行或执行一半就挂了,好像就是因为太大了,本来用MYSQL 的Administrator工具

还原备份会方便点,但有时也会出现无法还原的问题,不知如何是好,最后只能想到在命令窗口来执行SQL文件,好像还挺管用,具

体执行命令如下:
                          先进入cmd命令行;
                         然后进入mysql命令行;
                       >mysql -u admin -p
                       >*****
                       >use dbname
                mysql>source %pass%\mySQLFile.sql(这里的%pass%指的就是SQL文件所在的路径,如F:/date/mysqlDB.sql,这里路径尽量别用中

文吧,像安装ORACLE一样,中文路径可能会出现问题,用英文保险一点^_^)

posted @ 2008-09-13 00:23 阿伟 阅读(528) | 评论 (0)编辑 收藏

转自:http://www.blogjava.net/freeman1984/archive/2007/09/27/148850.html

六种异常处理的陋习

你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗?

1 OutputStreamWriter out = ...
2 java.sql.Connection conn = ...
3 try { // ⑸
4  Statement stat = conn.createStatement();
5  ResultSet rs = stat.executeQuery(
6   "select uid, name from user");
7  while (rs.next())
8  {
9   out.println("ID:" + rs.getString("uid") // ⑹
10    ",姓名:" + rs.getString("name"));
11  }
12  conn.close(); // ⑶
13  out.close();
14 }
15 catch(Exception ex) // ⑵
16 {
17  ex.printStackTrace(); //⑴,⑷
18 }


  作为一个Java程序员,你至少应该能够找出两个问题。但是,如果你不能找出全部六个问题,请继续阅读本文。

  本文讨论的不是Java异常处理的一般性原则,因为这些原则已经被大多数人熟知。我们要做的是分析各种可称为“反例”(anti-pattern)的违背优秀编码规范的常见坏习惯,帮助读者熟悉这些典型的反面例子,从而能够在实际工作中敏锐地察觉和避免这些问题。

  反例之一:丢弃异常

  代码:15行-18行。

  这段代码捕获了异常却不作任何处理,可以算得上Java编程中的杀手。从问题出现的频繁程度和祸害程度来看,它也许可以和C/C++程序的一个恶名远播的问题相提并论??不检查缓冲区是否已满。如果你看到了这种丢弃(而不是抛出)异常的情况,可以百分之九十九地肯定代码存在问题(在极少数情况下,这段代码有存在的理由,但最好加上完整的注释,以免引起别人误解)。

  这段代码的错误在于,异常(几乎)总是意味着某些事情不对劲了,或者说至少发生了某些不寻常的事情,我们不应该对程序发出的求救信号保持沉默和无动于衷。调用一下printStackTrace算不上“处理异常”。不错,调用printStackTrace对调试程序有帮助,但程序调试阶段结束之后,printStackTrace就不应再在异常处理模块中担负主要责任了。

  丢弃异常的情形非常普遍。打开JDK的ThreadDeath类的文档,可以看到下面这段说明:“特别地,虽然出现ThreadDeath是一种‘正常的情形’,但ThreadDeath类是Error而不是Exception的子类,因为许多应用会捕获所有的Exception然后丢弃它不再理睬。”这段话的意思是,虽然ThreadDeath代表的是一种普通的问题,但鉴于许多应用会试图捕获所有异常然后不予以适当的处理,所以JDK把ThreadDeath定义成了Error的子类,因为Error类代表的是一般的应用不应该去捕获的严重问题。可见,丢弃异常这一坏习惯是如此常见,它甚至已经影响到了Java本身的设计。

  那么,应该怎样改正呢?主要有四个选择:

  1、处理异常。针对该异常采取一些行动,例如修正问题、提醒某个人或进行其他一些处理,要根据具体的情形确定应该采取的动作。再次说明,调用printStackTrace算不上已经“处理好了异常”。

  2、重新抛出异常。处理异常的代码在分析异常之后,认为自己不能处理它,重新抛出异常也不失为一种选择。

  3、把该异常转换成另一种异常。大多数情况下,这是指把一个低级的异常转换成应用级的异常(其含义更容易被用户了解的异常)。

  4、不要捕获异常。

  结论一:既然捕获了异常,就要对它进行适当的处理。不要捕获异常之后又把它丢弃,不予理睬。

  反例之二:不指定具体的异常

  代码:15行。

  许多时候人们会被这样一种“美妙的”想法吸引:用一个catch语句捕获所有的异常。最常见的情形就是使用catch(Exception ex)语句。但实际上,在绝大多数情况下,这种做法不值得提倡。为什么呢?

  要理解其原因,我们必须回顾一下catch语句的用途。catch语句表示我们预期会出现某种异常,而且希望能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。由于绝大多数异常都直接或间接从java.lang.Exception派生,catch(Exception ex)就相当于说我们想要处理几乎所有的异常。

  再来看看前面的代码例子。我们真正想要捕获的异常是什么呢?最明显的一个是SQLException,这是JDBC操作中常见的异常。另一个可能的异常是IOException,因为它要操作OutputStreamWriter。显然,在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOException就要好多了。这就是说,catch语句应当尽量指定具体的异常类型,而不应该指定涵盖范围太广的Exception类。

  另一方面,除了这两个特定的异常,还有其他许多异常也可能出现。例如,如果由于某种原因,executeQuery返回了null,该怎么办?答案是让它们继续抛出,即不必捕获也不必处理。实际上,我们不能也不应该去捕获可能出现的所有异常,程序的其他地方还有捕获异常的机会??直至最后由JVM处理。

  结论二:在catch语句中尽可能指定具体的异常类型,必要时使用多个catch。不要试图处理所有可能出现的异常。

  反例之三:占用资源不释放

  代码:3行-14行。

  异常改变了程序正常的执行流程。这个道理虽然简单,却常常被人们忽视。如果程序用到了文件、Socket、JDBC连接之类的资源,即使遇到了异常,也要正确释放占用的资源。为此,Java提供了一个简化这类操作的关键词finally。

  finally是样好东西:不管是否出现了异常,Finally保证在try/catch/finally块结束之前,执行清理任务的代码总是有机会执行。遗憾的是有些人却不习惯使用finally。

  当然,编写finally块应当多加小心,特别是要注意在finally块之内抛出的异常??这是执行清理任务的最后机会,尽量不要再有难以处理的错误。

  结论三:保证所有资源都被正确释放。充分运用finally关键词。

反例之四:不说明异常的详细信息

  代码:3行-18行。

  仔细观察这段代码:如果循环内部出现了异常,会发生什么事情?我们可以得到足够的信息判断循环内部出错的原因吗?不能。我们只能知道当前正在处理的类发生了某种错误,但却不能获得任何信息判断导致当前错误的原因。

  printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程,但只提供了一些最基本的信息,未能说明实际导致错误的原因,同时也不易解读。

  因此,在出现异常时,最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。

  结论四:在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。

  反例之五:过于庞大的try块

  代码:3行-14行。

  经常可以看到有人把大量的代码放入单个try块,实际上这不是好习惯。这种现象之所以常见,原因就在于有些人图省事,不愿花时间分析一大块代码中哪几行代码会抛出异常、异常的具体类型是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大箱子,虽然东西是带上了,但要找出来可不容易。

  一些新手常常把大量的代码放入单个try块,然后再在catch语句中声明Exception,而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难,因为一大段代码中有太多的地方可能抛出Exception。

  结论五:尽量减小try块的体积。

  反例之六:输出数据不完整

  代码:7行-11行。

  不完整的数据是Java程序的隐形杀手。仔细观察这段代码,考虑一下如果循环的中间抛出了异常,会发生什么事情。循环的执行当然是要被打断的,其次,catch块会执行??就这些,再也没有其他动作了。已经输出的数据怎么办?使用这些数据的人或设备将收到一份不完整的(因而也是错误的)数据,却得不到任何有关这份数据是否完整的提示。对于有些系统来说,数据不完整可能比系统停止运行带来更大的损失。

  较为理想的处置办法是向输出设备写一些信息,声明数据的不完整性;另一种可能有效的办法是,先缓冲要输出的数据,准备好全部数据之后再一次性输出。

  结论六:全面考虑可能出现的异常以及这些异常对执行流程的影响。

  改写后的代码

  根据上面的讨论,下面给出改写后的代码。也许有人会说它稍微有点?嗦,但是它有了比较完备的异常处理机制。

OutputStreamWriter out = ...
java.sql.Connection conn = ...
try {
 Statement stat = conn.createStatement();
 ResultSet rs = stat.executeQuery(
  "select uid, name from user");
 while (rs.next())
 {
  out.println("ID:" + rs.getString("uid") + ",姓名: " + rs.getString("name"));
 }
}
catch(SQLException sqlex)
{
 out.println("警告:数据不完整");
 throw new ApplicationException("读取数据时出现SQL错误", sqlex);
}
catch(IOException ioex)
{
 throw new ApplicationException("写入数据时出现IO错误", ioex);
}
finally
{
 if (conn != null) {
  try {
   conn.close();
  }
  catch(SQLException sqlex2)
  {
   System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连接: " + sqlex2.toString());
  }
 }

 if (out != null) {
  try {
   out.close();
  }
  catch(IOException ioex2)
  {
   System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文件" + ioex2.toString());
  }
 }
}

  本文的结论不是放之四海皆准的教条,有时常识和经验才是最好的老师。如果你对自己的做法没有百分之百的信心,务必加上详细、全面的注释。

  另一方面,不要笑话这些错误,不妨问问你自己是否真地彻底摆脱了这些坏习惯。即使最有经验的程序员偶尔也会误入歧途,原因很简单,因为它们确确实实带来了“方便”。所有这些反例都可以看作Java编程世界的恶魔,它们美丽动人,无孔不入,时刻诱惑着你。也许有人会认为这些都属于鸡皮蒜毛的小事,不足挂齿,但请记住:勿以恶小而为之,勿以善小而不为。





------------------------------------------------------------------下面是一些java异常集-------------------------------------------------------------------------------------------


 

算术异常类:ArithmeticExecption

空指针异常类:NullPointerException

类型强制转换异常:ClassCastException

数组负下标异常:NegativeArrayException

数组下标越界异常:ArrayIndexOutOfBoundsException

违背安全原则异常:SecturityException

文件已结束异常:EOFException

文件未找到异常:FileNotFoundException

字符串转换为数字异常:NumberFormatException


操作数据库异常:SQLException


输入输出异常:IOException


方法未找到异常:NoSuchMethodException

java.lang.AbstractMethodError

抽象方法错误。当应用试图调用抽象方法时抛出。

java.lang.AssertionError

断言错。用来指示一个断言失败的情况。

java.lang.ClassCircularityError

类循环依赖错误。在初始化一个类时,若检测到类之间循环依赖则抛出该异常。

java.lang.ClassFormatError

类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。

java.lang.Error

错误。是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。

java.lang.ExceptionInInitializerError

初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。

java.lang.IllegalAccessError

违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常。

java.lang.IncompatibleClassChangeError

不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误。

java.lang.InstantiationError

实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.

java.lang.InternalError

内部错误。用于指示Java虚拟机发生了内部错误。

java.lang.LinkageError

链接错误。该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况。

java.lang.NoClassDefFoundError

未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。

java.lang.NoSuchFieldError

域不存在错误。当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误。

java.lang.NoSuchMethodError

方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。

java.lang.OutOfMemoryError

内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。

java.lang.StackOverflowError

堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。

java.lang.ThreadDeath

线程结束。当调用Thread类的stop方法时抛出该错误,用于指示线程结束。

java.lang.UnknownError

未知错误。用于指示Java虚拟机发生了未知严重错误的情况。

java.lang.UnsatisfiedLinkError

未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。

java.lang.UnsupportedClassVersionError

不支持的类版本错误。当Java虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候,抛出该错误。

java.lang.VerifyError

验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误。

java.lang.VirtualMachineError

虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况。


java.lang.ArithmeticException

算术条件异常。譬如:整数除零等。

java.lang.ArrayIndexOutOfBoundsException

数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

java.lang.ArrayStoreException

数组存储异常。当向数组中存放非数组声明类型对象时抛出。

java.lang.ClassCastException

类造型异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。

java.lang.ClassNotFoundException

找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

java.lang.CloneNotSupportedException

不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。

java.lang.EnumConstantNotPresentException

枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象并不包含常量时,抛出该异常。

java.lang.Exception

根异常。用以描述应用程序希望捕获的情况。

java.lang.IllegalAccessException

违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法,而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常。

java.lang.IllegalMonitorStateException

违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。

java.lang.IllegalStateException

违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常。

java.lang.IllegalThreadStateException

违法的线程状态异常。当县城尚未处于某个方法的合法调用状态,而调用了该方法时,抛出异常。

java.lang.IndexOutOfBoundsException

索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。

java.lang.InstantiationException

实例化异常。当试图通过newInstance()方法创建某个类的实例,而该类是一个抽象类或接口时,抛出该异常。

java.lang.InterruptedException

被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。

java.lang.NegativeArraySizeException

数组大小为负值异常。当使用负数大小值创建数组时抛出该异常。

java.lang.NoSuchFieldException

属性不存在异常。当访问某个类的不存在的属性时抛出该异常。

java.lang.NoSuchMethodException

方法不存在异常。当访问某个类的不存在的方法时抛出该异常。

java.lang.NullPointerException

空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。

java.lang.NumberFormatException

数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。

java.lang.RuntimeException

运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类。

java.lang.SecurityException

安全异常。由安全管理器抛出,用于指示违反安全情况的异常。

java.lang.StringIndexOutOfBoundsException

字符串索引越界异常。当使用索引值访问某个字符串中的字符,而该索引值小于0或大于等于序列大小时,抛出该异常。

java.lang.TypeNotPresentException

类型不存在异常。当应用试图以某个类型名称的字符串表达方式访问该类型,但是根据给定的名称又找不到该类型是抛出该异常。该异常与ClassNotFoundException的区别在于该异常是unchecked(不被检查)异常,而ClassNotFoundException是checked(被检查)异常。

java.lang.UnsupportedOperationException

不支持的方法异常。指明请求的方法不被支持情况的异常。

异常
javax.servlet.jsp.JspException: Cannot retrieve mapping for action /Login (/Login是你的action名字)  

可能原因
action没有再struts-config.xml 中定义,或没有找到匹配的action,例如在JSP文件中使用 <html:form action="Login.do".将表单提交给Login.do处理,如果出现上述异常,请查看struts-config.xml中的定义部分,有时可能是打错了字符或者是某些不符合规则,可以使用strutsconsole工具来检查。
-----------------------------------------------------------------------------------------------------------------
异常
org.apache.jasper.JasperException: Cannot retrieve definition for form bean null

可能原因     
      
这个异常是因为Struts根据struts-config.xml中的mapping没有找到action期望的form bean。大部分的情况可能是因为在form-bean中设置的name属性和action中设置的name属性不匹配所致。换句话说,action和form都应该各自有一个name属性,并且要精确匹配,包括大小写。这个错误当没有name属性和action关联时也会发生,如果没有在action中指定name属性,那么就没有name属性和action相关联。当然当action制作某些控制时,譬如根据参数值跳转到相应的jsp页面,而不是处理表单数据,这是就不用name属性,这也是action的使用方法之一。
-----------------------------------------------------------------------------------------------------------------
异常
No action instance for path /xxxx could be created

可能原因
特别提示:因为有很多中情况会导致这个错误的发生,所以推荐大家调高你的web服务器的日志/调试级别,这样可以从更多的信息中看到潜在的、在试图创建action类时发生的错误,这个action类你已经在struts-config.xml中设置了关联(即添加了<action>标签)。

在struts-config.xml中通过action标签的class属性指定的action类不能被找到有很多种原因,例如:定位编译后的.class文件失败。Failure to place compiled .class file for the action in the classpath (在web开发中,class的的位置在r WEB-INF/classes,所以你的action class必须要在这个目录下。例如你的action类位于WEB-INF/classes/action/Login.class,那么在struts-config.xml中设置action的属性type时就是action.Login).
拼写错误,这个也时有发生,并且不易找到,特别注意第一个字母的大小写和包的名称。
-----------------------------------------------------------------------------------------------------------------
异常
javax.servlet.jsp.JspException: No getter method for property username of bean org.apache.struts.taglib.html.BEAN

可能原因
没有位form bean中的某个变量定义getter 方法

这个错误主要发生在表单提交的FormBean中,用struts标记<html:text property=”username”>时,在FormBean中必须有一个getUsername()方法。注意字母“U”。
-----------------------------------------------------------------------------------------------------------------
异常
java.lang.NoClassDefFoundError: org/apache/struts/action/ActionForm

可能原因
这个错误主要发生在在classpath中找不到相应的Java .class文件。如果这个错误发生在web应用程序的运行时,主要是因为指定的class文件不在web server的classpath中(/WEB-INF/classes 和 /WEB-INF/lib)。在上面的错误中,原因是找不到ActionForm类。
-----------------------------------------------------------------------------------------------------------------
异常
javax.servlet.jsp.JspException: Exception creating bean of class org.apache.struts.action.ActionForm: {1}

可能原因
Instantiating Struts-provided ActionForm class directly instead of instantiating a class derived off ActionForm. This mightoccur implicitly if you specify that a form-bean is this Struts ActionForm class rather than specifying a child of this classfor the form-bean.

Not associating an ActionForm-descended class with an action can also lead to this error.
-----------------------------------------------------------------------------------------------------------------
异常
javax.servlet.jsp.JspException: Cannot find ActionMappings or ActionFormBeans collection

可能原因
不是标识Struts actionServlet的<servlet>标记就是映射.do扩展名的<sevlet-mapping>标记或者两者都没有在web.xml中声明。

在struts-config.xml中的打字或者拼写错误也可导致这个异常的发生。例如缺少一个标记的关闭符号/>。最好使用struts console工具检查一下。

另外,load-on-startup必须在web.xml中声明,这要么是一个空标记,要么指定一个数值,这个数值用来表servlet运行的优先级,数值越大优先级越低。

还有一个和使用load-on-startup有关的是使用Struts预编译JSP文件时也可能导致这个异常。
-----------------------------------------------------------------------------------------------------------------
异常
java.lang.NullPointerException at org.apache.struts.util.RequestUtils.forwardURL(RequestUtils.java:1223)

可能原因
在struts-config.xml中的forward元素缺少path属性。例如应该是如下形式:
<forward name="userhome" path="/user/userhome.jsp"/>
-----------------------------------------------------------------------------------------------------------------
异常
javax.servlet.jsp.JspException: Cannot find bean org.apache.struts.taglib.html.BEAN in any scope


 

Probable Causes
试图在Struts的form标记外使用form的子元素。这常常发生在你在</html:form>后面使用Struts的html标记。另外要注意可能你不经意使用的无主体的标记,如<html:form … />,这样web 服务器解析时就当作一个无主体的标记,随后使用的所有<html>标记都被认为是在这个标记之外的,如又使用了<html:text property=”id”>还有就是在使用taglib引入HTML标记库时,你使用的prefix的值不是html。
-----------------------------------------------------------------------------------------------------------------
异常
javax.servlet.jsp.JspException: Missing message for key xx.xx.xx

Probable Causes
这个key的值对没有在资源文件ApplicationResources.properties中定义。如果你使用eclipse时经常碰到这样的情况,当项目重新编译时,eclipse会自动将classes目录下的资源文件删除。

资源文件ApplicationResources.properties 不在classpath中应将资源文件放到 WEB-INF/classes 目录下,当然要在struts-config.xml中定义)
-----------------------------------------------------------------------------------------------------------------
异常
Cannot find message resources under key org.apache.struts.action.MESSAGE

可能原因
很显然,这个错误是发生在使用资源文件时,而Struts没有找到资源文件。

Implicitly trying to use message resources that are not available (such as using empty html:options tag instead of specifyingthe options in its body -- this assumes options are specified in ApplicationResources.properties file)

XML parser issues -- too many, too few, incorrect/incompatible versions
-----------------------------------------------------------------------------------------------------------------
异常
Strange and seemingly random characters in HTML and on screen, but not in original JSP or servlet.

可能原因
混和使用Struts的html:form标记和标准的HTML标记不正确。

使用的编码样式在本页中不支持。
-----------------------------------------------------------------------------------------------------------------
异常
"Document contained no data" in Netscape

No data rendered (completely empty) page in Microsoft Internet Explorer

可能原因
使用一个Action的派生类而没有实现perform()方法或execute()方法。在Struts1.0中实现的是perform()方法,在Struts1.1中实现的是execute()方法,但Struts1.1向后兼容perform()方法。但你使用Struts1.1创建一个Action的派生类,并且实现了execute()方法,而你在Struts1.0中运行的话,就会得到"Document contained nodata" error message in Netscape or a completely empty (no HTML whatsoever) page rendered in Microsoft Internet Explorer.”的错误信息。

---------------------------------------------------------------------------------------------------------------------------
异常
ServletException: BeanUtils.populate
解决方案
在用Struts上传文件时,遇到了javax.servlet.ServletException: BeanUtils.populate异常。
我的ActionServlet并没有用到BeanUtils这些工具类。后来仔细检查代码发现是在jsp文件里的form忘了加enctype=&quot;multipart/form-data&quot; 了。所以写程序遇到错误或异常应该从多方面考虑问题存在的可能性,想到系统提示信息以外的东西。
----------------------------------------------------------------------------------------------------------------------------
1. 定义Action后, 如果指定了name, 那么必须要定义一个与它同名的FormBean才能进行form映射.2. 如果定义Action后, 提交页面时出现 "No input attribute for mapping path..." 错误, 则需要在其input属性中定义转向的页面.3. 如果插入新的数据时出现 "Batch update row count wrong:..." 错误, 则说明XXX.hbm.xml中指定的key的类型为原始类型(int, long),因为这种类型会自动分配值, 而这个值往往会让系统认为已经存在该记录, 正确的方法是使用java.lang.Integer或java.lang.Long对象.4. 如果插入数据时出现 "argument type mismatch" 错误, 可能是你使用了Date等特殊对象, 因为struts不能自动从String型转换成Date型,所以, 你需要在Action中手动把String型转换成Date型.5. Hibernate中, Query的iterator()比list()方法快很多.6. 如果出现 "equal symbol expected" 错误, 说明你的strtus标签中包含另一个标签或者变量, 例如:
<html:select property="test" onchange="<%=test%>"/>
或者
<html:hidden property="test" value="<bean:write name="t" property="p"/>"/>
这样的情况...
---------------------------------------------------------------------------------------------------------------------------
错误:Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update原因与解决:      因为Hibernate Tools(或者Eclipse本身的Database Explorer)生成*.hbn.xml工具中包含有catalog="***"(*表示数据库名称)这样的属性,将该属性删除就可以了
---------------------------------------------------------------------------------------------------------------------------
错误:org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations)
原因与解决:
方法1 删除Set方的cascade
方法2 解决关联关系后,再删除
方法3 在many-to-one方增加cascade 但值不能是none
最后一招:
检查一下hashCode equals是否使用了id作为唯一标示的选项了;我用uuid.hex时是没有问题的;但是用了native,就不行了,怎么办?删除啊!
----------------------------------------------------------------------------------------------------------------------------
问题:今天用Tomcat 5.5.12,发现原来很好用的系统不能用了,反复测试发现页面中不能包含 taglib,否则会出现以下提示:HTTP Status 500 -type Exception reportMessage description The server encountered an internal error () that prevented it from fulfilling this request.exceptionorg.apache.jasper.JasperException: /index.jsp(1,1) Unable to read TLD "META-INF/tlds/struts-bean.tld" from JAR file"file:*****/WEB-INF/lib/struts.jar":原因:更新了工程用的lib文件夹下的jar,发布时也发布了servlet.jar和jsp-api.jar。解决:把jsp-api.jar删除就解决这个问题了。-----------------------------------------------------------------------------------------------------------------------------
错误: java.lang.NullPointerException
原因: 发现 dao 实例、 manage 实例等需要注入的东西没有被注入(俗称空指针异常)解决:这个时候,你应该查看日志文件;默认是应用服务器的 log 文件,比如 Tomcat 就是 [Tomcat 安装目录 ]/logs ;你会发现提示你:可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sf' defined in ServletContextresource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xmlorg.hibernate.HibernateException: could not configure from URL: file:src/hibernate.cfg.xml……………………….Caused by: java.io.FileNotFoundException: src\hibernate.cfg.xml可能是:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined inServletContext resource [/WEB-INF/applicationContext.xml]: Initialization of bean failed; nested exception isorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not foundorg.hibernate.MappingException: Resource: com/mcc/coupon/model/UserRole.hbm.xml not found然后你就知道原因是因为配置文件的解析出了错误,这个通过 Web 页面是看不出来的。更多的是持久化影射文件出的错误;导致了没有被解析;当然你需要的功能就无法使用了。
----------------------------------------------------------------------------------------------------------------------------
错误:StandardWrapperValve[action]: Servlet.service() for servlet action threw exception
javax.servlet.jsp.JspException: Cannot retrieve mapping for action /settlementTypeManage
或者:      type Status report      message Servlet action is not available      description The requested resource (Servlet action is not available) is not available.
原因: 同 上
----------------------------------------------------------------------------------------------------------------------------
错误StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exceptionjava.lang.ClassNotFoundException: org.apache.struts.taglib.bean.CookieTei界面错误具体描述:
org.apache.jasper.JasperException: Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.bean.CookieTei
      原因与解决:    <方案一>你的“html:”开头的标签没有放在一个<html:form>中       <方案二>重新启动你的应用服务器,自动就没有这个问题

posted @ 2008-08-26 10:06 阿伟 阅读(598) | 评论 (0)编辑 收藏
转自:http://freeman983.javaeye.com/blog/215073

创建型模式
  1、FACTORY―追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory
  
  工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。
  
  2、BUILDER―MM最爱听的就是“我爱你”这句话了,见到不同地方的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM我只要按对应的键,它就能够用相应的语言说出“我爱你”这句话了,国外的MM也可以轻松搞掂,这就是我的“我爱你”builder。(这一定比美军在伊拉克用的翻译机好卖)
  
  建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。
  
  3、FACTORY METHOD―请MM去麦当劳吃汉堡,不同的MM有不同的口味,要每个都记住是一件烦人的事情,我一般采用Factory Method模式,带着MM到服务员那儿,说“要一个汉堡”,具体要什么样的汉堡呢,让MM直接跟服务员说就行了。
  
  工厂方法模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
  
  4、PROTOTYPE―跟MM用QQ聊天,一定要说些深情的话语了,我搜集了好多肉麻的情话,需要时只要copy出来放到QQ里面就行了,这就是我的情话prototype了。(100块钱一份,你要不要)
  
  原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。
  
  5、SINGLETON―俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Sigleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)
  
  单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。
  
  结构型模式
  6、ADAPTER―在朋友聚会上碰到了一个美女Sarah,从香港来的,可我不会说粤语,她不会说普通话,只好求助于我的朋友kent了,他作为我和Sarah之间的Adapter,让我和Sarah可以相互交谈了(也不知道他会不会耍我)
  
  适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
  
  7、BRIDGE―早上碰到MM,要说早上好,晚上碰到MM,要说晚上好;碰到MM穿了件新衣服,要说你的衣服好漂亮哦,碰到MM新做的发型,要说你的头发好漂亮哦。不要问我“早上碰到MM新做了个发型怎么说”这种问题,自己用BRIDGE组合一下不就行了
  
  桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。
  
  8、COMPOSITE―Mary今天过生日。“我过生日,你要送我一件礼物。”“嗯,好吧,去商店,你自己挑。”“这件T恤挺漂亮,买,这条裙子好看,买,这个包也不错,买。”“喂,买了三件了呀,我只答应送一件礼物的哦。”“什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻烦你包起来。”“……”,MM都会用Composite模式了,你会了没有?
  
  合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。
  
  9、DECORATOR―Mary过完轮到Sarly过生日,还是不要叫她自己挑了,不然这个月伙食费肯定玩完,拿出我去年在华山顶上照的照片,在背面写上“最好的的礼物,就是爱你的Fita”,再到街上礼品店买了个像框(卖礼品的MM也很漂亮哦),再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来……,我们都是Decorator,最终都在修饰我这个人呀,怎么样,看懂了吗?
  
  装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。
  
  10、FACADE―我有一个专业的Nikon相机,我就喜欢自己手动调光圈、快门,这样照出来的照片才专业,但MM可不懂这些,教了半天也不会。幸好相机有Facade设计模式,把相机调整到自动档,只要对准目标按快门就行了,一切由相机自动调整,这样MM也可以用这个相机给我拍张照片了。
  
  门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。
  
  11、FLYWEIGHT―每天跟MM发短信,手指都累dead了,最近买了个新手机,可以把一些常用的句子存在手机里,要用的时候,直接拿出来,在前面加上MM的名字就可以发送了,再不用一个字一个字敲了。共享的句子就是Flyweight,MM的名字就是提取出来的外部特征,根据上下文情况使用。
  
  享元模式:FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。
  
  12、PROXY―跟MM在网上聊天,一开头总是“hi,你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这些话,真烦人,写个程序做为我的Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。
  
  代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
  
   行为模式
  13、CHAIN OF RESPONSIBLEITY―晚上去上英语课,为了好开溜坐到了最后一排,哇,前面坐了好几个漂亮的MM哎,找张纸条,写上“Hi,可以做我的女朋友吗?如果不愿意请向前传”,纸条就一个接一个的传上去了,糟糕,传到第一排的MM把纸条传给老师了,听说是个老处女呀,快跑!
  
  责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接
  
  起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。
  
  14、COMMAND―俺有一个MM家里管得特别严,没法见面,只好借助于她弟弟在我们俩之间传送信息,她对我有什么指示,就写一张纸条让她弟弟带给我。这不,她弟弟又传送过来一个COMMAND,为了感谢他,我请他吃了碗杂酱面,哪知道他说:“我同时给我姐姐三个男朋友送COMMAND,就数你最小气,才请我吃面。”,
  
  命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。
  
  15、INTERPRETER―俺有一个《泡MM真经》,上面有各种泡MM的攻略,比如说去吃西餐的步骤、去看电影的方法等等,跟MM约会时,只要做一个Interpreter,照着上面的脚本执行就可以了。
  
  解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合.

posted @ 2008-08-18 22:17 阿伟 阅读(283) | 评论 (0)编辑 收藏
一: 使用Limit参数优化MySQL查询
转自:http://www.blogjava.net/chenpengyi/archive/2006/07/29/60679.html

我们在做一些查询的时候总希望能避免数据库引擎做全表扫描,因为全表扫描时间长,而且其中大部分扫描对客户端而言是没有意义的。那么在 MySQL 中有那些方式是可以避免全表扫面的呢?除了我们大家很熟悉的通过使用索引列或分区等方式来进行查询的优化之外还有那些呢?

前些天看了一个老外写的程序,在 MySQL 查询中使用了很多 Limit 关键字,这就让我很感兴趣了,因为在我印象中, Limit 关键字似乎更多被使用 MySQL 数据库的程序员用来做查询分页(当然这也是一种很好的查询优化),那在这里举个例子,假设我们需要一个分页的查询 ,Oracle中一般来说都是用以下 SQL 句子实现:

SELECT * FROM

( SELECT a1.*, rownum rownum_

FROM testtable a1

WHERE rownum > 20)

 WHERE rownum_ <= 1000

       这个语句就能查询到 testtable 表中的 20 1000 记录,而且还需要嵌套查询,效率不会太高,看看 MySQL 的实现:

       SELECT * FROM testtable a1 limit 20,980;

       这样就能返回 testtable 表中的 21 条到( 20 980 =) 1000 条的记录。

       实现语法确实简单,但如果要说这里两个 SQL 语句的效率,那就很难做比较了,因为在 MySQL Limit 选项有多种不同的解释方式,不同方式下的速度差异是很大的,因此我们不能从这语句的简洁程度就说谁的效率高。

       不过对程序员来说,够简单就好,因为维护成本低,呵呵。

       下面讲讲这个 Limit 的语法吧:

       SELECT ……. --Select 语句的其他参数

[LIMIT {[offset,] row_count | row_count OFFSET offset}]

这里 offset 是偏移量(这个偏移量的起始地址是 0 ,而不是 1 ,这点很容易搞错的)顾名思义就是离开起始点的位置,而 row-count 也是很简单的,就是返回的记录的数量限制。

Eg. SELECT * FROM testtable a limit 10,20 where ….

这样就能使结果返回 10 行以后(包括 10 行自身)的符合 where 条件的 20 条记录。

那么如果没有约束条件就返回 10 29 行的记录。

       那这跟避免全表扫描有什么关系呢? 下面是 MySQL 手册对 Limit 参数优化扫描的一些说明:

在一些情况中,当你使用 LIMIT 选项而不是使用 HAVING 时, MySQL 将以不同方式处理查询。

l          如果你用 LIMIT 只选择其中一部分行,当 MySQL 一般会做完整的表扫描时,但在某些情况下会使用索引(跟 ipart 有关)。

l          如果你将 LIMIT n ORDER BY 同时使用,在 MySQL 找到了第一个符合条件的记录后,将结束排序而不是排序整个表。

l          LIMIT n DISTINCT 同时使用时, MySQL 在找到一个记录后将停止查询。

l          某些情况下, GROUP BY 能通过顺序读取键 ( 或在键上做排序 ) 来解决,并然后计算摘要直到键值改变。在这种情况下, LIMIT n 将不计算任何不必要的 GROUP

l          MySQL 完成发送第 n 行到客户端,它将放弃余下的查询。

l          LIMIT 0 选项总是快速返回一个空记录。这对检查查询并且得到结果列的列类型是有用的。

l          临时表的大小使用 LIMIT # 计算需要多少空间来解决查询。


二:在MySQL查询结果集中得到记录行号(转自:http://www.zeali.net/entry/452)

如果需要在查询语句返回的列中包含一列表示该条记录在整个结果集中的行号, ISO SQL:2003 标准提出的方法是提供 ROW_NUMBER() / RANK() 函数。 Oracle 中可以使用标准方法(8i版本以上),也可以使用非标准的 ROWNUM ; MS SQL Server 则在 2005 版本中提供了 ROW_NUMBER() 函数;但在 MySQL 中似乎还没有这样的系统自带功能。虽然 LIMIT 可以很方便的对返回的结果集数量和位置进行过滤,但过滤出来的记录的行号却没办法被 SELECT 到。据说 MySQL 是早就想增加这个功能了,但我是还没找到。

解决方法是通过预定义用户变量来实现:

set @mycnt = 0;
select (@mycnt := @mycnt + 1) as ROWNUM , othercol from tblname order by othercol;

这样查询出来的结果集中 ROWNUM 就保存了行编号信息。这个行编号信息的某种用途在于当你需要根据需要对数据按照某种规则排序并取出排序之后的某一行数据,并且希望知道这行数据在之前排序中的位置时就用得着了。比如:

set @mycnt = 0;
select * from (
    select (@mycnt := @mycnt + 1) as ROWNUM , othercol
     from tblname order by othercol
) as A where othercol=OneKeyID;

当然你也可以通过创建临时表的方法把查询结果写到某个拥有 auto_increment 字段的临时表中再做查询,但考虑到临时表在 MySQL master / slave 模式下可能产生的问题,用这样临时用户定义变量的方式来计算查询结果集每一行对应的行号还是更为简洁 -- 除非你愿意在 PHP 或其他语言脚本中对返回的整个结果集再作处理。


posted @ 2008-06-02 16:26 阿伟 阅读(869) | 评论 (0)编辑 收藏
 

开发环境:

Eclipse3.2

MyEclipse5.5.1GA

JDK1.5

 

创建一个WEB Service工程XFire,按照网上的实例开发了一个简单的HelloWorld程序,发布到TOMCAT一切OK

客户端用XFire插件开发(比较方便),需要先下载插件,步骤如下:

打开EclipseHelp菜单,选择”Software Updates”,然后再选择”Find and Install.”
选择"Search for new features to install",然后点击Next
选择"Create New Remote Site" name中输入"XFire",在eclipse update site中输入

http://dist.codehaus.org/xfire/update/
选择OK
选择Finish

2、新建一个java project。命名为“Client”,其他默认,finish

3File->New->Other ,选择“XFire”文件夹下的“Code generation from WSDL document”,打开代码生成向导,

WSDL的地址栏填入http://localhost:8080/XFire/services/HelloWorldService?wsdlOutput directory栏中点浏览按钮,选择我们刚才新建的项目Client,这两项是必填的。可选项中,package一栏可以选已经存在的包名,如果不填这一项,代码生成器会在wsdl目标命名空间的基础上创建一个。

   完成后,可以看到项目中多了XFire类库,还有package下面的生成的一些类。此时要保证IDETomcat服务器是打开的。
    
此时,在调用服务之前,还有一个重要的步骤,从XFireProject项目的右键菜单里调出Properties配置窗口,选中左面一栏中的XFire项,右面会列出所有与XFire运行有关的类库,按列表中所示的,选中一些类库,这些类库在调用本服务时是必须的。

Commons Codec(commons-codec-1.3.jar)

Commons HttpClient(commons-httpclient-3.0.jar)

如果缺少这两个JAR文件,客户端在调用WEB 服务时会出错。

   所有的配置都已经完成,最后就是编写代码完成调用。

 

Tomcat5.0下正常发布,客户端也能正常调用。然而在发布到WebSphere5.1(base)上面时,就出现了一些列问题,下面是问题简单描述(只截取了LOG中部分信息)以及解决过程。

[08-5-14 7:02:31:500 GMT] 2a29c7a6 XFireServlet  E org.codehaus.xfire.transport.http.XFireServlet  TRAS0014I: 下列异常已记录 org.springframework.beans.factory.BeanDefinitionStoreException: Error registering bean with name 'xfire.typeMappingRegistry' defined in class path resource [org/codehaus/xfire/spring/xfire.xml]: Class that bean class [org.codehaus.xfire.aegis.type.DefaultTypeMappingRegistry] depends on not found; nested exception is java.lang.NoClassDefFoundError: org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry

java.lang.NoClassDefFoundError: org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry

 

[08-5-14 7:02:31:531 GMT] 2a29c7a6 ServletInstan E SRVE0100E: 未识别出由 servlet XFireServlet 抛出的 init() 异常:javax.servlet.ServletException: Error initializing XFireServlet.

       at org.codehaus.xfire.transport.http.XFireServlet.init(XFireServlet.java:52)

[08-5-14 7:02:31:531 GMT] 2a29c7a6 WebGroup      E SRVE0020E: Servlet 错误]-[XFireServlet]:无法装入 servletorg.springframework.beans.factory.BeanDefinitionStoreException: Error registering bean with name 'xfire.typeMappingRegistry' defined in class path resource [org/codehaus/xfire/spring/xfire.xml]: Class that bean class [org.codehaus.xfire.aegis.type.DefaultTypeMappingRegistry] depends on not found; nested exception is java.lang.NoClassDefFoundError: org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry

java.lang.NoClassDefFoundError: org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry

 

[08-5-14 7:02:31:547 GMT] 2a29c7a6 WebGroup      E SRVE0026E: Servlet 错误]-[XFireServlet]:org.springframework.beans.factory.BeanDefinitionStoreException: Error registering bean with name 'xfire.typeMappingRegistry' defined in class path resource [org/codehaus/xfire/spring/xfire.xml]: Class that bean class [org.codehaus.xfire.aegis.type.DefaultTypeMappingRegistry] depends on not found; nested exception is java.lang.NoClassDefFoundError: org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry

java.lang.NoClassDefFoundError: org/codehaus/xfire/aegis/type/DefaultTypeMappingRegistry

 

上述问题出现后开始在网上大肆查找资料,中间替换过WebSpherelib里面的几个包,报的错误虽然有所变化,但仍然不能清除。最后觉得是否与JDK版本有关,因为在WebSphere启动日志里看到WebSphere用的JDK版本是1.4.1,而我所开发的XFire工程是JDK1.5,因此决定把XFire工程用JDK包换成1.4然后用1.4版本重新编译,然后导出WAR包重新在WebSphere中发布。

 

先将WebSphere下的lib包恢复到原来状态(因为中间替换过几个包)重新发布1.4版本后,错误依旧,好吧,开始替换WebSphere下的包:

1、  先将WebSphere下的lib包中的qname.jar包替换为最新版本。

2、  WebSphere下的lib包中的jdom.jar替换为jdom-1.0.jar.

3、  WebSphere下的lib包中的wsdl4j.jar包替换为wsdl4j-1.5.1.jar(本来替换为xfire-1.2.6lib里面的wsdl4j-1.6.1.jar,但替换完之后服务起不来了,其他版本的没试,在网上看到好像说wsdl4j-1.5.1解决了之前版本的什么BUG.)

4、  WebSphere下的lib包中添加:stax-api-1.0.1.jarjaxen-1.1-beta-9.jar两个包。(还有说需要添加stax-untils-20040917.jar,不过好像不添加也没问题。这些包在xfire-1.2.6lib里面都有。)

重新启动服务器,我们终于可以看到盼望已久的wsdl描述页面。

 

然后就测试客户端,注意XFire插件开发客户端程序好像必须使用JDK1.5,低版本好像不支持。(记得在工程属性里将JDK换成1.5后,然后在Java Compiler中选中“Enable project specific settings”,然后在下面的“Compiler compliance level选中5.0”,然后点Apply->ok,重新编译一下),好,编写一个测试类,运行就可以看到我们想要得到的HelloWorld了。

 

总结:注意JDK版本是否冲突。注意WebSphere下的lib中的包是否和项目中的包冲突以及包是否全。

posted @ 2008-05-14 16:36 阿伟 阅读(3456) | 评论 (1)编辑 收藏
一个不错的编写properties文件的Eclipse插件(plugin),有了它我们在编辑一些简体中文、繁体中文等Unicode文本时,就不必再使用native2ascii编码了。您可以通过Eclipse中的软件升级(Software Update)安装此插件,步骤如下:
1、展开Eclipse的Help菜单,将鼠标移到Software Update子项,在出现的子菜单中点击Find and Install;
2、在Install/Update对话框中选择Search for new features to install,点击Next;
3、在Install对话框中点击New Remote Site;
4、在New Update Site对话框的Name填入“PropEdit”或其它任意非空字符串,在URL中填入http://propedit.sourceforge.jp/eclipse/updates/;
5、在Site to include to search列表中,除上一步加入的site外的其它选项去掉,点击Finsih;
6、在弹出的Updates对话框中的Select the features to install列表中将所有结尾为“3.1.x”的选项去掉(适用于Eclipse 3.2版本的朋友);
7、点击Finish关闭对话框;
8、在下载后,同意安装,再按提示重启Eclipse,在工具条看到形似vi的按钮表示安装成功,插件可用。此时,Eclpise中所有properties文件的文件名前有绿色的P的图标作为标识。
posted @ 2008-04-15 13:10 阿伟 阅读(1818) | 评论 (2)编辑 收藏
Tomcat5.5 Administration Web Application配置
转自:http://www.blogjava.net/bisal/archive/2007/04/18/111669.html
Tomcat5.5默认安装时,并没有提供 Administration Web Application,需要另外下载安装,到这里下载:http://tomcat.apache.org/download-55.cgi ,在下载页面的Binary Distributions栏下的第四大项,Administration Web Application ,下载后解压,然后把apache-tomcat-5.5.20\conf\Catalina\localhost\admin.xml拷贝到 Tomcat 5.5\conf\Catalina\localhost下面,再把apache-tomcat-5.5.20\server\webapps下
的 admin文件夹拷贝到Tomcat5.5\server\webapps下面。

/*打开Tomcat5.5\conf\下的tomcat- users.xml,加入下面这句<user username="admin" password="admin" roles="admin, manager"/>,*/


最后重新启动tomcat就ok了。
posted @ 2008-04-11 17:01 阿伟 阅读(491) | 评论 (0)编辑 收藏

转自:http://dev.csdn.net/article/68/68297.shtm
hibernate 三种查询方式     选择自 wangyihust 的 Blog 
 

(一)HQL

HQLHibernate Qusery Language,如果你已经熟悉它,就会发现它跟SQL非常相像。不过你不要被表面的假象迷惑,HQL是面向对象的(OO,用生命的眼光看待每一个对象,他们是如此鲜活)。如果你对JAVASQL语句有一定了解的话,那么HQL对你简直易如反掌,你完全可以利用在公车上的时间掌握它。

以下从几个方面进行慢慢深入:

1
。大小些敏感
大家知道SQL-92 Query是对大小写不敏感的,但是在HQL(前面提到它是OO的)中对对象类的名称和属性确实大小写敏感的(符合java编程语法)。

HQL 子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写区分
如:sElect cat.name from Cat as catselect cat.name from Cat as cat是一样的
但是:
sElect
cat.name from CAT as catselect cat.name from Cat as cat确实不一样的。

2
from语句
最简单的:
from eg.Cat
它只是简单的返回所有eg.Cat的实例,通常我们此时会为eg.Cat其个别名,因为在query的其余部分可能会用到(参看上边关于大小写敏感时的例子情形),如:
from eg.Cat as cat 这里as可以省略。


上边只是单表查询,多表的情况如下写法:
from eg.Cat, eg.Dog
from eg.Cat as cat, eg.Dog as dog

3
join相关
(inner) join
left (outer) join
right (outer) join
full join
HQL
同样对SQL中的这些特性支持
下面插播一个小话题,关于上边的那些特性,我一直都没怎么用,今天既然说到这里,就想把上边的几个特性的用法说一下,也算对自己的一个补充:


假设有两个表:部门、员工,下面列举一些数据:
员工(Employee)
 ID     Name    DepNo
 001   Jplateau   01
 002    Jony        01
 003   Camel      02

部门(Department)
 ID  Name
 01  
研发部
 02   
营销部

Hibernate中我们操纵的都是对象,所以我们操纵的是部门类和员工


1).(inner) join
select employee.ID as id1,employee.Name as name1,

department.ID as id2,department.Name as name2  from Employee as employee

 join  Department as department on employee.DepNo=department.ID (注意到条件语句我用on 没有用where)
那么执行结果是什么呢?
id1 name1 id2 name2
++++++++++++++++++++++++++++++++++++++
001 Jplateau 01
研发部
002 Jony 01
研发部

2).left (outer) join
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee left join Department as department on employee.DepNo=
department.ID
那么执行结果又该是什么呢?
id1 name1 id2 name2
++++++++++++++++++++++++++++++++++++++
001 Jplateau 01
研发部
002 Jony 01
研发部
003 Camel null null
{
就是说此时我要已第一个表的记录多少为准,第二个表中没有相应纪录的时候填充null}
3). right (outer) join
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee right join Department as department on employee.DepNo=
department.ID
那么执行结果又该是什么呢?
id1 name1 id2 name2
++++++++++++++++++++++++++++++++++++++
001 Jplateau 01
研发部
002 Jony 01
研发部
null null 02
营销部
{
就是说此时我要已第二个表的记录多少为准,第一个表中没有相应纪录的时候填充null}

4
select语句
就是要确定你要从查询中返回哪些对象或者哪些对象的属性。写几个例子吧:
select employee form Employee as employee
select employee form Employee as employee where employee.Name like 'J%'
select employee.Name form Employee as employee where employee.Name like 'J%'
select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
as name2 from Employee as employee right join Department as department on employee.DepNo=
department.ID

select
elements(employee.Name) from Employee as employee
(不明白elements到底是做什么用的?望给于说明)
等等


5。数学函数
JDO
目前好像还不支持此类特性。
avg(...), sum(...), min(...), max(...)

count(*)

count(...), count(distinct ...), count(all...)

其用法和SQL基本相同

select distinct employee.name from Employee as employee
select count(distinct employee.name),count(employee) from Employee as employee

6
polymorphism (暂时不知道如何解释?)
from com.test.Animal as animal
不光得到所有Animal得实例,而且可以得到所有Animal的子类(如果我们定义了一个子类Cat
一个比较极端的例子
from java.lang.Object as o
可以得到所有持久类的实例

7
where语句
定义查询语句的条件,举几个例子吧:
from Employee as employee where employee.Name='Jplateau'
from Employee as employee where employee.Name like 'J%'
from Employee as employee where employee.Name like '%u'
where语句中“=”不光可以比较对象的属性,也可以比较对象,如:
select animal from com.test.Animal as animal where animal.name=dog

8
。表达式

SQL语句中大部分的表达式在HQL中都可以使用:
mathematical operators +, -, *, /

binary comparison operators =, >=, <=, <>, !=, like

logical operations and, or, not

string concatenation ||

SQL scalar functions like upper() and lower()

Parentheses ( ) indicate grouping

in, between, is null

JDBC IN parameters ?

named parameters :name, :start_date, :x1
(这种应该是另一种"?"的变通解决方法)

SQL literals 'foo', 69, '1970-01-01 10:00:01.0'

Java public static final constants eg.Color.TABBY

其他不必解释了,在这里我只想对查询中的参数问题说明一下:
大家知道在SQL中进行传递参数进行查询的时候,我们通常用PreparedStatement,在语句中写一大堆的“?”,
hql中也可以用这种方法,如:
List mates = sess.find(
"select employee.name from Employee as employee " +
"where employee.Name=? ",
name,
Hibernate.STRING
);
(
说明:上面利用Session里的find方法,在hibernateapi Session中重载了很多find方法,它可以满足你多种形式的查询)
上边是一个参数的情形,这种情况下紧接着引入参数和定义参数的类型,当为多个参数,调用另一个find方法,它的后两个
参数都是数组的形式。

还有另外一种方法来解决上边的问题,JDO也有这样的方法,不过和hibernate的表现形式上有差别,但他们两个骨子里却是
一样的,如:
Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name");
q.setString("name", "Jplateau");
//
当有多个参数的时候在此逐一定义
Iterator employees = q.iterate();

9
order 语句
sql语句没什么差别,如:
select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (
或者asc)

10
group by 语句
同样和sql语句没什么差别,如:

select employee.name,employee.DepNo from Employee as employee group by employee.DepNo

select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id
{Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.}
谁帮我解释一下上边两句,谢过!

11
。子查询
hibernate
同样支持子查询,写几个例子:

from eg.Cat as fatcat where fatcat.weight > ( select avg(cat.weight) from eg.DomesticCat cat )

(二)条件查询Criteria  Query

。数学函数
JDO
目前好像还不支持此类特性。
avg(...), sum(...), min(...), max(...)

count(*)

count(...), count(distinct ...), count(all...)

其用法和SQL基本相同

select distinct employee.name from Employee as employee
select count(distinct employee.name),count(employee) from Employee as employee

6
polymorphism (暂时不知道如何解释?)
from com.test.Animal as animal
不光得到所有Animal得实例,而且可以得到所有Animal的子类(如果我们定义了一个子类Cat
一个比较极端的例子
from java.lang.Object as o
可以得到所有持久类的实例

7
where语句
定义查询语句的条件,举几个例子吧:
from Employee as employee where employee.Name='Jplateau'
from Employee as employee where employee.Name like 'J%'
from Employee as employee where employee.Name like '%u'
where语句中“=”不光可以比较对象的属性,也可以比较对象,如:
select animal from com.test.Animal as animal where animal.name=dog

8
。表达式

SQL语句中大部分的表达式在HQL中都可以使用:
mathematical operators +, -, *, /

binary comparison operators =, >=, <=, <>, !=, like

logical operations and, or, not

string concatenation ||

SQL scalar functions like upper() and lower()

Parentheses ( ) indicate grouping

in, between, is null

JDBC IN parameters ?

named parameters :name, :start_date, :x1
(这种应该是另一种"?"的变通解决方法)

SQL literals 'foo', 69, '1970-01-01 10:00:01.0'

Java public static final constants eg.Color.TABBY

其他不必解释了,在这里我只想对查询中的参数问题说明一下:
大家知道在SQL中进行传递参数进行查询的时候,我们通常用PreparedStatement,在语句中写一大堆的“?”,
hql中也可以用这种方法,如:
List mates = sess.find(
"select employee.name from Employee as employee " +
"where employee.Name=? ",
name,
Hibernate.STRING
);
(
说明:上面利用Session里的find方法,在hibernateapi Session中重载了很多find方法,它可以满足你多种形式的查询)
上边是一个参数的情形,这种情况下紧接着引入参数和定义参数的类型,当为多个参数,调用另一个find方法,它的后两个
参数都是数组的形式。

还有另外一种方法来解决上边的问题,JDO也有这样的方法,不过和hibernate的表现形式上有差别,但他们两个骨子里却是
一样的,如:
Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name");
q.setString("name", "Jplateau");
//
当有多个参数的时候在此逐一定义
Iterator employees = q.iterate();

9
order 语句
sql语句没什么差别,如:
select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (
或者asc)

10
group by 语句
同样和sql语句没什么差别,如:

select employee.name,employee.DepNo from Employee as employee group by employee.DepNo

select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id
{Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.}
谁帮我解释一下上边两句,谢过!

11
。子查询
hibernate
同样支持子查询,写几个例子:

from eg.Cat as fatcat where fatcat.weight > ( select avg(cat.weight) from eg.DomesticCat cat )

(二)条件查询Criteria  Query

 Criteria criteria = osession.createCriteria(Owner.class);
   criteria.add(Expression.eq("age", new Integer(100)));
   criteria.setFirstResult(2);                   //从返回结果的第二条记录开始的5条记录
   criteria.setMaxResults(5);
   List lc=criteria.list();
   System.out.println("条件查询");
   System.out.println(lc.size());

(三)原生SQL语句查询

posted @ 2008-04-10 17:41 阿伟 阅读(279) | 评论 (0)编辑 收藏

Spring与Struts如何整合

转自:http://lihaiyan.javaeye.com/blog/127812
为了在Struts中加载Spring context,需要在struts-config.xml文件中加入如下部分:
<struts-config>
  <plug-in
         className="org.springframework.web.struts.ContextLoaderPlugIn">
     <set-property property="contextConfigLocation"
         value="/WEB-INF/applicationContext.xml" />
  </plug-in>
</struts-config>
第一种方法:
    通过Struts的plug-in在Struts和Spring之间提供了良好的结合点。通过plug-in我们实现了Spring context的加载,不过仅仅加载Spring context并没有什么实际的意义,还应该经过配置将Struts的Action交给Spring容器进行管理。
<action-mappings>
  <action path="/login"
             type="org.springframework.web.struts.DelegatingActionProxy"
             name="loginForm">
      <forward name="success" path="/main.jsp" />
      <forward name="failure" path="/login.jsp" />
</action>
    在form bean这个节点上与传统的Struts配置没有什么区别,而在Action上面则发生了变化。在传统的action节点上type属性写入action类的完整类名,而和Spring结合后在这点上是使用了Spring提供的DelegatingActionProxy
作为action的type属性,DelegatingActionProxy同样是org.apache.struts.action.Action的一个子类,它将把调用请求转交给真正的Action实现。通过这样的方式,Spring获得了Action实例的管理权,它将对Action进行调度,并为Struts提供所需的Action实例。这样,就可以将Action看作是Spring的一个bean,它就可以享受Spring的所有服务,如依赖注入、实例管理、事务管理等。
    在applicationContext.xml中相应的配置如下的节点:
<beans>
.......
    <bean name="/login" class="net.xiaxin.action.LoginAction"
                           singleton="false">
        <property name="userDAO">
           <ref bean="userDAOProxy" />
        </property>
    </bean>
</beans>
    最后这个bean的配置是关键,这个名为“/login”的bean与Struts中的
<action path="/login" ……>
……
</action>
节点相对应,这样,Spring Bean Name与Struts Action Path相关联,当Struts加载对应的Action时,DelegatingActionProxy就根据传入的path属性,在Spring Context寻找对应bean,并将其实例返回给Struts。与此同时,还可以看到,"/login" bean 中包含了一个userDAO 引用,Spring 在运行期将根据配置为其提供userDAO 实例,以及围绕userDAO 的事务管理服务。这样一来,对于Struts 开发而言,我们既可以延续Struts 的开发流程,也可以享受Spring 提供的事务管
理服务。而bean 的另外一个属性singleton="false",指明了Action 的实例获取方式为每次重新创建。这也解决了Struts中令人诟病的线程安全问题。
第二种方法:

为了在 struts-config.xml 文件中配置 DelegatingRequestProcessor,你需要重载 <controller> 元素的 “processorClass” 属性。 下面的几行应该放在 <action-mapping> 元素的后面。

<controller>
<set-property property="processorClass"
value="http://www.zhmy.com/org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>

增加这些设置之后,不管你查询任何类型的 Action,Sping都自动在它的context配置文件中寻找。 实际上,你甚至不需要指定类型。下面两个代码片断都可以工作:

<action path="/user" type="com.whatever.struts.UserAction"/>
<action path="/user"/>

如果你使用 Struts 的 modules 特性,你的 bean 命名必须含有 module 的前缀。 举个例子,如果一个 Action 的定义为 <action path="/user"/>,而且它的 module 前缀为“admin”, 那么它应该对应名为 <bean name="/admin/user"/> 的 bean

   
如果你在 Struts 应用中使用了 Tiles,你需要配置 <controller> 为 DelegatingTilesRequestProcessor

如果第二种方法不行,再用第一种方法。   
 至此,SS组合已经将Struts MVC以及Spring中的Bean管理、事务管理融为一体。如
果算上userDAO 中的Hibernate 部分,我们就获得了一个全面、成熟、高效、自顶而下的
Web 开发框架。

来源:http://deathmask1980.spaces.live.com/blog/cns!8633c46371110374!118.entry


posted @ 2008-04-10 16:46 阿伟 阅读(775) | 评论 (0)编辑 收藏

Struts+Spring+Hibernate实现上传下载(四)

转自:http://lihaiyan.javaeye.com/blog/127797

Web层实现

  1、Web层的构件和交互流程

  Web层包括主要3个功能:

  ·上传文件。

  ·列出所有已经上传的文件列表,以供点击下载。

  ·下载文件。

  Web层实现构件包括与2个JSP页面,1个ActionForm及一个Action:

  ·file-upload.jsp:上传文件的页面。

  ·file-list.jsp:已经上传文件的列表页面。

  ·FileActionForm:file-upload.jsp页面表单对应的ActionForm。

  ·FileAction:继承org.apache.struts.actions.DispatchAction的Action,这样这个Action就可以通过一个URL参数区分中响应不同的请求。

  Web层的这些构件的交互流程如图 6所示:

420){this.resized=true;this.style.width=420;}" border=0 resized="true">
图 6 Web层Struts流程图


  其中,在执行文件上传的请求时,FileAction在执行文件上传后,forward到loadAllFile出口中,loadAllFile加载数据库中所有已经上传的记录,然后forward到名为fileListPage的出口中,调用file-list.jsp页面显示已经上传的记录。

  2、FileAction功能

  Struts 1.0的Action有一个弱项:一个Action只能处理一种请求,Struts 1.1中引入了一个DispatchAction,允许通过URL参数指定调用Action中的某个方法,如http://yourwebsite/fileAction.do?method=upload即调用FileAction中的upload方法。通过这种方式,我们就可以将一些相关的请求集中到一个Action当中编写,而没有必要为某个请求操作编写一个Action类。但是参数名是要在struts-config.xml中配置的:

1. <struts-config>
2. <form-beans>
3. <form-bean name="fileActionForm" type="sshfile.web.FileActionForm" />
4. </form-beans>
5. <action-mappings>
6. <action name="fileActionForm" parameter="method" path="/fileAction"
7. type="sshfile.web.FileAction">
8. <forward name="fileListPage" path="/file-list.jsp" />
9. <forward name="loadAllFile" path="/fileAction.do?method=listAllFile" />
10. </action>
11. </action-mappings>
12. </struts-config>


  第6行的parameter="method"指定了承载方法名的参数,第9行中,我们还配置了一个调用FileAction不同方法的Action出口。

  FileAction共有3个请求响应的方法,它们分别是:

  ·upload(…):处理上传文件的请求。

  ·listAllFile(…):处理加载数据库表中所有记录的请求。

  ·download(…):处理下载文件的请求。

  下面我们分别对这3个请求处理方法进行讲解。

  2.1 上传文件

  上传文件的请求处理方法非常简单,简之言之,就是从Spring容器中获取业务层处理类FileService,调用其save(FileActionForm form)方法上传文件,如下所示:

1. public class FileAction
2. extends DispatchAction
3. {
4. //将上传文件保存到数据库中
5. public ActionForward upload(ActionMapping mapping, ActionForm form,
6. HttpServletRequest request,
7. HttpServletResponse response)
8. {
9. FileActionForm fileForm = (FileActionForm) form;
10. FileService fileService = getFileService();
11. fileService.save(fileForm);
12. return mapping.findForward("loadAllFile");
13. }
14. //从Spring容器中获取FileService对象
15. private FileService getFileService()
16. {
17. ApplicationContext appContext = WebApplicationContextUtils.
18. getWebApplicationContext(this.getServlet().getServletContext());
19. return (FileService) appContext.getBean("fileService");
20. }
21. …
22. }


  由于FileAction其它两个请求处理方法也需要从Spring容器中获取FileService实例,所以我们特别提供了一个getFileService()方法(第15~21行)。重构的一条原则就是:"发现代码中有重复的表达式,将其提取为一个变量;发现类中有重复的代码段,将其提取为一个方法;发现不同类中有相同的方法,将其提取为一个类"。在真实的系统中,往往拥有多个Action和多个Service类,这时一个比较好的设置思路是,提供一个获取所有Service实现对象的工具类,这样就可以将Spring 的Service配置信息屏蔽在一个类中,否则Service的配置名字散落在程序各处,维护性是很差的。

  2.2 列出所有已经上传的文件

  listAllFile方法调用Servie层方法加载T_FILE表中所有记录,并将其保存在Request域中,然后forward到列表页面中:

1. public class FileAction
2. extends DispatchAction
3. {
4. …
5. public ActionForward listAllFile(ActionMapping mapping, ActionForm form,
6. HttpServletRequest request,
7. HttpServletResponse response)
8. throws ModuleException
9. {
10. FileService fileService = getFileService();
11. List fileList = fileService.getAllFile();
12. request.setAttribute("fileList",fileList);
13. return mapping.findForward("fileListPage");
14. }
15. }


  file-list.jsp页面使用Struts标签展示出保存在Request域中的记录:

1. <%@page contentType="text/html; charset=GBK"%>
2. <%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
3. <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
4. <html>
5. <head>
6. <title>file-download</title>
7. </head>
8. <body bgcolor="#ffffff">
9. <ol>
10. <logic:iterate id="item" name="fileList" scope="request">
11. <li>
12. <a href='fileAction.do?method=download&fileId=
13. <bean:write name="item"property="fileId"/>'>
14. <bean:write name="item" property="fileName"/>
15. </a>
16. </li>
17. </logic:iterate>
18. </ol>
19. </body>
20. </html>


  展现页面的每条记录挂接着一个链接地址,形如:fileAction.do?method=download&fileId=xxx,method参数指定了这个请求由FileAction的download方法来响应,fileId指定了记录的主键。

  由于在FileActionForm中,我们定义了fileId的属性,所以在download响应方法中,我们将可以从FileActionForm中取得fileId的值。这里涉及到一个处理多个请求Action所对应的ActionForm的设计问题,由于原来的Action只能对应一个请求,那么原来的ActionForm非常简单,它仅需要将这个请求的参数项作为其属性就可以了,但现在一个Action对应多个请求,每个请求所对应的参数项是不一样的,此时的ActionForm的属性就必须是多请求参数项的并集了。所以,除了文件上传请求所对应的fileContent和remark属性外还包括文件下载的fileId属性:

420){this.resized=true;this.style.width=420;}" border=0>
图 7 FileActionForm


  当然这样会造成属性的冗余,比如在文件上传的请求中,只会用到fileContent和remark属性,而在文件下载的请求时,只会使用到fileId属性。但这种冗余是会带来好处的--它使得一个Action可以处理多个请求。

  2.3 下载文件

  在列表页面中点击一个文件下载,其请求由FileAction的download方法来响应,download方法调用业务层的FileService方法,获取文件数据并写出到response的响应流中。通过合理设置HTTP响应头参数,将响应流在客户端表现为一个下载文件对话框,其代码如下所示:

  代码 10 业务接口实现类之download

1. public class FileAction
2. extends DispatchAction
3. {
4. …
5. public ActionForward download(ActionMapping mapping, ActionForm form,
6. HttpServletRequest request,
7. HttpServletResponse response)
8. throws ModuleException
9. {
10. FileActionForm fileForm = (FileActionForm) form;
11. FileService fileService = getFileService();
12. String fileName = fileService.getFileName(fileForm.getFileId());
13. try
14. {
15. response.setContentType("application/x-msdownload");
16. response.setHeader("Content-Disposition",
17. "attachment;" + " filename="+
18. new String(fileName.getBytes(), "ISO-8859-1"));
19. fileService.write(response.getOutputStream(), fileForm.getFileId());
20. }
21. catch (Exception e)
22. {
23. throw new ModuleException(e.getMessage());
24. }
25. return null;
26. }
27. }


  第15~18行,设置HTTP响应头,将响应类型设置为application/x-msdownload MIME类型,则响应流在IE中将弹出一个文件下载的对话框,如图 4所示。IE所支持的MIME类型多达26种,您可以通过这个网址查看其他的MIME类型:

http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp

  如果下载文件的文件名含有中文字符,如果不对其进行硬编码,如第18行所示,客户文件下载对话框中出现的文件名将会发生乱码。
第19行代码获得response的输出流,作为FileServie write(OutputStream os,String fileId)的入参,这样文件的内容将写到response的输出流中。

  3、web.xml文件的配置

  Spring容器在何时启动呢?我可以在Web容器初始化来执行启动Spring容器的操作,Spring提供了两种方式启动的方法:

  ·通过org.springframework.web.context .ContextLoaderListener容器监听器,在Web容器初始化时触发初始化Spring容器,在web.xml中通过<listener></listener>对其进行配置。

  ·通过Servlet org.springframework.web.context.ContextLoaderServlet,将其配置为自动启动的Servlet,在Web容器初始化时,通过这个Servlet启动Spring容器。

  在初始化Spring容器之前,必须先初始化log4J的引擎,Spring也提供了容器监听器和自动启动Servlet两种方式对log4J引擎进行初始化:

  ·org.springframework.web.util .Log4jConfigListener

  ·org.springframework.web.util.Log4jConfigServlet

  下面我们来说明如何配置web.xml启动Spring容器:

  代码 11 web.xml中对应Spring的配置内容

1. <web-app>
2. <context-param>
3. <param-name>contextConfigLocation</param-name>
4. <param-value>/WEB-INF/applicationContext.xml</param-value>
5. </context-param>
6. <context-param>
7. <param-name>log4jConfigLocation</param-name>
8. <param-value>/WEB-INF/log4j.properties</param-value>
9. </context-param>
10. <servlet>
11. <servlet-name>log4jInitServlet</servlet-name>
12. <servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
13. <load-on-startup>1</load-on-startup>
14. </servlet>
15. <servlet>
16. <servlet-name>springInitServlet</servlet-name>
17. <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
18. <load-on-startup>2</load-on-startup>
19. </servlet>
20. …
21. </web-app>


  启动Spring容器时,需要得到两个信息:Spring配置文件的地址和Log4J属性文件,这两上信息分别通过contextConfigLocationWeb和log4jConfigLocation容器参数指定,如果有多个Spring配置文件,则用逗号隔开,如:

/WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2

  由于在启动ContextLoaderServlet之前,必须事先初始化Log4J的引擎,所以Log4jConfigServlet必须在ContextLoaderServlet之前启动,这通过<load-on-startup>来指定它们启动的先后顺序。

  乱码是开发Web应用程序一个比较老套又常见问题,由于不同Web应用服务器的默认编码是不一样的,为了方便Web应用在不同的Web应用服务器上移植,最好的做法是Web程序自身来处理编码转换的工作。经典的作法是在web.xml中配置一个编码转换过滤器,Spring就提供了一个编码过滤器类CharacterEncodingFilter,下面,我们为应用配置上这个过滤器:

1. <web-app>
2. …
3. <filter>
4. <filter-name>encodingFilter</filter-name>
5. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
6. <init-param>
7. <param-name>encoding</param-name>
8. <param-value>GBK</param-value>
9. </init-param>
10. </filter>
11. <filter-mapping>
12. <filter-name>encodingFilter</filter-name>
13. <url-pattern>/*</url-pattern>
14. </filter-mapping>
15. …
16. </web-app>


  Spring的过滤器类是org.springframework.web.filter.CharacterEncodingFilter,通过encoding参数指定编码转换类型为GBK,<filter-mapping>的配置使该过滤器截获所有的请示。

  Struts的框架也需要在web.xml中配置,想必读者朋友对Struts的配置都很熟悉,故在此不再提及,请参见本文所提供的源码。

  总结

  本文通过一个文件上传下载的Web应用,讲解了如何构建基于SSH的Web应用,通过Struts和FormFile,Spring的LobHandler以及Spring为HibernateBlob处理所提供的用户类BlobByteArrayType ,实现上传和下载文件的功能仅需要廖廖数行的代码即告完成。读者只需对程序作稍许的调整,即可处理Clob字段:

  ·领域对象对应Clob字段的属性声明为String类型;

  ·映射文件对应Clob字段的属性声明为org.springframework.orm.hibernate3.support.ClobStringType类型。

  本文通过SSH对文件上传下载简捷完美的实现得以管中窥豹了解SSH强强联合构建Web应用的强大优势。在行文中,还穿插了一些分层的设计经验,配置技巧和Spring所提供的方便类,相信这些知识对您的开发都有所裨益。

作者:陈雄华出处:天极开发


posted @ 2008-04-10 15:03 阿伟 阅读(359) | 评论 (0)编辑 收藏

Struts+Spring+Hibernate实现上传下载(三)

转自:http://lihaiyan.javaeye.com/blog/127796

业务层

  1、业务层接口

  "面向接口而非面向类编程"是Spring不遗余力所推荐的编程原则,这条原则也已经为大部开发者所接受;此外,JDK的动态代理只对接口有效,否则必须使用CGLIB生成目标类的子类。我们依从于Spring的倡导为业务类定义一个接口:

  代码 7 业务层操作接口

1. public interface FileService
2. {
3. void save(FileActionForm fileForm);//将提交的上传文件保存到数据表中
4. List getAllFile();//得到T_FILE所示记录
5. void write(OutputStream os,String fileId);//将某个文件的文件数据写出到输出流中
6. String getFileName(String fileId);//获取文件名
7. }

  其中save(FileActionForm fileForm)方法,将封装在fileForm中的上传文件保存到数据库中,这里我们使用FileActionForm作为方法入参,FileActionForm是Web层的表单数据对象,它封装了提交表单的数据。将FileActionForm直接作为业务层的接口入参,相当于将Web层传播到业务层中去,即将业务层绑定在特定的Web层实现技术中,按照分层模型学院派的观点,这是一种反模块化的设计,但在"一般"的业务系统并无需提供多种UI界面,系统Web层将来切换到另一种实现技术的可能性也微乎其微,所以笔者觉得没有必要为了这个业务层完全独立于调用层的过高目标而去搞一个额外的隔离层,浪费了原材料不说,还将系统搞得过于复杂,相比于其它原则,"简单"始终是最大的一条原则。

  getAllFile()负责获取T_FILE表所有记录,以便在网页上显示出来。

  而getFileName(String fileId)和write(OutputStream os,String fileId)则用于下载某个特定的文件。具体的调用是将Web层将response.getOutputStream()传给write(OutputStream os,String fileId)接口,业务层直接将文件数据输出到这个响应流中。具体实现请参见错误!未找到引用源。节下载文件部分。

  2、业务层接口实现类

  FileService的实现类为FileServiceImpl,其中save(FileActionForm fileForm)的实现如下所示:

  代码 8 业务接口实现类之save()

1. …
2. public class FileServiceImpl
3. implements FileService
4. {
5. private TfileDAO tfileDAO;
6. public void save(FileActionForm fileForm)
7. {
8. Tfile tfile = new Tfile();
9. try
10. {
11. tfile.setFileContent(fileForm.getFileContent().getFileData());
12. }
13. catch (FileNotFoundException ex)
14. {
15. throw new RuntimeException(ex);
16. }
17. catch (IOException ex)
18. {
19. throw new RuntimeException(ex);
20. }
21. tfile.setFileName(fileForm.getFileContent().getFileName());
22. tfile.setRemark(fileForm.getRemark());
23. tfileDAO.save(tfile);
24. }
25. …
26. }

  在save(FileActionForm fileForm)方法里,完成两个步骤:

  其一,象在水桶间倒水一样,将FileActionForm对象中的数据倒入到Tfile对象中;

  其二,调用TfileDAO保存数据。

  需要特别注意的是代码的第11行,FileActionForm的fileContent属性为org.apache.struts.upload.FormFile类型,FormFile提供了一个方便的方法getFileData(),即可获取文件的二进制数据。通过解读FormFile接口实现类DiskFile的原码,我们可能知道FormFile本身并不缓存文件的数据,只有实际调用getFileData()时,才从磁盘文件输入流中获取数据。由于FormFile使用流读取方式获取数据,本身没有缓存文件的所有数据,所以对于上传超大体积的文件,也是没有问题的;但是,由于数据持久层的Tfile使用byte[]来缓存文件的数据,所以并不适合处理超大体积的文件(如100M),对于超大体积的文件,依然需要使用java.sql.Blob类型以常规流操作的方式来处理。

  此外,通过FileForm的getFileName()方法就可以获得上传文件的文件名,如第21行代码所示。

  write(OutputStream os,String fileId)方法的实现,如代码 9所示:

  代码 9 业务接口实现类之write()

1. …
2. public class FileServiceImpl
3. implements FileService
4. {
5.
6. public void write(OutputStream os, String fileId)
7. {
8. Tfile tfile = tfileDAO.findByFildId(fileId);
9. try
10. {
11. os.write(tfile.getFileContent());
12. os.flush();
13. }
14. catch (IOException ex)
15. {
16. throw new RuntimeException(ex);
17. }
18. }
19. …
20. }

  write(OutputStream os,String fileId)也简单地分为两个操作步骤,首先,根据fileId加载表记录,然后将fileContent写入到输出流中。

  3、Spring事务配置

  下面,我们来看如何在Spring配置文件中为FileService配置声明性的事务

1. <beans>
2. …
3. <bean id="transactionManager"
4. class="org.springframework.orm.hibernate3.HibernateTransactionManager">
5. <property name="sessionFactory" ref="sessionFactory"/>
6. </bean>
7. <!-- 事务处理的AOP配置 //-->
8. <bean id="txProxyTemplate" abstract="true"
9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
10. <property name="transactionManager" ref="transactionManager"/>
11. <property name="transactionAttributes">
12. <props>
13. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
14. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
15. <prop key="save">PROPAGATION_REQUIRED</prop>
16. <prop key="write">PROPAGATION_REQUIRED,readOnly</prop>
17. </props>
18. </property>
19. </bean>
20. <bean id="fileService" parent="txProxyTemplate">
21. <property name="target">
22. <bean class="sshfile.service.FileServiceImpl">
23. <property name="tfileDAO" ref="tfileDAO"/>
24. </bean>
25. </property>
26. </bean>
27. </beans>

  Spring的事务配置包括两个部分:

  其一,定义事务管理器transactionManager,使用HibernateTransactionManager实现事务管理;

  其二,对各个业务接口进行定义,其实txProxyTemplate和fileService是父子节点的关系,本来可以将txProxyTemplate定义的内容合并到fileService中一起定义,由于我们的系统仅有一个业务接口需要定义,所以将其定义的一部分抽象到父节点txProxyTemplate中意义确实不大,但是对于真实的系统,往往拥有为数众多的业务接口需要定义,将这些业务接口定义内容的共同部分抽取到一个父节点中,然后在子节点中通过parent进行关联,就可以大大简化业务接口的配置了。

  父节点txProxyTemplate注入了事务管理器,此外还定义了业务接口事务管理的方法(允许通过通配符的方式进行匹配声明,如前两个接口方法),有些接口方法仅对数据进行读操作,而另一些接口方法需要涉及到数据的更改。对于前者,可以通过readOnly标识出来,这样有利于操作性能的提高,需要注意的是由于父类节点定义的Bean仅是子节点配置信息的抽象,并不能具体实现化一个Bean对象,所以需要特别标注为abstract="true",如第8行所示。

  fileService作为一个目标类被注入到事务代理器中,而fileService实现类所需要的tfileDAO实例,通过引用3.2节中定义的tfileDAO Bean注入。


posted @ 2008-04-10 15:01 阿伟 阅读(228) | 评论 (0)编辑 收藏

Struts+Spring+Hibernate实现上传下载(二)

转自:http://lihaiyan.javaeye.com/blog/127795

数据持久层

  1、领域对象及映射文件

  您可以使用Hibernate Middlegen、HIbernate Tools、Hibernate Syhchronizer等工具或手工的方式,编写Hibernate的领域对象和映射文件。其中对应T_FILE表的领域对象Tfile.java为:

  代码 1 领域对象Tfile

1. package sshfile.model;
2. public class Tfile
3.{
4. private String fileId;
5. private String fileName;
6. private byte[] fileContent;
7. private String remark;
8. …//getter and setter
9. }

  特别需要注意的是:数据库表为Blob类型的字段在Tfile中的fileContent类型为byte[]。Tfile的Hibernate映射文件Tfile.hbm.xml放在Tfile .java类文件的相同目录下:

  代码 2 领域对象映射文件

1. <?xml version="1.0"?>
2. <!DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
5. <hibernate-mapping>
6. <class name="sshfile.model.Tfile" table="T_FILE">
7. <id name="fileId" type="java.lang.String" column="FILE_ID">
8. <generator class="uuid.hex"/>
9. </id>
10. <property name="fileContent"
11. type="org.springframework.orm.hibernate3.support.BlobByteArrayType"
12. column="FILE_CONTENT" lazy="true"/>
13. …//其它一般字段的映射
14. </class>
15. </hibernate-mapping>

  fileContent字段映射为Spring所提供的BlobByteArrayType类型,BlobByteArrayType是用户自定义的数据类型,它实现了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取的Lob操作句柄lobHandler将byte[]的数据保存到Blob数据库字段中。这样,我们就再没有必要通过硬编码的方式,先insert然后再update来完成Blob类型数据的持久化,这个原来难伺候的老爷终于被平民化了。关于lobHandler的配置请见本文后面的内容。

  此外lazy="true"说明地返回整个Tfile对象时,并不返回fileContent这个字段的数据,只有在显式调用tfile.getFileContent()方法时才真正从数据库中获取fileContent的数据。这是Hibernate3引入的新特性,对于包含重量级大数据的表字段,这种抽取方式提高了对大字段操作的灵活性,否则加载Tfile对象的结果集时如果总是返回fileContent,这种批量的数据抽取将可以引起数据库的"洪泛效应"。

  2、DAO编写和配置

  Spring强调面向接口编程,所以我们将所有对Tfile的数据操作的方法定义在TfileDAO接口中,这些接口方法分别是:

  ·findByFildId(String fileId)

  ·save(Tfile tfile)

  ·List findAll()

  TfileDAOHibernate提供了对TfileDAO接口基于Hibernate的实现,如代码 3所示:

  代码 3 基于Hibernate 的fileDAO实现类

1. package sshfile.dao;
2.
3. import sshfile.model.*;
4. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
5. import java.util.List;
6.
7. public class TfileDAOHibernate
8. extends HibernateDaoSupport implements TfileDAO
9. {
10. public Tfile findByFildId(String fileId)
11. {
12. return (Tfile) getHibernateTemplate().get(Tfile.class, fileId);
13. }
14. public void save(Tfile tfile)
15. {
16. getHibernateTemplate().save(tfile);
17. getHibernateTemplate().flush();
18. }
19. public List findAll()
20. {
21. return getHibernateTemplate().loadAll(Tfile.class);
22. }
23. }

  TfileDAOHibernate通过扩展Spring提供的Hibernate支持类HibernateDaoSupport而建立,HibernateDaoSupport封装了HibernateTemplate,而HibernateTemplate封装了Hibernate所提供几乎所有的的数据操作方法,如execute(HibernateCallback action),load(Class entityClass, Serializable id),save(final Object entity)等等。

  所以我们的DAO只需要简单地调用父类的HibernateTemplate就可以完成几乎所有的数据库操作了。

  由于Spring通过代理Hibernate完成数据层的操作,所以原Hibernate的配置文件hibernate.cfg.xml的信息也转移到Spring的配置文件中:

  代码 4 Spring中有关Hibernate的配置信息

1. <beans>
2. <!-- 数据源的配置 //-->
3. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
4. destroy-method="close">
5. <property name="driverClassName" value="http://www.zhmy.com/oracle.jdbc.driver.OracleDriver"/>
6. <property name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/>
7. <property name="username" value="test"/>
8. <property name="password" value="test"/>
9. </bean>
10. <!-- Hibernate会话工厂配置 //-->
11. <bean id="sessionFactory"
12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
13. <property name="dataSource" ref="dataSource"/>
14. <property name="mappingDirectoryLocations">
15. <list>
16. <value>classpath:/sshfile/model</value>
17. </list>
18. </property>
19. <property name="hibernateProperties">
20. <props>
21. <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
22. <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
23. </props>
24. </property>
25. </bean>
26. <!-- Hibernate 模板//-->
27. <bean id="hibernateTemplate"
28. class="org.springframework.orm.hibernate3.HibernateTemplate">
29. <property name="sessionFactory" ref="sessionFactory"/>
30. </bean>
31. <!--DAO配置 //-->
32. <bean id="tfileDAO" class="sshfile.dao.TfileDAOHibernate">
33. <property name="hibernateTemplate" ref="hibernateTemplate" />
34. </bean>
35. …
36. </beans>

  第3~9行定义了一个数据源,其实现类是apache的BasicDataSource,第11~25行定义了Hibernate的会话工厂,会话工厂类用Spring提供的LocalSessionFactoryBean维护,它注入了数据源和资源映射文件,此外还通过一些键值对设置了Hibernate所需的属性。

  其中第16行通过类路径的映射方式,将sshfile.model类包目录下的所有领域对象的映射文件装载进来,在本文的例子里,它将装载进Tfile.hbm.xml映射文件。如果有多个映射文件需要声明,使用类路径映射方式显然比直接单独指定映射文件名的方式要简便。

  第27~30行定义了Spring代理Hibernate数据操作的HibernateTemplate模板,而第32~34行将该模板注入到tfileDAO中。

  需要指定的是Spring 1.2.5提供了两套Hibernate的支持包,其中Hibernate 2相关的封装类位于org.springframework.orm.hibernate2.*包中,而Hibernate 3.0的封装类位于org.springframework.orm.hibernate3.*包中,需要根据您所选用Hibernate版本进行正确选择。

  3、Lob字段处理的配置

  我们前面已经指出Oracle的Lob字段和一般类型的字段在操作上有一个明显的区别--那就是你必须首先通过Oracle的empty_blob()/empty_clob()初始化Lob字段,然后获取该字段的引用,通过这个引用更改其值。所以要完成对Lob字段的操作,Hibernate必须执行两步数据库访问操作,先Insert再Update。

  使用BlobByteArrayType字段类型后,为什么我们就可以象一般的字段类型一样操作Blob字段呢?可以确定的一点是:BlobByteArrayType不可能逾越Blob天生的操作方式,原来是BlobByteArrayType数据类型本身具体数据访问的功能,它通过LobHandler将两次数据访问的动作隐藏起来,使Blob字段的操作在表现上和其他一般字段业类型无异,所以LobHandler即是那个"苦了我一个,幸福十亿人"的那位幕后英雄。

  LobHandler必须注入到Hibernate会话工厂sessionFactory中,因为sessionFactory负责产生与数据库交互的Session。LobHandler的配置如代码 5所示:

  代码 5 Lob字段的处理句柄配置

1. <beans>
2. …
3. <bean id="nativeJdbcExtractor"
4. class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
5. lazy-init="true"/>
6. <bean id="lobHandler"
7. class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
8. <property name="nativeJdbcExtractor">
9. <ref local="nativeJdbcExtractor"/>
10. </property>
11. </bean>
12. …
13. </beans>

  首先,必须定义一个能够从连接池中抽取出本地数据库JDBC对象(如OracleConnection,OracleResultSet等)的抽取器:nativeJdbcExtractor,这样才可以执行一些特定数据库的操作。对于那些仅封装了Connection而未包括Statement的简单数据连接池,SimpleNativeJdbcExtractor是效率最高的抽取器实现类,但具体到apache的BasicDataSource连接池,它封装了所有JDBC的对象,这时就需要使用CommonsDbcpNativeJdbcExtractor了。Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器:

  ·WebLogic:WebLogicNativeJdbcExtractor

  ·WebSphere:WebSphereNativeJdbcExtractor

  ·JBoss:JBossNativeJdbcExtractor

  在定义了JDBC抽取器后,再定义lobHandler。Spring 1.2.5提供了两个lobHandler:

  ·DefaultLobHandler:适用于大部分的数据库,如SqlServer,MySQL,对Oracle 10g也适用,但不适用于Oracle 9i(看来Oracle 9i确实是个怪胎,谁叫Oracle 公司自己都说Oracle 9i是一个过渡性的产品呢)。

  ·OracleLobHandler:适用于Oracle 9i和Oracle 10g。

  由于我们的数据库是Oracle9i,所以使用OracleLobHandler。

  在配置完LobHandler后, 还需要将其注入到sessionFactory的Bean中,下面是调用后的sessionFactory Bean的配置:

  代码 6 将lobHandler注入到sessionFactory中的配置

1. <beans>
2. …
3. <bean id="sessionFactory"
4. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
5. <property name="dataSource" ref="dataSource"/>
6. <!-- 为处理Blob类型字段的句柄声明 //-->
7. <property name="lobHandler" ref="lobHandler"/>
8. …
9. </bean>
10. …
11. </beans>

  如第7所示,通过sessionFactory的lobHandler属性进行注入。


posted @ 2008-04-10 14:55 阿伟 阅读(285) | 评论 (0)编辑 收藏
转自:http://lihaiyan.javaeye.com/blog/127794
引言

  文件的上传和下载在
J2EE编程已经是一个非常古老的话题了,也许您马上就能掰着指头数出好几个著名的大件:如SmartUpload、Apache的FileUpload。但如果您的项目是构建在Struts+Spring+Hibernate(以下称SSH)框架上的,这些大件就显得笨重而沧桑了,SSH提供了一个简捷方便的文件上传下载的方案,我们只需要通过一些配置并辅以少量的代码就可以完好解决这个问题了。

  本文将围绕SSH文件上传下载的主题,向您详细讲述如何开发基于SSH的Web程序。SSH各框架的均为当前最新版本:

  ·Struts 1.2

  ·Spring 1.2.5

  ·Hibernate 3.0

  本文选用的数据库为
Oracle 9i,当然你可以在不改动代码的情况下,通过配置文件的调整将其移植到任何具有Blob字段类型的数据库上,如MySQL,SQLServer等。

  总体实现

  上传文件保存到T_FILE表中,T_FILE表结构如下:

420){this.resized=true;this.style.width=420;}" border=0>
图 1 T_FILE表结构

  其中:

  ·FILE_ID:文件ID,32个字符,用Hibernate的uuid.hex算法生成。

  ·FILE_NAME:文件名。

  ·FILE_CONTENT:文件内容,对应Oracle的Blob类型。

  ·REMARK:文件备注。

  文件数据存储在Blob类型的FILE_CONTENT表字段上,在Spring中采用OracleLobHandler来处理Lob字段(包括Clob和Blob),由于在程序中不需要引用到oracle数据驱动程序的具体类且屏蔽了不同数据库处理Lob字段方法上的差别,从而撤除程序在多数据库移植上的樊篱。

  1.首先数据表中的Blob字段在Java领域对象中声明为byte[]类型,而非java.sql.Blob类型。

  2.数据表Blob字段在Hibernate持久化映射文件中的type为org.springframework.orm.hibernate3.support.BlobByteArrayType,即Spring所提供的用户自定义的类型,而非java.sql.Blob。

  3.在Spring中使用org.springframework.jdbc.support.lob.OracleLobHandler处理Oracle数据库的Blob类型字段。

  通过这样的设置和配置,我们就可以象持久化表的一般字段类型一样处理Blob字段了。

  以上是Spring+Hibernate将文件二进制数据持久化到数据库的解决方案,而Struts通过将表单中file类型的组件映射为ActionForm中类型为org.apache.struts.upload. FormFile的属性来获取表单提交的文件数据。

  综上所述,我们可以通过图 2,描绘出SSH处理文件上传的方案:

420){this.resized=true;this.style.width=420;}" border=0>
图 2 SSH处理文件上传技术方案

  文件上传的页面如图 3所示:

420){this.resized=true;this.style.width=420;}" border=0 resized="true">
图 3 文件上传页面

  文件下载的页面如图 4所示:

420){this.resized=true;this.style.width=420;}" border=0 resized="true">
图 4 文件下载页面

  该工程的资源结构如图 5所示:

420){this.resized=true;this.style.width=420;}" border=0>
图 5 工程资源结构

  工程的类按SSH的层次结构划分为数据持久层、业务层和Web层;WEB-INF下的applicationContext.xml为Spring的配置文件,struts-config.xml为Struts的配置文件,file-upload.jsp为文件上传页面,file-list.jsp为文件列表页面。

  本文后面的章节将从数据持久层->业务层->Web层的开发顺序,逐层讲解文件上传下载的开发过程。
posted @ 2008-04-10 14:48 阿伟 阅读(338) | 评论 (1)编辑 收藏

转自:http://ttitfly.javaeye.com/blog/133000

Spring配置初始化ApplicationContext

1. 在struts-config.xml里,以插件的形式

xml 代码
< plug-in className="org.springframework.web.struts.ContextLoaderPlugIn" / >  
    < set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" / >  
< / plug-in >   

这种方式如果没有配置contextConfigLocation的值,则会自动加载xx-servlet.xml.

xx的值是和web.xml里的配置org.apache.struts.action.ActionServlet的servlet-name的值一样

如下:xx的值也就是 action,所以会自动加载action-servlet.xml

xml 代码
< servlet >  
    < servlet-name >action< / servlet-name >  
    < servlet-class >org.apache.struts.action.ActionServlet< / servlet-class >  
    < load-on-startup >1< / load-on-startup >  
  < / servlet >  
  < servlet-mapping >  
    < servlet-name >action< / servlet-name >  
    < url-pattern >*.do< / url-pattern >  
  < / servlet-mapping >  

 如果sturts-config.xml里配置了contextConfigLocation的值,那么就不会自动加载xx-servlet.xml了,而只会加载contextConfigLocation所指定的xml.

 2. 第2种方式

在web.xml里配置Listener

xml 代码
<listener>  
        <  listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>  
    <  /  listener>  

 

如果在web.xml里给该Listener指定要加载的xml,如:

xml 代码
<context-param>  
        <param-name>contextConfigLocationparam-name>  
        <param-value>classpath*:spring/*.xmlparam-value>  
    context-param>  

则会去加载相应的xml,而不会去加载/WEB-INF/下的applicationContext.xml。。但是,如果没有指定的话,默认会去/WEB-INF/下加载applicationContext.xml。

 

3. 第三种方式:ContextLoaderServlet

xml 代码
< servlet>    
        < servlet-name>context< / servlet-name>    
        < servlet-class>org.springframework.web.context.ContextLoaderServlet< / servlet-class>    
        < load-on-startup>1< / load-on-startup>    
    < / servlet>  

 

 这种方式和第二种Listener方式一样,唯一的区别就是用Listener方式初始化ApplicationContext,可以和用第一种方式(struts-config.xml里 plugin方式)同时存在,而ContextLoaderServlet则不可以和第一种方式同时存在

总结:

ContextLoaderServlet已经不推荐用了,它只是为了兼容低版本的servlet.jar才用的。

总的来说:Listerner要比Servlet更好一些,而且Listerner监听应用的启动和结束,而Servlet启动要稍微延迟一些。

 

posted @ 2008-04-10 10:20 阿伟 阅读(858) | 评论 (0)编辑 收藏
  转自:http://blog.tostudy.com.cn/blog/show_3574.html

优化Web应用的性能绝不象有些人想象的那样简单易行,它涉及到诸多技术,从最简单的HTML代码修改,到复杂的EJB改造,无不涉及性能问题。但有一点是非常清楚的:要想找出和解决Web应用的性能瓶颈,就必须深入全面地了解信息在Web应用中的流程。

  改善Web应用的性能不一定要局限于Web应用的Java代码,例如有些时候,简单地改动一下HTML页面的质量、减少其传输频度和数据量就可以有效地提高应用的性能表现;有时提高性能的关键却在于修改Web应用的数据库访问部分——这只是Java代码之外影响性能的两个因素,其他还有许多因素会影响到Web应用的整体性能表现。另一方面,就Java程序本身而言,其性能优化又可以分成三个领域:基本的Java代码优化,JSP/Servlet优化,EJB优化。

  一、表现层优化

  Web应用的最大性能瓶颈常常不在其他地方,而在于最基本的网络带宽限制。如果你的Web应用也面临这类问题,提高性能最简单的办法是减少HTTP传输,例如用JavaScript实现客户端编辑功能以减少数据传输次数,避免将数据发送到服务器端再执行合法性验证之类的编辑操作。

  应当采用一切可能措施减少通过网络传输的数据。例如,你可以要求浏览器缓冲模块化的JavaScript文件,在SCRIPT标记的SRC中指定:
SCRIPT LANGUAGE="JavaScript" SRC="FormChek.js"。

  其他减少网络传输应当注意的地方还包括:避免过度使用隐藏域,减少超长Cookie值,在RADIO、CHECKBOX和SELECT域中用代码来替代长长的字符串,等等。不过在HTML优化方面本文不准备作全面的讨论,因为WebSphere应用的开发者一般不会担负设计表现层的责任,只要了解下面这个原理就足够了:

  性能技巧之一:尽可能减少HTTP数据传输的总量和频度

  二、数据库访问

  朋友小A对Java的了解极为有限,但他却成功地改进了许多WebSphere应用的性能。他是怎么做到的呢?原来,小A是一个数据库专家,他通过优化数据库访问有效地改进了整个应用的性能,但对于Java,他只是略微了解一些有关JDBC的知识。在优化数据库访问时,小A做的第一件事情总是检查数据库的设计,有时他会建议重新构造数据库的结构(必须指出的是,为了提高性能而重新构造数据库结构有时可能使数据库反规格化(De-Normalization),从而带来维护方面的问题)。 
性能技巧之二:规格化(Normalization)数据库结构

  小A做的第二件事情是执行数据库分析,根据分析结果提出增加某个索引、减少某个索引的建议。完成这一步骤后,小A通常可以让应用有令人满意的性能表现,根本不必去查看应用的Java代码。

  性能技巧之三:针对常用的SQL操作建立索引,删除多余的索引

  有时,为了进一步优化应用的性能,小A会检查Java(也许应该说是SQL)代码,经常找到Java程序没有合理运用PreparedStatement和连接缓冲池的情形。只要把Statement类的动态SQL替换成PreparedStatement类的静态SQL,从连接池提取SQL连接(而不是直接创建连接),应用的性能将得到显著的改善。注意DB2 UDB(包括其他一些数据库)的PreparedStatement是可调整和配置的。

  性能技巧之四:合理运用PreparedStatement和连接池

  进一步分析应用的工作流程之后,小A有时会建议批量执行某些SQL命令,这样就只需一个对数据库服务器的请求就可以运行大量的SQL命令。

  性能技巧之五:考虑批量执行SQL命令

  既然如此,小A有时还会指出,如果应用中有些SQL命令可以组合成单个事务逻辑,那么应该可以用一个存储过程来替代。DB2 UDB的存储过程语言(SPL,Stored Procedure Language)非常强大,如果把数据库操作逻辑从Web应用转移到数据库,一般总是对性能有益。不过需要注意的是,虽然批量执行SQL命令或使用存储过程会提高性能,但就象重新构造数据库结构一样,有时会带来维护方面的困难。

  性能技巧之六:考虑使用数据库存储过程

  检查JDBC代码的时候,小A总是留意对象有没有及时正确释放。这一点其实很重要。

  性能技巧之七:及时关闭不用的Statement、ResultSet、Connection等对象(但不是在finalize方法内)

三、Java代码

  前面我们以小A的经验为例,探讨了Web应用中数据库访问性能的重要性。调整好数据库之后,接下来要做的自然是深入分析应用的Java代码。从哪里入手呢?你最好使用Java分析工具来找出性能问题的焦点所在。优化Java代码的性能是一个艰苦的过程,因此一个重要的原则是把精力集中到那些可能引起性能问题的代码上。换句话说,就是要尊重80/20规则:利用Java分析工具的结果,调整带来80%性能开销的那20%代码。

  性能技巧之八:用Java分析工具清楚地界定性能问题所在

  目前市场上已经有许多优秀的Java分析工具,例如ej-technologie的JProfile(http://www.ej-technologies.com),Klgroup的Jprobe(http://www.klg.com),以及Intuitive Systems的OptimizeIt(http://www.optimizeit.com)。不过不要忘记WebSphere Studio Application Developer(WSAD)本身也集成了一个优秀的分析器,有条件的话,最好多用几种分析工具分析Java代码。

  考虑到资金问题,你不一定乐意购买昂贵的分析软件,但你可以用Java本身的命令行工具生成分析信息。例如,在JDK 1.3中,你可以用下面的命令将TestOrderProcessing类的CPU使用情况保存到java.hprof文件:java -Xrunhprof:cpu=times,format=a,file=java.hprof TestOrderProcessing。

  这种办法的缺点是它提供的信息条理不够清楚,比较繁杂;也许可以找到一些源代码开放的工具辅助分析,但一般不如使用WSAD本身的分析工具或商业化的分析工具方便。另外,如果你已经了解哪些代码块可能引起性能问题,可以通过保存系统时间的方式获得分析信息,例如:
long startTime = System.currentTimeMillis();
// 执行某些操作
long endTime = System.currentTimeMillis();

  3.1 基本篇

  有人建议“稳定性第一,速度第二”,一般而言遵从这个建议是不会错的,但这并不妨碍我们在编写代码的同时运用某些已经证实的性能技巧。例如,我们都知道String类是不可变的,连接两个String是一项开销很大操作。

  性能技巧之九:用StringBuffer来连接两个字符串

  也许你已经注意到,SUN的许多标准Java类是线程安全的,这些类内部的同步机制实际上很容易造成性能问题。例如,Vector类就是一个线程安全的类,除非确实要用到同步机制,否则使用Vector是不值得的,如有可能,应当尽量改用非线程安全的类如ArrayList。

  性能技巧之十:只有在必要时才运用线程安全的类

  许多人习惯使用System.out.println来输出跟踪信息,但println要占用不少资源,所以输出跟踪信息最好使用专用日志记录框架,如IBM的JRas或Apache的Log4j。

  性能技巧之十一:用日志记录框架类输出跟踪信息,而不是使用System.out.println

  最后一个提高代码性能的简单技巧是清除类里面的调试信息,减小类的体积。IBM有一个WSAD插件,它提供了一个叫做setDebugInfo的任务,可以从Ant脚本调用。

  性能技巧之十二:从正式发行的软件中删除调试信息

posted @ 2008-04-08 13:03 阿伟 阅读(198) | 评论 (0)编辑 收藏
web.xml配置的详细说明3
7 指定欢迎页

假如用户提供了一个像http: //host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL,会发生什么事情呢?用户能得到一个目录表?一个错误?还是标准文件的内容?如果得到标准文件内容,是 index.html、index.jsp、default.html、default.htm或别的什么东西呢?
Welcome-file-list 元素及其辅助的welcome-file元素解决了这个模糊的问题。例如,下面的web.xml项指出,如果一个URL给出一个目录名但未给出文件名,服务器应该首先试用index.jsp,然后再试用index.html。如果两者都没有找到,则结果有赖于所用的服务器(如一个目录列表)。
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
虽然许多服务器缺省遵循这种行为,但不一定必须这样。因此,明确地使用welcom-file-list保证可移植性是一种良好的习惯。

8 指定处理错误的页面

现在我了解到,你在开发servlet和JSP页面时从不会犯错误,而且你的所有页面是那样的清晰,一般的程序员都不会被它们的搞糊涂。但是,是人总会犯错误的,用户可能会提供不合规定的参数,使用不正确的URL或者不能提供必需的表单字段值。除此之外,其它开发人员可能不那么细心,他们应该有些工具来克服自己的不足。
error-page元素就是用来克服这些问题的。它有两个可能的子元素,分别是:error-code和exception- type。第一个子元素error-code指出在给定的HTTP错误代码出现时使用的URL。第二个子元素excpetion-type指出在出现某个给定的Java异常但未捕捉到时使用的URL。error-code和exception-type都利用location元素指出相应的URL。此 URL必须以/开始。location所指出的位置处的页面可通过查找HttpServletRequest对象的两个专门的属性来访问关于错误的信息,这两个属性分别是:javax.servlet.error.status_code和javax.servlet.error.message。
可回忆一下,在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住,error-page出现在web.xml文件的末尾附近,servlet、servlet-name和welcome-file-list之后即可。

8.1 error-code元素
为了更好地了解error-code元素的值,可考虑一下如果不正确地输入文件名,大多数站点会作出什么反映。这样做一般会出现一个404错误信息,它表示不能找到该文件,但几乎没提供更多有用的信息。另一方面,可以试一下在www.microsoft.comwww.ibm.com 处或者特别是在www.bea.com 处输出未知的文件名。这是会得出有用的消息,这些消息提供可选择的位置,以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上rm-error-page子元素)。由form-login-page给出的HTML表单必须具有一个j_security_check的 ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。
例如,程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令,并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。

程序清单5-19 web.xml(说明login-config的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<security-constraint> ... </security-constraint>
<login-config>
<auth-method> FORM </auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login-error.jsp</form-error-page>
</form-login-config>
</login-config>
<!-- ... -->
</web-app>

8.2 exception-type元素
error-code元素处理某个请求产生一个特定的HTTP状态代码时的情况。然而,对于servlet或JSP页面返回200但产生运行时异常这种同样是常见的情况怎么办呢?这正是exception-type元素要处理的情况。只需提供两样东西即可:即提供如下的一个完全限定的异常类和一个位置:
<error-page>
<exception-type>packageName.className</exception-type>
<location>/SomeURL</location>
</error-page>
这样,如果Web应用中的任何servlet或JSP页面产生一个特定类型的未捕捉到的异常,则使用指定的URL。此异常类型可以是一个标准类型,如javax.ServletException或java.lang.OutOfMemoryError,或者是一个专门针对你的应用的异常。
例如,程序清单5-15给出了一个名为DumbDeveloperException的异常类,可用它来特别标记经验较少的程序员(不是说你的开发组中一定有这种人)所犯的错误。这个类还包含一个名为dangerousComputation的静态方法,它时不时地生成这种类型的异常。程序清单5-16给出对随机整数值调用dangerousCompution的一个JSP页面。在抛出此异常时,如程序清单5-18的web.xml版本中所给出的exception-type所指出的那样,对客户机显示DDE.jsp(程序清单5-17)。图5-16和图5-17分别给出幸运和不幸的结果。

程序清单5-15 DumbDeveloperException.java
package moreservlets;

/** Exception used to flag particularly onerous
programmer blunders. Used to illustrate the
exception-type web.xml element.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* &copy; 2002 Marty Hall; may be freely used or adapted.
*/

public class DumbDeveloperException extends Exception {
public DumbDeveloperException() {
super("Duh. What was I *thinking*?");
}

public static int dangerousComputation(int n)
throws DumbDeveloperException {
if (n < 5) {
return(n + 10);
} else {
throw(new DumbDeveloperException());
}
}
}


程序清单5-16 RiskyPage.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>Risky JSP Page</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2>Risky Calculations</H2>
<%@ page import="moreservlets.*" %>
<% int n = ((int)(10 * Math.random())); %>
<UL>
<LI>n: <%= n %>
<LI>dangerousComputation(n):
<%= DumbDeveloperException.dangerousComputation(n) %>
</UL>
</BODY></HTML>


程序清单5-17 DDE.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>Dumb</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2>Dumb Developer</H2>
We're brain dead. Consider using our competitors.
</BODY></HTML>


程序清单5-18 web.xml(为异常指定错误页面的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<servlet> … </servlet>
<!-- ... -->
<error-page>
<exception-type>
moreservlets.DumbDeveloperException
</exception-type>
<location>/DDE.jsp</location>
</error-page>
<!-- ... -->
</web-app>

9 提供安全性

利用web.xml中的相关元素为服务器的内建功能提供安全性。
9.1 指定验证的方法
使用login-confgi元素规定服务器应该怎样验证试图访问受保护页面的用户。它包含三个可能的子元素,分别是:auth-method、realm-name和form-login-config。login-config元素应该出现在web.xml部署描述符文件的结尾附近,紧跟在security-constraint元素之后。
l auth-method
login-config的这个子元素列出服务器将要使用的特定验证机制。有效值为BASIC、DIGEST、FORM和CLIENT-CERT。服务器只需要支持BASIC和FORM。
BASIC指出应该使用标准的HTTP验证,在此验证中服务器检查Authorization头。如果缺少这个头则返回一个401状态代码和一个WWW-Authenticate头。这导致客户机弹出一个用来填写Authorization头的对话框。此机制很少或不提供对攻击者的防范,这些攻击者在Internet连接上进行窥探(如通过在客户机的子网上执行一个信息包探测装置),因为用户名和口令是用简单的可逆base64编码发送的,他们很容易得手。所有兼容的服务器都需要支持BASIC验证。
DIGEST指出客户机应该利用加密Digest Authentication形式传输用户名和口令。这提供了比BASIC验证更高的防范网络截取得的安全性,但这种加密比SSL(HTTPS)所用的方法更容易破解。不过,此结论有时没有意义,因为当前很少有浏览器支持Digest Authentication,所以servlet容器不需要支持它。
FORM指出服务器应该检查保留的会话cookie并且把不具有它的用户重定向到一个指定的登陆页。此登陆页应该包含一个收集用户名和口令的常规HTML表单。在登陆之后,利用保留会话级的cookie跟踪用户。虽然很复杂,但FORM验证防范网络窥探并不比BASIC验证更安全,如果有必要可以在顶层安排诸如SSL或网络层安全(如IPSEC或VPN)等额外的保护。所有兼容的服务器都需要支持FORM验证。
CLIENT-CERT规定服务器必须使用HTTPS(SSL之上的HTTP)并利用用户的公开密钥证书(Pulic Key Certificat)对用户进行验证。这提供了防范网络截取的很强的安全性,但只有兼容J2EE的服务器需要支持它。
l realm-name
此元素只在auth-method为BASIC时使用。它指出浏览器在相应对话框标题使用的、并作为Authorization头组成部分的安全域的名称。
l form-login-config
此元素只在auth-method为FORM时适用。它指定两个页面,分别是:包含收集用户名及口令的HTML表单的页面(利用form-login-page子元素),用来指示验证失败的页面(利用form-error-page子元素)。由form-login-page给出的HTML表单必须具有一个j_security_check的ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。
例如,程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令,并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。

程序清单5-19 web.xml(说明login-config的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<security-constraint> ... </security-constraint>
<login-config>
<auth-method> FORM </auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login-error.jsp</form-error-page>
</form-login-config>
</login-config>
<!-- ... -->
</web-app>


9.2 限制对Web资源的访问
现在,可以指示服务器使用何种验证方法了。"了不起,"你说道,"除非我能指定一个来收到保护的 URL,否则没有多大用处。"没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在 web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素,分别是:web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小节对它们进行介绍。
l web-resource-collection
此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的 HTTP命令(GET、POST等,缺省为所有方法)的http-method元素和一个提供资料的可选description元素组成。例如,下面的 Web-resource-collection项(在security-constratint元素内)指出Web应用的proprietary目录中所有文档应该受到保护。
<security-constraint>
<web-resource-coolection>
<web-resource-name>Proprietary</web-resource-name>
<url-pattern>/propritary/*</url-pattern>
</web-resource-coolection>
<!-- ... -->
</security-constraint>
重要的是应该注意到,url-pattern仅适用于直接访问这些资源的客户机。特别是,它不适合于通过MVC体系结构利用 RequestDispatcher来访问的页面,或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如,servlet可利用MVC体系结构查找数据,把它放到bean中,发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面,而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是,这种不匀称的行为可能让开发人员放松警惕,使他们偶然对应受保护的资源提供不受限制的访问。
l auth-constraint
尽管web-resource-collention元素质出了哪些URL应该受到保护,但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role- name元素,以及包含(可选)一个描述角色的description元素。例如,下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna(或两者)的用户具有指定资源的访问权。
<security-constraint>
<web-resource-coolection> ... </web-resource-coolection>
<auth-constraint>
<role-name>administrator</role-name>
<role-name>kahuna</role-name>
</auth-constraint>
</security-constraint>
重要的是认识到,到此为止,这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令,完全有赖于具体的系统。
例如,Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联,正如下面例子中所示,它指出用户joe(口令bigshot)和jane(口令enaj)属于administrator和kahuna角色。
<tomcat-users>
<user name="joe" password="bigshot" roles="administrator,kahuna" />
<user name="jane" password="enaj" roles="kahuna" />
</tomcat-users>
l user-data-constraint
这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素(合法值为NONE、 INTEGRAL或CONFIDENTIAL),并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL。例如,下面指示服务器只允许对相关资源做 HTTPS连接:
<security-constraint>
<!-- ... -->
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
l display-name
security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。
9.3 分配角色名
迄今为止,讨论已经集中到完全由容器(服务器)处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。
例如,容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面,但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法,并据此修改访问。
Servlet的 security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如,假如编写了一个调用 request.isUserInRole("boss")的servlet,但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。
<servlet>
<!-- ... -->
<security-role-ref>
<role-name>boss</role-name> <!-- New alias -->
<role-link>manager</role-link> <!-- Real name -->
</security-role-ref>
</servlet>
也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。

10 控制会话超时

如果某个会话在一定的时间内未被访问,服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法,则缺省的超时值由具体的服务器决定。但可利用session-config和session- timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟,因此,下面的例子设置缺省会话超时值为三个小时(180分钟)。
<session-config>
<session-timeout>180</session-timeout>
</session-config>

11 Web应用的文档化

越来越多的开发环境开始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio(写此文时,已被Macromedia收购)以及IBM VisuaAge for Java等。
大量的web.xml元素不仅是为服务器设计的,而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。
可回忆一下,在web.xml内以适当地次序声明web-app子元素很重要。不过,这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。
l icon
icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像,用large-icon元素指定一幅32 x 32的图像。下面举一个例子:
<icon>
<small-icon>/images/small-book.gif</small-icon>
<large-icon>/images/tome.jpg</large-icon>
</icon>
l display-name
display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。
<display-name>Rare Books</display-name>
l description
description元素提供解释性文本,如下所示:
<description>
This Web application represents the store developed for
rare-books.com, an online bookstore specializing in rare
and limited-edition books.
</description>

12 关联文件与MIME类型

服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如,将会自动给予名为mom.jpg的文件一个image/jpeg的MIME 类型。但是,假如你的Web应用具有几个不寻常的文件,你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素(具有 extension和mime-type子元素)可提供这种保证。例如,下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。
<mime-mapping>
<extension>foo</extension>
<mime-type>application/x-fubar</mime-type>
</mime-mapping>
或许,你的Web应用希望重载(override)标准的映射。例如,下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本(text/plain)而不是作为PostScript(application/postscript)。
<mime-mapping>
<extension>ps</extension>
<mime-type>application/postscript</mime-type>
</mime-mapping>


13 定位TLD

JSP taglib元素具有一个必要的uri属性,它给出一个TLD(Tag Library Descriptor)文件相对于Web应用的根的位置。TLD文件的实际名称在发布新的标签库版本时可能会改变,但我们希望避免更改所有现有JSP页面。此外,可能还希望使用保持taglib元素的简练性的一个简短的uri。这就是部署描述符文件的taglib元素派用场的所在了。Taglib包含两个子元素:taglib-uri和taglib-location。taglib-uri元素应该与用于JSP taglib元素的uri属性的东西相匹配。Taglib-location元素给出TLD文件的实际位置。例如,假如你将文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。现在,假如web.xml在web-app元素内包含下列内容。
<taglib>
<taglib-uri>/charts.tld</taglib-uri>
<taglib-location>
/WEB-INF/tlds/chart-tags-1.3beta.tld
</taglib-location>
</taglib>
给出这个说明后,JSP页面可通过下面的简化形式使用标签库。
<%@ taglib uri="/charts.tld" prefix="somePrefix" %>

14 指定应用事件监听程序

应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内,listener-class元素列出监听程序的完整的限定类名,如下所示:
<listener>
<listener-class>package.ListenerClass</listener-class>
</listener>
虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用 web.xml DTD的2.3版本,而不是2.2版本。
例如,程序清单5-20给出一个名为ContextReporter的简单的监听程序,只要Web应用的Servlet-Context建立(如装载Web应用)或消除(如服务器关闭)时,它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。

程序清单5-20 ContextReporterjava
package moreservlets;

import javax.servlet.*;
import java.util.*;

/** Simple listener that prints a report on the standard output
* when the ServletContext is created or destroyed.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class ContextReporter implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("Context created on " +
new Date() + ".");
}

public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed on " +
new Date() + ".");
}
}

程序清单5-21 web.xml(声明一个监听程序的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<filter-mapping> … </filter-mapping>
<listener>
<listener-class>package.ListenerClass</listener-class>
</listener>
<servlet> ... </servlet>
<!-- ... -->
</web-app>

15 J2EE元素

本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍,详细内容可以参阅http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。
l distributable
distributable 元素指出,Web应用是以这样的方式编程的:即,支持集群的服务器可安全地在多个服务器上分布Web应用。例如,一个可分布的应用必须只使用 Serializable对象作为其HttpSession对象的属性,而且必须避免用实例变量(字段)来实现持续性。distributable元素直接出现在discription元素之后,并且不包含子元素或数据,它只是一个如下的标志。
<distributable />
l resource-env-ref
resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素(一个相对于java:comp/env环境的JNDI名)以及一个resource-env-type元素(指定资源类型的完全限定的类),如下所示:
<resource-env-ref>
<resource-env-ref-name>
jms/StockQueue
</resource-env-ref-name>
<resource-env-ref-type>
javax.jms.Queue
</resource-env-ref-type>
</resource-env-ref>
l env-entry
env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个env-entry-name元素(一个相对于java: comp/env环境JNDI名)、一个env-entry-value元素(项值)以及一个env-entry-type元素(java.lang程序包中一个类型的完全限定类名,java.lang.Boolean、java.lang.String等)组成。下面是一个例子:
<env-entry>
<env-entry-name>minAmout</env-entry-name>
<env-entry-value>100.00</env-entry-value>
<env-entry-type>minAmout</env-entry-type>
</env-entry>
l ejb-ref
ejb -ref元素声明对一个EJB的主目录的应用。它由一个可选的description元素、一个ejb-ref-name元素(相对于java: comp/env的EJB应用)、一个ejb-ref-type元素(bean的类型,Entity或Session)、一个home元素(bean的主目录接口的完全限定名)、一个remote元素(bean的远程接口的完全限定名)以及一个可选的ejb-link元素(当前bean链接的另一个 bean的名称)组成。
l ejb-local-ref
ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外,此元素具有与ejb-ref元素相同的属性并以相同的方式使用

posted @ 2008-04-06 17:42 阿伟 阅读(485) | 评论 (0)编辑 收藏

 web.xml配置的详细说明 2
4 禁止激活器servlet
对servlet或JSP页面建立定制URL的一个原因是,这样做可以注册从 init(servlet)或jspInit(JSP页面)方法中读取得初始化参数。但是,初始化参数只在是利用定制URL模式或注册名访问 servlet或JSP页面时可以使用,用缺省URL http://host/webAppPrefix/servlet/ServletName 访问时不能使用。因此,你可能会希望关闭缺省URL,这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet,因为多数服务器具有一个用缺省的servlet URL注册的标准servlet,并激活缺省的URL应用的实际servlet。
有两种禁止此缺省URL的主要方法:
l 在每个Web应用中重新映射/servlet/模式。
l 全局关闭激活器servlet。
重要的是应该注意到,虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多,但重新映射可以用一种完全可移植的方式来完成。相反,全局禁止激活器servlet完全是针对具体机器的,事实上有的服务器(如ServletExec)没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。
4.1 重新映射/servlet/URL模式
在一个特定的Web应用中禁止以http://host/webAppPrefix/servlet/ 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet,并使用前一节讨论的url-pattern元素将所有匹配请求转向该 servlet。只要简单地使用:
<url-pattern>/servlet/*</url-pattern>
作为servlet-mapping元素中的模式即可。
例如,程序清单5-5给出了将SorryServlet servlet(程序清单5-6)与所有以http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。
程序清单5-5 web.xml(说明JSP页命名的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<servlet>
<servlet-name>Sorry</servlet-name>
<servlet-class>moreservlets.SorryServlet</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> Sorry </servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>

程序清单5-6 SorryServlet.java
package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** Simple servlet used to give error messages to
* users who try to access default servlet URLs
* (i.e., http://host/webAppPrefix/servlet/ServletName)
* in Web applications that have disabled this
* behavior.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class SorryServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Invoker Servlet Disabled.";
out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2>" + title + "</H2>\n" +
"Sorry, access to servlets by means of\n" +
"URLs that begin with\n" +
"http://host/webAppPrefix/servlet/\n" +
"has been disabled.\n" +
"</BODY></HTML>");
}

public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}


4.2 全局禁止激活器:Tomcat
Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法:
1.禁止激活器: Tomcat 4
Tomcat 4用与前面相同的方法关闭激活器servlet,即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在 install_dir/conf中的一个服务器专用的全局web.xml文件,而前面使用的是存放在每个Web应用的WEB-INF目录中的标准 web.xml文件。
因此,为了在Tomcat 4中关闭激活器servlet,只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可,如下所示:
<!--
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
-->
再次提醒,应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的,此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。
2.禁止激活器:Tomcat3
在Apache Tomcat的版本3中,通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省 servlet URL。例如,下面是禁止使用缺省servlet URL的server.xml文件的一部分。
<!--
<RequsetInterceptor
className="org.apache.tomcat.request.InvokerInterceptor"
debug="0" prefix="/servlet/" />
-->

5 初始化和预装载servlet与JSP页面
这里讨论控制servlet和JSP页面的启动行为的方法。特别是,说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。
5.1 分配servlet初始化参数
利用init-param元素向servlet提供初始化参数,init-param元素具有param-name和param-value子元素。例如,在下面的例子中,如果initServlet servlet是利用它的注册名(InitTest)访问的,它将能够从其方法中调用getServletConfig(). getInitParameter("param1")获得"Value 1",调用getServletConfig().getInitParameter("param2")获得"2"。
<servlet>
<servlet-name>InitTest</servlet-name>
<servlet-class>moreservlets.InitServlet</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>param2</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
在涉及初始化参数时,有几点需要注意:
l 返回值。GetInitParameter的返回值总是一个String。因此,在前一个例子中,可对param2使用Integer.parseInt获得一个int。
l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。
l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此,在这个例子中,param1和 param2初始化参数将能够在使用URL http://host/webAppPrefix/servlet/InitTest 时可用,但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 时不能使用。
例如,程序清单5-7给出一个名为InitServlet的简单servlet,它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。
程序清单5-7 InitServlet.java
package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** Simple servlet used to illustrate servlet
* initialization parameters.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class InitServlet extends HttpServlet {
private String firstName, emailAddress;

public void init() {
ServletConfig config = getServletConfig();
firstName = config.getInitParameter("firstName");
emailAddress = config.getInitParameter("emailAddress");
}

public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String uri = request.getRequestURI();
out.println(ServletUtilities.headWithTitle("Init Servlet") +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2>Init Parameters:</H2>\n" +
"<UL>\n" +
"<LI>First name: " + firstName + "\n" +
"<LI>Email address: " + emailAddress + "\n" +
"</UL>\n" +
"</BODY></HTML>");
}
}


程序清单5-8 web.xml(说明初始化参数的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<servlet>
<servlet-name>InitTest</servlet-name>
<servlet-class>moreservlets.InitServlet</servlet-class>
<init-param>
<param-name>firstName</param-name>
<param-value>Larry</param-value>
</init-param>
<init-param>
<param-name>emailAddress</param-name>
<param-value>Ellison@Microsoft.com</param-value>
</init-param>
</servlet>
<!-- ... -->
</web-app>

5.2 分配JSP初始化参数
给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。
1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示:
<servlet>
<servlet-name>PageName</servlet-name>
<jsp-file>/RealPage.jsp</jsp-file>
<init-param>
<param-name>...</param-name>
<param-value>...</param-value>
</init-param>
...
</servlet>
2) 几乎总是分配一个明确的URL模式。对servlet,一般相应地使用以http://host/webAppPrefix/servlet/ 开始的缺省URL。只需记住,使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如,在上面给出的例子中,可用URL http://host/webAppPrefix/servlet/PageName 访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时,许多用户似乎不喜欢应用常规的servlet的URL。此外,如果 JSP页面位于服务器为其提供了目录清单的目录中(如,一个既没有index.html也没有index.jsp文件的目录),则用户可能会连接到此 JSP页面,单击它,从而意外地激活未初始化的页面。因此,好的办法是使用url-pattern(5.3节)将JSP页面的原URL与注册的 servlet名相关联。这样,客户机可使用JSP页面的普通名称,但仍然激活定制的版本。例如,给定来自项目1的servlet定义,可使用下面的 servlet-mapping定义:
<servlet-mapping>
<servlet-name>PageName</servlet-name>
<url-pattern>/RealPage.jsp</url-pattern>
</servlet-mapping>
3)JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此,使用JSP声明提供一个init方法是不合法的,必须制定jspInit方法。
为了说明初始化JSP页面的过程,程序清单5-9给出了一个名为InitPage.jsp的JSP页面,它包含一个jspInit方法且放置于 deployDemo Web应用层次结构的顶层。一般,http://host/deployDemo/InitPage.jsp 形式的URL将激活此页面的不具有初始化参数访问权的版本,从而将对firstName和emailAddress变量显示null。但是, web.xml文件(程序清单5-10)分配了一个注册名,然后将该注册名与URL模式/InitPage.jsp相关联。

程序清单5-9 InitPage.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>JSP Init Test</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2>Init Parameters:</H2>
<UL>
<LI>First name: <%= firstName %>
<LI>Email address: <%= emailAddress %>
</UL>
</BODY></HTML>
<%!
private String firstName, emailAddress;

public void jspInit() {
ServletConfig config = getServletConfig();
firstName = config.getInitParameter("firstName");
emailAddress = config.getInitParameter("emailAddress");
}
%>


程序清单5-10 web.xml(说明JSP页面的init参数的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<servlet>
<servlet-name>InitPage</servlet-name>
<jsp-file>/InitPage.jsp</jsp-file>
<init-param>
<param-name>firstName</param-name>
<param-value>Bill</param-value>
</init-param>
<init-param>
<param-name>emailAddress</param-name>
<param-value>gates@oracle.com</param-value>
</init-param>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> InitPage</servlet-name>
<url-pattern>/InitPage.jsp</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>


5.3 提供应用范围内的初始化参数
一般,对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的getInitParameter方法读取这些参数。但是,在某些情形下,希望提供可由任意servlet或JSP页面借助ServletContext的getInitParameter方法读取的系统范围内的初始化参数。
可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素,如下所示:
<context-param>
<param-name>support-email</param-name>
<param-value>blackhole@mycompany.com</param-value>
</context-param>
可回忆一下,为了保证可移植性,web.xml内的元素必须以正确的次序声明。但这里应该注意,context-param元素必须出现任意与文档有关的元素(icon、display-name或description)之后及filter、filter-mapping、listener或 servlet元素之前。
5.4 在服务器启动时装载servlet
假如servlet或JSP页面有一个要花很长时间执行的init (servlet)或jspInit(JSP)方法。例如,假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下,在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此,可利用servlet的load-on- startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。
<servlet>
<servlet-name> … </servlet-name>
<servlet-class> … </servlet-class> <!-- Or jsp-file -->
<load-on-startup/>
</servlet>
可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如,下面的servlet项(放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内)将指示服务器首先装载和初始化SearchServlet,然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。
<servlet>
<servlet-name>Search</servlet-name>
<servlet-class>myPackage.SearchServlet</servlet-class> <!-- Or jsp-file -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Results</servlet-name>
<servlet-class>/results/index.jsp</servlet-class> <!-- Or jsp-file -->
<load-on-startup>2</load-on-startup>
</servlet>

6 声明过滤器

servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器,但为了使用与过滤器有关的元素,必须在web.xml中使用版本2.3的DTD。
过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前,必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时,执行链中的下一个过滤器。如果没有其他过滤器,servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权,因此,它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出,过滤器可将响应对象包裹在一个替身对象(stand-in object)中,比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后,过滤器可检查缓冲区,如有必要,就对它进行修改,然后传送到客户机。
例如,程序清单5-11帝国难以了一个简单的过滤器,只要访问相关的servlet或JSP页面,它就截取请求并在标准输出上打印一个报告(开发过程中在桌面系统上运行时,大多数服务器都可以使用这个过滤器)。

程序清单5-11 ReportFilter.java
package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

/** Simple filter that prints a report on the standard output
* whenever the associated servlet or JSP page is accessed.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class ReportFilter implements Filter {
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest)request;
System.out.println(req.getRemoteHost() +
" tried to access " +
req.getRequestURL() +
" on " + new Date() + ".");
chain.doFilter(request,response);
}

public void init(FilterConfig config)
throws ServletException {
}

public void destroy() {}
}

一旦建立了一个过滤器,可以在web.xml中利用filter元素以及filter-name(任意名称)、file-class(完全限定的类名)和(可选的)init-params子元素声明它。请注意,元素在web.xml的web-app元素中出现的次序不是任意的;允许服务器(但不是必需的)强制所需的次序,并且实际中有些服务器也是这样做的。但这里要注意,所有filter元素必须出现在任意filter-mapping元素之前, filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。
例如,给定上述的ReportFilter类,可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter(位于moreservlets程序包中)相关联。
<filter>
<filter-name>Reporter</filter-name>
<filter-class>moresevlets.ReportFilter</filter-class>
</filter>
一旦命名了一个过滤器,可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。
首先,可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名(此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明)关联。例如,下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面,就运行名为Reporter的过滤器。
<filter-mapping>
<filter-name>Reporter</filter-name>
<servlet-name>SomeServletName</servlet-name>
</filter-mapping>
其次,可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如,相面的程序片段指示系统只要访问Web应用中的任意URL,就运行名为Reporter的过滤器。
<filter-mapping>
<filter-name>Reporter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
例如,程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字 PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http: //host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节"分配名称和定制的URL"中给出。事实上,程序清单5- 12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项,可看到下面的标准输出形式的调试报告(换行是为了容易阅读)。
audit.irs.gov tried to access
http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html
on Tue Dec 25 13:12:29 EDT 2001.

程序清单5-12 Web.xml(说明filter用法的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<filter>
<filter-name>Reporter</filter-name>
<filter-class>moresevlets.ReportFilter</filter-class>
</filter>
<!-- ... -->
<filter-mapping>
<filter-name>Reporter</filter-name>
<servlet-name>PageName</servlet-name>
</filter-mapping>
<!-- ... -->
<servlet>
<servlet-name>PageName</servlet-name>
<jsp-file>/RealPage.jsp</jsp-file>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> PageName </servlet-name>
<url-pattern>/UrlTest2/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>


posted @ 2008-04-06 17:39 阿伟 阅读(226) | 评论 (0)编辑 收藏

 web.xml配置的详细说明1

1 定义头和根元素
部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。
DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本(如2.2或2.3)并指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义)。
所有部署描述符文件的顶层(根)元素为web-app。请注意,XML元素不像HTML,他们是大小写敏感的。因此,web-App和WEB-APP都是不合法的,web-app必须用小写。
2 部署描述符文件内的元素次序
XML 元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感。例如,XML头必须是文件中的第一项,DOCTYPE声明必须是第二项,而web- app元素必须是第三项。在web-app元素内,元素的次序也很重要。服务器不一定强制要求这种次序,但它们允许(实际上有些服务器就是这样做的)完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。
下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如,此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意,所有这些元素都是可选的。因此,可以省略掉某一元素,但不能把它放于不正确的位置。
l icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。
l display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。
l description description元素给出与此有关的说明性文本。
l context-param context-param元素声明应用范围内的初始化参数。
l filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。
l filter-mapping 一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。
l listener servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。
l servlet 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。
l servlet-mapping 服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。
l session-config 如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。
l mime-mapping 如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。
l welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。
l error-page error-page元素使得在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。
l taglib taglib元素对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。
l resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。
l resource-ref resource-ref元素声明一个资源工厂使用的外部资源。
l security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用
l login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。
l security-role security-role元素给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。
l env-entry env-entry元素声明Web应用的环境项。
l ejb-ref ejb-ref元素声明一个EJB的主目录的引用。
l ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。
3 分配名称和定制的UL
在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称,使用servlet-mapping元素将定制的URL与刚分配的名称相关联。
3.1 分配名称
为了提供初始化参数,对servlet或JSP页面定义一个定制URL或分配一个安全角色,必须首先给servlet或JSP页面一个名称。可通过 servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素(在web-app元素内),如下所示:
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>moreservlets.TestServlet</servlet-class>
</servlet>
这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给 servlet一个名称具有两个主要的含义。首先,初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在 URL而不是类名中使用此名称。因此,利用刚才给出的定义,URL http://host/webAppPrefix/servlet/Test 可用于 http://host/webAppPrefix/servlet/moreservlets.TestServlet 的场所。
请记住:XML元素不仅是大小写敏感的,而且定义它们的次序也很重要。例如,web-app元素内所有servlet元素必须位于所有servlet- mapping元素(下一小节介绍)之前,而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素(如果有的话)之前。类似地,servlet 的servlet-name子元素也必须出现在servlet-class之前。5.2节"部署描述符文件内的元素次序"将详细介绍这种必需的次序。
例如,程序清单5-1给出了一个名为TestServlet的简单servlet,它驻留在moreservlets程序包中。因为此servlet是扎根在一个名为deployDemo的目录中的Web应用的组成部分,所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清单5-2给出将放置在deployDemo/WEB-INF/内的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素将名称Test与TestServlet.class相关联。图 5-1和图5-2分别显示利用缺省URL和注册名调用TestServlet时的结果。
程序清单5-1 TestServlet.java
package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** Simple servlet used to illustrate servlet naming
* and custom URLs.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
* http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String uri = request.getRequestURI();
out.println(ServletUtilities.headWithTitle("Test Servlet") +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2>URI: " + uri + "</H2>\n" +
"</BODY></HTML>");
}
}

程序清单5-2 web.xml(说明servlet名称的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- … -->
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>moreservlets.TestServlet</servlet-class>
</servlet>
<!-- … -->
</web-app>

3.2 定义定制的URL
大多数服务器具有一个缺省的serlvet URL:
http://host/webAppPrefix/servlet/packageName.ServletName。虽然在开发中使用这个URL很方便,但是我们常常会希望另一个URL用于部署。例如,可能会需要一个出现在Web应用顶层的URL(如,http: //host/webAppPrefix/Anyname),并且在此URL中没有servlet项。位于顶层的URL简化了相对URL的使用。此外,对许多开发人员来说,顶层URL看上去比更长更麻烦的缺省URL更简短。
事实上,有时需要使用定制的URL。比如,你可能想关闭缺省URL映射,以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL,那么你怎样访问servlet呢?这时只有使用定制的URL了。
为了分配一个定制的URL,可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一个任意名称,可利用此名称引用相应的servlet;url-pattern描述了相对于Web应用的根目录的URL。url- pattern元素的值必须以斜杠(/)起始。
下面给出一个简单的web.xml摘录,它允许使用URL http://host/webAppPrefix/UrlTest而不是http://host/webAppPrefix/servlet/Test
http: //host/webAppPrefix/servlet/moreservlets.TestServlet。请注意,仍然需要XML头、 DOCTYPE声明以及web-app封闭元素。此外,可回忆一下,XML元素出现地次序不是随意的。特别是,需要把所有servlet元素放在所有 servlet-mapping元素之前。
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>moreservlets.TestServlet</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>/UrlTest</url-pattern>
</servlet-mapping>
URL模式还可以包含通配符。例如,下面的小程序指示服务器发送所有以Web应用的URL前缀开始,以..asp结束的请求到名为BashMS的servlet。
<servlet>
<servlet-name>BashMS</servlet-name>
<servlet-class>msUtils.ASPTranslator</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name>BashMS</servlet-name>
<url-pattern>/*.asp</url-pattern>
</servlet-mapping>
3.3 命名JSP页面
因为JSP页面要转换成sevlet,自然希望就像命名servlet一样命名JSP页面。毕竟,JSP页面可能会从初始化参数、安全设置或定制的URL中受益,正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的,但存在一个关键的猜疑:即,你不知道JSP页面的实际类名(因为系统自己挑选这个名字)。因此,为了命名JSP页面,可将jsp-file元素替换为servlet-calss元素,如下所示:
<servlet>
<servlet-name>Test</servlet-name>
<jsp-file>/TestPage.jsp</jsp-file>
</servlet>
命名JSP页面的原因与命名servlet的原因完全相同:即为了提供一个与定制设置(如,初始化参数和安全设置)一起使用的名称,并且,以便能更改激活 JSP页面的URL(比方说,以便多个URL通过相同页面得以处理,或者从URL中去掉.jsp扩展名)。但是,在设置初始化参数时,应该注意,JSP页面是利用jspInit方法,而不是init方法读取初始化参数的。
例如,程序清单5-3给出一个名为TestPage.jsp的简单JSP页面,它的工作只是打印出用来激活它的URL的本地部分。TestPage.jsp放置在deployDemo应用的顶层。程序清单5-4给出了用来分配一个注册名PageName,然后将此注册名与http://host/webAppPrefix/UrlTest2/anything 形式的URL相关联的web.xml文件(即,deployDemo/WEB-INF/web.xml)的一部分。

程序清单5-3 TestPage.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>
JSP Test Page
</TITLE>
</HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2>URI: <%= request.getRequestURI() %></H2>
</BODY>
</HTML>

程序清单5-4 web.xml(说明JSP页命名的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<!-- ... -->
<servlet>
<servlet-name>PageName</servlet-name>
<jsp-file>/TestPage.jsp</jsp-file>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> PageName </servlet-name>
<url-pattern>/UrlTest2/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>

转自:http://lizzyostrich.blog.sohu.com/83686972.html
posted @ 2008-04-06 17:36 阿伟 阅读(258) | 评论 (0)编辑 收藏

web.xml的元素
首先注意 xml是大小写敏感的

1、 web.xml的头和根元素
必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。
DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本(如2.2或2.3)并指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义)。
所有部署描述符文件的顶层(根)元素为web-app。
例(红色部分是可选项):
--------------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
   <web-app id="WebApp">
   </web-app>
--------------------------------------------------------------------------------------------------------------------------
 2、元素
以下元素几乎都是可选项,不过要注意它们是有顺序的。虽然有些服务器要求宽松些,但某些服务器会拒绝执行顺序不正确的web应用。所以还是按顺序写好

--------------------------------------------------------------------------------------------------------------------------
· icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。
· display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。
· description description元素给出与此有关的说明性文本。
· context-param context-param元素声明应用范围内的初始化参数。
· filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。
· filter-mapping 一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。
· listener servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。
· servlet 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。
· servlet-mapping服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。
·session-config如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。
· mime-mapping 如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。
· welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。
· error-page error-page元素使得在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。
· taglib taglib元素对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。
· resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。
· resource-ref resource-ref元素声明一个资源工厂使用的外部资源。
· security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用
· login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。
· security-role security-role元素给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。
· env-entry env-entry元素声明Web应用的环境项。
· ejb-ref ejb-ref元素声明一个EJB的主目录的引用。
· ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。


该文章的原文地址为:http://www.blogjava.net/fastzch/archive/2007/08/28/140607.html

 

posted @ 2008-04-06 17:34 阿伟 阅读(229) | 评论 (0)编辑 收藏
 

Springweblogic jndi集成

虽然spring本身是可以直接使用jndi来进行获取一些对象,但是在和weblogic集成的时候往往还是容易出

现问题(web应用的时候出现问题的可能性不大,因为container已经做了很多事情了.)但是在ide或者其

他的应用环境下(不同的jvm的时候),通常找不到provider_url等属性造成无法找到jndi.

修改配置文件如下:

<!-- 通过jndi的方式来调用datasource,即使不一定是在j2ee环境中也可以正常使用默认情况下,如果

没有指定,"java:comp/env/"将放在后面jndi名称前面

-->

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

<property name="jndiName">

<value>jdbc/myDatasource</value>

</property>

<!-- 如果你不想使用 'java:comp/env/'前缀的话请设置下面的值为true, 默认值为false -->

<property name="resourceRef">

<value>false</value>

</property>

<property name="jndiEnvironment">

<props>

Spring连接weblogic-DataSource错误

<!-- The value of Context.PROVIDER_URL -->

<prop key="java.naming.provider.url">t3://localhost:7001</prop>

<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory

</prop>

</props>

</property>

</bean>

注意在设置的时候由于不在同一个jvm里面,所以一定要设置provider.urlfactory.initial的属性值,

则会出现NoInitialContextException的异常出现.

此外如果和其他的应用服务器集成的话可能不只是要设置上面的两个属性,还要设置相关的其他属性。详

细情况参考:javax.naming.Context类的说明文档。

http://java.sun.com/j2se/1.4.2/docs/api/javax/naming/Context.html

其中设置的:

<property name="jndiEnvironment">

<props>

<!-- The value of Context.PROVIDER_URL -->

<prop key="java.naming.provider.url">t3://localhost:7001</prop>

<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory

</prop>

</props>

</property> 实际上就是设置Context初始化的时候设置的Properties属性。

http://java.mblogger.cn/layout/posts/11849.aspx

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

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

各种应用服务器的不同的properties集合:

websphere:

java.naming.provider.url->iiop://websphere.machine.domain.com:900

java.naming.factory.initial ->com.ibm.websphere.naming.WsnInitialContextFactory

java.naming.factory.url.pkgs ->com.ibm.ws.naming

org.omg.CORBA.ORBClass->com.ibm.rmi.iiop.ORB

org.omg.CORBA.ORBSingletonClass->com.ibm.rmi.corba.ORBSingleton

javax.rmi.CORBA.UtilClass->com.ibm.rmi.javax.rmi.CORBA.Util

javax.rmi.CORBA.StubClass->com.ibm.rmi.javax.rmi.CORBA.StubDelegateImpl

javax.rmi.CORBA.PortableRemoteObjectClass->com.ibm.rmi.javax.rmi.PortableRemoteObject

weblogic:

java.naming.factory.initial -> weblogic.jndi.WLInitialContextFactory

java.naming.provider.url -> t3://localhost:7001

jboss:

ava.naming.factory.initial ->org.jnp.interfaces.NamingContextFactory

java.naming.factory.url.pkgs->org.jboss.naming.client

java.naming.provider.url ->jnp://10.0.0.18:1099

sunone IMQ ldap:

java.naming.provider.url -> ldap://localhost:389/dc=yusong,dc=com

java.naming.factory.initial -> com.sun.jndi.ldap.LdapCtxFactory

sunone Application Server:

java.naming.provider.url -> iiop://192.168.0.34:3700

java.naming.factory.initial -> com.sun.jndi.cosnaming.CNCtxFactory

oracle oc4j:

java.naming.factory.initial->com.evermind.server.ApplicationClientInitialContextFactory

java.naming.provider.url->ormi://localhost/bmpapp

posted @ 2008-03-01 01:01 阿伟 阅读(3489) | 评论 (0)编辑 收藏

配置WEB.XML ,让SESSION在页面中一直打开.

<!-- spring中对hibernate的一个session支持,直到页面执行完后才能关闭 -->
<filter>
  <filter-name>opensession</filter-name>
  <filter-class>
   org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  </filter-class>

<!--  当遇到所有的.do文件都要按照此设置 -->
 </filter>
 <filter-mapping>
  <filter-name>opensession</filter-name>
  <url-pattern>*.do</url-pattern>
 </filter-mapping>
posted @ 2008-02-26 23:02 阿伟 阅读(925) | 评论 (0)编辑 收藏

1.在weblogic目录下的serverlib下添加mysql驱动

mysql-connector-java-3.1.11-bin.jar

2.在weblogic目录下的commonbin下找到commEnv.cmd打开

找到set weblogic_classpath= 后边加上mysql驱动的路径

例:%WL_HOME%\server\lib\mysql-connector-java-3.1.11-bin.jar
(@rem set up WebLogic Server's class path
set WEBLOGIC_CLASSPATH=%PATCH_CLASSPATH%;%JAVA_HOME%\lib\tools.jar;%WL_HOME%\server\lib\weblogic_sp.jar;%WL_HOME%\server\lib\weblogic.jar;%WL_HOME%\server\lib\webservices.jar;%WL_HOME%\server\lib\MySQL5.0 driver.zip)

3.创建domain

4.在开始菜单打开start AdminServer for weblogic Server domain

等到running状态

5.打开console 输入用户名密码。

6.点开Service->JDBC->Data Source

7.JDBC Data Source Properties 页面

Name和JNDI Name可以一样 我起名为MySQLJDBCDataSource

Database Type:选择MySQL

Database Driver:选择第一个com包下的驱动就可以 Next.

8.Transaction Options

选择倒数第二个Emulate Two-Phase Commit Next.

9.Connection Properties

Database Name :自己的数据库名 例如:test

Host Name :主机名 例如:localhost或192.168.1.117

Port :3306 (mysql默认)

Database User Name:数据库用户名

Password :数据库密码

Confirm Password :同上 Next

10.Test Database Connection

可以点击Test Configuration 测试一下数据库连接。Next

11.Select Targets

选择发布到哪个AdminServer的JNDI树上。Next

12.点击左上的Activate Changes 如果没有异常就OK了哦。

友情提示:

1) 如果你直接在weblogic下配连接池而不在weblogic下的domain下配置,可以跳过1,2步。

2) 如果配置成功后你可以在console下的Environment->Servers页面点击你的AdminServer(admin),然后View JNDI Tree中看到你刚配置的JNDI名。

posted @ 2008-02-26 10:11 阿伟 阅读(369) | 评论 (0)编辑 收藏
 Weblogic9.0图解安装   (详细可参考BEA官方网站:http://e-docs.bea.com/wlp/docs92/index.html)
初次使用Weblogic9.0图解安装


weblogic1.jpg

weblogic2.jpg

weblogic3.jpg

weblogic4.jpg

weblogic9.jpg

weblogic10.jpg

weblogic7.jpg

weblogic8.jpg

初次使用Weblogic,需要对其进行域的配置。现在我就图解说明怎样配置Weblogic9.0


weblogic1.jpg

weblogic2.jpg

weblogic3.jpg

weblogic4.jpg

weblogic9.jpg

weblogic10.jpg

weblogic7.jpg

weblogic8.jpg

 
 

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

posted @ 2008-02-25 16:58 阿伟 阅读(1852) | 评论 (0)编辑 收藏

Java系统中内存泄漏测试方法的研究

本文链接:http://user.qzone.qq.com/18485108/blog/1203413108
摘 要 稳定性是衡量软件系统质量的重要指标,内存泄漏是破坏系统稳定性的重要因素。由于采用垃圾回收机制,Java语言的内存泄漏的模式与C++等语言相比有很大的不同。全文通过与C++中的内存泄漏问题进行对比,讲述了Java内存泄漏的基本原理,以及如何借助Optimizeit profiler工具来测试内存泄漏和分析内存泄漏的原因,在实践中证明这是一套行之有效的方法。

  关键词 Java; 内存泄漏; GC(垃圾收集器) 引用; Optimizeit

  问题的提出

  笔者曾经参与开发的网管系统,系统规模庞大,涉及上百万行代码。系统主要采用Java语言开发,大体上分为客户端、服务器和数据库三个层次。在版本进入测试和试用的过程中,现场人员和测试部人员纷纷反映:系统的稳定性比较差,经常会出现服务器端运行一昼夜就死机的现象,客户端跑死的现象也比较频繁地发生。对于网管系统来讲,经常性的服务器死机是个比较严重的问题,因为频繁的死机不仅可能导致前后台数据不一致,发生错误,更会引起用户的不满,降低客户的信任度。因此,服务器端的稳定性问题必须尽快解决。

  解决思路

  通过察看服务器端日志,发现死机前服务器端频繁抛出OutOfMemoryException内存溢出错误,因此初步把死机的原因定位为内存泄漏引起内存不足,进而引起内存溢出错误。如何查找引起内存泄漏的原因呢?有两种思路:第一种,安排有经验的编程人员对代码进行走查和分析,找出内存泄漏发生的位置;第二种,使用专门的内存泄漏测试工具Optimizeit进行测试。这两种方法都是解决系统稳定性问题的有效手段,使用内存测试工具对于已经暴露出来的内存泄漏问题的定位和解决非常有效;但是软件测试的理论也告诉我们,系统中永远存在一些没有暴露出来的问题,而且,系统的稳定性问题也不仅仅只是内存泄漏的问题,代码走查是提高系统的整体代码质量乃至解决潜在问题的有效手段。基于这样的考虑,我们的内存稳定性工作决定采用代码走查结合测试工具的使用,双管齐下,争取比较彻底地解决系统的稳定性问题。

  在代码走查的工作中,安排了对系统业务和开发语言工具比较熟悉的开发人员对应用的代码进行了交叉走查,找出代码中存在的数据库连接声明和结果集未关闭、代码冗余和低效等故障若干,取得了良好的效果,文中主要讲述结合工具的使用对已经出现的内存泄漏问题的定位方法。

  内存泄漏的基本原理

  在C++语言程序中,使用new操作符创建的对象,在使用完毕后应该通过delete操作符显示地释放,否则,这些对象将占用堆空间,永远没有办法得到回收,从而引起内存空间的泄漏。如下的简单代码就可以引起内存的泄漏:

void function(){
 Int[] vec = new int[5];
}
  在function()方法执行完毕后,vec数组已经是不可达对象,在C++语言中,这样的对象永远也得不到释放,称这种现象为内存泄漏。

  而Java是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存,但它只能回收无用并且不再被其它对象引用的那些对象所占用的空间。在下面的代码中,循环申请Object对象,并将所申请的对象放入一个Vector中,如果仅仅释放对象本身,但是因为Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。

Vector v = new Vector(10);
for (int i = 1; i < 100; i++)
{
 Object o = new Object();
 v.add(o);
 o = null;
}//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。
  实际上无用,而还被引用的对象,GC就无能为力了(事实上GC认为它还有用),这一点是导致内存泄漏最重要的原因。

  Java的内存回收机制可以形象地理解为在堆空间中引入了重力场,已经加载的类的静态变量和处于活动线程的堆栈空间的变量是这个空间的牵引对象。这里牵引对象是指按照Java语言规范,即便没有其它对象保持对它的引用也不能够被回收的对象,即Java内存空间中的本原对象。当然类可能被去加载,活动线程的堆栈也是不断变化的,牵引对象的集合也是不断变化的。对于堆空间中的任何一个对象,如果存在一条或者多条从某个或者某几个牵引对象到该对象的引用链,则就是可达对象,可以形象地理解为从牵引对象伸出的引用链将其拉住,避免掉到回收池中;而其它的不可达对象由于不存在牵引对象的拉力,在重力的作用下将掉入回收池。在图1中,A、B、C、D、E、F六个对象都被牵引对象所直接或者间接地“牵引”,使得它们避免在重力的作用下掉入回收池。如果TR1-A链和TR2-D链断开,则A、B、C三个对象由于失去牵引,在重力的作用下掉入回收池(被回收),D对象也是同样的原因掉入回收池,而F对象仍然存在一个牵引链(TR3-E-F),所以不会被回收,如图2、3所示。

  
  图1 初始状态

  
  图2 TR1-A链和TR2-D链断开,A、B、C、D掉入回收池

  
  图3 A、B、C、D四个对象被回收

  通过前面的介绍可以看到,由于采用了垃圾回收机制,任何不可达对象都可以由垃圾收集线程回收。因此通常说的Java内存泄漏其实是指无意识的、非故意的对象引用,或者无意识的对象保持。无意识的对象引用是指代码的开发人员本来已经对对象使用完毕,却因为编码的错误而意外地保存了对该对象的引用(这个引用的存在并不是编码人员的主观意愿),从而使得该对象一直无法被垃圾回收器回收掉,这种本来以为可以释放掉的却最终未能被释放的空间可以认为是被“泄漏了”。

  这里通过一个例子来演示Java的内存泄漏。假设有一个日志类Logger,其提供一个静态的log(String msg)方法,任何其它类都可以调用Logger.Log(message)来将message的内容记录到系统的日志文件中。Logger类有一个类型为HashMap的静态变量temp,每次在执行log(message)方法的时候,都首先将message的值丢入temp中(以当前线程+当前时间为键),在方法退出之前再从temp中将以当前线程和当前时间为键的条目删除。注意,这里当前时间是不断变化的,所以log方法在退出之前执行删除条目的操作并不能删除方法执行之初丢入的条目。这样,任何一个作为参数传给log方法的字符串最终由于被Logger的静态变量temp引用,而无法得到回收,这种违背实现者主观意图的无意识的对象保持就是我们所说的Java内存泄漏。
鉴别泄漏对象的方法

  一般说来,一个正常的系统在其运行稳定后其内存的占用量是基本稳定的,不应该是无限制的增长的,同样,对任何一个类的对象的使用个数也有一个相对稳定的上限,不应该是持续增长的。根据这样的基本假设,我们可以持续地观察系统运行时使用的内存的大小和各实例的个数,如果内存的大小持续地增长,则说明系统存在内存泄漏,如果某个类的实例的个数持续地增长,则说明这个类的实例可能存在泄漏情况。

  Optimizeit是Borland公司的产品,主要用于协助对软件系统进行代码优化和故障诊断,其功能众多,使用方便,其中的OptimizeIt Profiler主要用于内存泄漏的分析。Profiler的堆视图(如图4)就是用来观察系统运行使用的内存大小和各个类的实例分配的个数的,其界面如图四所示,各列自左至右分别为类名称、当前实例个数、自上个标记点开始增长的实例个数、占用的内存空间的大小、自上次标记点开始增长的内存的大小、被释放的实例的个数信息、自上次标记点开始增长的内存的大小被释放的实例的个数信息,表的最后一行是汇总数据,分别表示目前JVM中的对象实例总数、实例增长总数、内存使用总数、内存使用增长总数等。

  在实践中,可以分别在系统运行四个小时、八个小时、十二个小时和二十四个小时时间点记录当时的内存状态(即抓取当时的内存快照,是工具提供的功能,这个快照也是供下一步分析使用),找出实例个数增长的前十位的类,记录下这十个类的名称和当前实例的个数。在记录完数据后,点击Profiler中右上角的Mark按钮,将该点的状态作为下一次记录数据时的比较点。

  
  图4 Profiler 堆视图

  系统运行二十四小时以后可以得到四个内存快照。对这四个内存快照进行综合分析,如果每一次快照的内存使用都比上一次有增长,可以认定系统存在内存泄漏,找出在四个快照中实例个数都保持增长的类,这些类可以初步被认定为存在泄漏。

  分析与定位

  通过上面的数据收集和初步分析,可以得出初步结论:系统是否存在内存泄漏和哪些对象存在泄漏(被泄漏),如果结论是存在泄漏,就可以进入分析和定位阶段了。

  前面已经谈到Java中的内存泄漏就是无意识的对象保持,简单地讲就是因为编码的错误导致了一条本来不应该存在的引用链的存在(从而导致了被引用的对象无法释放),因此内存泄漏分析的任务就是找出这条多余的引用链,并找到其形成的原因。前面还讲到过牵引对象,包括已经加载的类的静态变量和处于活动线程的堆栈空间的变量。由于活动线程的堆栈空间是迅速变化的,处于堆栈空间内的牵引对象集合是迅速变化的,而作为类的静态变量的牵引对象的集合在系统运行期间是相对稳定的。

  对每个被泄漏的实例对象,必然存在一条从某个牵引对象出发到达该对象的引用链。处于堆栈空间的牵引对象在被从栈中弹出后就失去其牵引的能力,变为非牵引对象,因此,在长时间的运行后,被泄露的对象基本上都是被作为类的静态变量的牵引对象牵引。

  Profiler的内存视图除了堆视图以外,还包括实例分配视图(图5)和实例引用图(图6)。

  Profiler的实例引用图为找出从牵引对象到泄漏对象的引用链提供了非常直接的方法,其界面的第二个栏目中显示的就是从泄漏对象出发的逆向引用链。需要注意的是,当一个类的实例存在泄漏时,并非其所有的实例都是被泄漏的,往往只有一部分是被泄漏对象,其它则是正常使用的对象,要判断哪些是正常的引用链,哪些是不正常的引用链(引起泄漏的引用链)。通过抽取多个实例进行引用图的分析统计以后,可以找出一条或者多条从牵引对象出发的引用链,下面的任务就是找出这条引用链形成的原因。

  实例分配图提供的功能是对每个类的实例的分配位置进行统计,查看实例分配的统计结果对于分析引用链的形成具有一定的作用,因为找到分配链与引用链的交点往往就可以找到了引用链形成的原因,下面将具体介绍。

  
  图5 实例分配图

  
  图6 实例引用图

  设想一个实例对象a在方法f中被分配,最终被实例对象b所引用,下面来分析从b到a的引用链可能的形成原因。方法f在创建对象a后,对它的使用分为四种情况:1、将a作为返回值返回;2、将a作为参数调用其它方法;3、在方法内部将a的引用传递给其它对象;4、其它情况。其中情况4不会造成由b到a的引用链的生成,不用考虑。下面考虑其它三种情况:对于1、2两种情况,其造成的结果都是在另一个方法内部获得了对象a的引用,它的分析与方法f的分析完全一样(递归分析);考虑第3种情况:1、假设方法f直接将对象a的引用加入到对象b,则对象b到a的引用链就找到了,分析结束;2、假设方法f将对象a的引用加入到对象c,则接下来就需要跟踪对象c的使用,对象c的分析比对象a的分析步骤更多一些,但大体原理都是一样的,就是跟踪对象从创建后被使用的历程,最终找到其被牵引对象引用的原因。

  现在将泄漏对象的引用链以及引用链形成的原因找到了,内存泄漏测试与分析的工作就到此结束,接下来的工作就是修改相应的设计或者实现中的错误了。

  总结

  使用上述的测试和分析方法,在实践中先后进行了三次测试,找出了好几处内存泄漏错误。系统的稳定性得到很大程度的提高,最初运行1~2天就抛出内存溢出异常,修改完成后,系统从未出现过内存溢出异常。此方法适用于任何使用Java语言开发的、对稳定性有比较高要求的软件系统。
posted @ 2008-02-24 18:23 阿伟 阅读(300) | 评论 (0)编辑 收藏

1.将数据库驱动程序的JAR文件放在Tomcat的 common/lib 中

2.在server.xml中设置数据源,以MySQL数据库为例,如下:
在<GlobalNamingResources> </GlobalNamingResources>节点中加入,
      <Resource
      name="jdbc/DBPool"
      type="javax.sql.DataSource"
      password="root"
      driverClassName="com.mysql.jdbc.Driver"
      maxIdle="2"
      maxWait="5000"
      username="root"
      url="jdbc:mysql://127.0.0.1:3306/test"
      maxActive="4"/>
   属性说明:name,数据源名称,通常取”jdbc/XXX”的格式;
            type,”javax.sql.DataSource”;
            password,数据库用户密码;
            driveClassName,数据库驱动;
            maxIdle,最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连
                     接将被标记为不可用,然后被释放。设为0表示无限制。
            MaxActive,连接池的最大数据库连接数。设为0表示无限制。
            maxWait ,最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示
                     无限制。

3.在你的web应用程序的web.xml中设置数据源参考,如下:
  在<web-app></web-app>节点中加入,
  <resource-ref>
    <description>MySQL DB Connection Pool</description>
    <res-ref-name>jdbc/DBPool</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
 </resource-ref>
  子节点说明: description,描述信息;
               res-ref-name,参考数据源名字,同上一步的属性name;
               res-type,资源类型,”javax.sql.DataSource”;
               res-auth,”Container”;
               res-sharing-scope,”Shareable”;

4.在web应用程序的context.xml中设置数据源链接,如下:
  在<Context></Context>节点中加入,
  <ResourceLink
   name="jdbc/DBPool" 
   type="javax.sql.DataSource" 
   global="jdbc/DBPool"/>
   属性说明:name,同第2步和第3步的属性name值,和子节点res-ref-name值;
             type,同样取”javax.sql.DataSource”;
             global,同name值。
 
至此,设置完成,下面是如何使用数据库连接池
1.建立一个连接池类,DBPool.java,用来创建连接池,代码如下:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class DBPool {
    private static DataSource pool;
    static {
         Context env = null;
          try {
              env = (Context) new InitialContext().lookup("java:comp/env");
              pool = (DataSource)env.lookup("jdbc/DBPool");
              if(pool==null) 
                  System.err.println("'DBPool' is an unknown DataSource");
               } catch(NamingException ne) {
                  ne.printStackTrace();
          }
      }
    public static DataSource getPool() {
        return pool;
    }
}

2.在要用到数据库操作的类或jsp页面中,用DBPool.getPool().getConnection(),获得一个Connection对象,就可以进行数据库操作,最后别忘了对Connection对象调用close()方法,注意:这里不会关闭这个Connection,而是将这个Connection放回数据库连接池。

posted @ 2008-02-19 15:47 阿伟 阅读(220) | 评论 (0)编辑 收藏

substr 方法
返回一个从指定位置开始的指定长度的子字符串。

stringvar.substr(start [, length ])

参数
stringvar

必选项。要提取子字符串的字符串文字或 String 对象。

start

必选项。所需的子字符串的起始位置。字符串中的第一个字符的索引为 0。

length

可选项。在返回的子字符串中应包括的字符个数。

说明
如果 length 为 0 或负数,将返回一个空字符串。如果没有指定该参数,则子字符串将延续到 stringvar 的最后。

示例
下面的示例演示了substr 方法的用法。

function SubstrDemo(){
   var s, ss;                // 声明变量。
   var s = "The rain in Spain falls mainly in the plain.";
   ss = s.substr(12, 5);  // 获取子字符串。
   return(ss);               // 返回 "Spain"。
}


substring 方法
返回位于 String 对象中指定位置的子字符串。

strVariable.substring(start, end)
"String Literal".substring(start, end)

参数
start

指明子字符串的起始位置,该索引从 0 开始起算。

end

指明子字符串的结束位置,该索引从 0 开始起算。

说明
substring 方法将返回一个包含从 start 到最后(不包含 end )的子字符串的字符串。

substring 方法使用 start 和 end 两者中的较小值作为子字符串的起始点。例如, strvar.substring(0, 3) 和 strvar.substring(3, 0) 将返回相同的子字符串。

如果 start 或 end 为 NaN 或者负数,那么将其替换为0。

子字符串的长度等于 start 和 end 之差的绝对值。例如,在 strvar.substring(0, 3) 和 strvar.substring(3, 0) 返回的子字符串的的长度是 3。

示例
下面的示例演示了 substring 方法的用法。

function SubstringDemo(){
   var ss;                         // 声明变量。
   var s = "The rain in Spain falls mainly in the plain..";
   ss = s.substring(12, 17);   // 取子字符串。
   return(ss);                     // 返回子字符串。
}

posted @ 2008-01-23 16:45 阿伟 阅读(711) | 评论 (0)编辑 收藏
转自: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1967495

第一句话是:优秀是一种习惯。
这句话是古希腊哲学家亚里士多德说的。如果说优秀是一种习惯,那么懒惰也是一种习惯。人出生的时候,除了脾气会因为天性而有所不同,其他的东西基本都是后天形成的,是家庭影响和教育的结果。所以,我们的一言一行都是日积月累养成的习惯。我们有的人形成了很好的习惯,有的人形成了很坏的习惯。所以我们从现在起就要把优秀变成一种习惯,使我们的优秀行为习以为常,变成我们的第二天性。让我们习惯性地去创造性思考,习惯性地去认真做事情,习惯性地对别人友好,习惯性地欣赏大自然。

注解:要会“装”,要持续的、不间断的“装”,装久了就成了真的了,就成了习惯了,比如准时到会,每次都按时到会,你装装看,你装30年看看,装的时间长了就形成了习惯。:)

第二句话是:生命是一种过程。
事情的结果尽管重要,但是做事情的过程更加重要,因为结果好了我们会更加快乐,但过程使我们的生命充实。人的生命最后的结果一定是死亡,我们不能因此说我们的生命没有意义。世界上很少有永恒。大学生谈恋爱,每天都在信誓旦旦地说我会爱你一辈子,这实际上是不真实的。统计数据表明,大学生谈恋爱的 100对里有 90对最后会分手,最后结婚了的还有一半会离婚。你说爱情能永恒吗?所以最真实的说法是:“我今天,此时此刻正在真心地爱着你。”明天也许你会失恋,失恋后我们会体验到失恋的痛苦。这种体验也是丰富你生命的一个过程。

注解:生命本身其实是没有任何意义的,只是你自己赋予你的生命一种你希望实现的意义,因此享受生命的过程就是一种意义所在。

第三句话是:两点之间最短的距离并不一定是直线。

在人与人的关系以及做事情的过程中,我们很难直截了当就把事情做好。我们有时需要等待,有时需要合作,有时需要技巧。我们做事情会碰到很多困难和障碍,有时候我们并不一定要硬挺、硬冲,我们可以选择有困难绕过去,有障碍绕过去,也许这样做事情更加顺利。大家想一想,我们和别人说话还得想想哪句话更好听呢。尤其在中国这个比较复杂的社会中,大家要学会想办法谅解别人,要让人觉得你这个人很成熟,很不错,你才能把事情做成。

注解:如果你在考数学试题,一定要答两点之间直线段最短,如果你在走路,从A到B,明明可以直接过去,但所有人都不走,你最好别走,因为有陷阱。在中国办事情,直线性思维在很多地方要碰壁,这是中国特色的中国处事方式。

第四句话是:只有知道如何停止的人才知道如何加快速度。

我在滑雪的时候,最大的体会就是停不下来。我刚开始学滑雪时没有请教练,看着别人滑雪,觉得很容易,不就是从山顶滑到山下吗?于是我穿上滑雪板,哧溜一下就滑下去了,结果我从山顶滑到山下,实际上是滚到山下,摔了很多个跟斗。我发现根本就不知道怎么停止、怎么保持平衡。最后我反复练习怎么在雪地上、斜坡上停下来。练了一个星期,我终于学会了在任何坡上停止、滑行、再停止。这个时候我就发现自己会滑雪了,就敢从山顶高速地往山坡下冲。因为我知道只要我想停,一转身就能停下来。只要你能停下来,你就不会撞上树、撞上石头、撞上人,你就不会被撞死。因此,只有知道如何停止的人,才知道如何高速前进。

注解:用汽车来比喻,宝马可以上200公里,奇瑞却只能上120公里,为什么?发动机估计不相上下,差距在刹车系统,上了200公里刹不了车,呵呵,我的天!

第五句话是:放弃是一种智慧,缺陷是一种恩惠。

当你拥有六个苹果的时候,千万不要把它们都吃掉,因为你把六个苹果全都吃掉,你也只吃到了六个苹果,只吃到了一种味道,那就是苹果的味道。如果你把六个苹果中的五个拿出来给别人吃,尽管表面上你丢了五个苹果,但实际上你却得到了其他五个人的友情和好感。以后你还能得到更多,当别人有了别的水果的时候,也一定会和你分享,你会从这个人手里得到一个橘子,那个人手里得到一个梨,最后你可能就得到了六种不同的水果,六种不同的味道,六种不同的颜色,六个人的友谊。人一定要学会用你拥有的东西去换取对你来说更加重要和丰富的东西。所以说,放弃是一种智慧。


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

 

 

posted @ 2008-01-23 13:26 阿伟 阅读(182) | 评论 (0)编辑 收藏

转自:http://topic.csdn.net/u/20070926/13/391568bc-d6ea-474a-880b-68005da5f09f.html

几乎每个企业都需要技术员的支持,生产制造型企业需要现场生产控制和工艺流程方面的技术人才;it等高科技行业需要大量软件研发和设备维护的硬件工程师;房地产、建筑工程领域需要建筑设计师、土木工程师和施工技术人员。此外,不论是国企、民营企业还是外资公司,都需要大量的基础技术工人。甚至很多在豪华写字楼office内工作的白领,从事的工作都是和技术相关的。  

      不过,一个严峻的现实是,大量的技术类人员对自己的职业定位和职业涯规划显得非常迷茫和困惑。中国有句古话:劳心者治人,劳力者治于人。与管理类岗位相比,技术人员往往被人看低一等,他们虽然从事着非常重要、繁琐的技术性工作,但更多的是扮演着幕后英雄的角色。在社会地位、经济收入方面与分光无限的各级管理层普遍存在差距,这一现实造就了技术人员的巨大心理落差。第二个造成职业规划困惑的因是部分技术性工作的局限性。拿it行业来说,由于技术和知识更新的速度太快,软件开放人员普遍被认为是吃“青春饭”的职位,谁学习的更快、谁的精力更旺盛、谁更能熬夜,谁就更有竞争力,因为这经验已经不再重要。如果超过35岁还从事软件开发的话,将很难在本职岗位取得突破。  

          那么,对于技术类人员来说,难道他们的职业发展前景真的如此黯淡?事实当然不会如此悲观,做技术工作同样有着非常广阔的空间,当然,关键一点你要令自己的视野更开阔些,从长远的角度来看待这个问题。根据我的经验,技术人员的职业方向可以有以下几个选择:  

方向一、成为项目经理  

对于很多从事技术方面工作的人员来说,发展成为项目经理是一个相当好的工作。项目管理工作既要扎实的技术背景支持,又涉及多方面的管理工作,最适合那些技术出身但又不甘于只做技术工作的人员。成为项目经理,一方面可以充分发挥技术人员的专业优势,同时又可在团队管理、协调各方资源、内外部沟通等工作中体验和发挥作为管理者的角色和作用,从而让自身价值更为充分的实现和得到认可。优秀的项目管理人才,也是今后很长时期内的一个热门职业方向。  

方向二、成为行业资深专家  

如果的确非常喜爱技术工作,而不擅长和喜欢与人沟通,则可以完全专注于自身的领域,以发展成为行业资深专家为方向和目标,当然,这一发展过程可能会比较漫长,任何一个领域的顶尖技术人才都需要长期的行业经验的累积和个人孜孜不倦的投入。不过这类人才的一个优势是越老越吃香,当别人随着年龄的逐步增长而开始担心饭碗问题时,你则渐入佳境,开始进入职业发展的黄金时期。  

方向三、成为研发经理或技术总监  

事实上,在某些行业和企业,技术研发人员的地位是非常高的。譬如在微软、诺基亚、华为等it产业,技术的支持和研发的速度,成为企业利润增长的最主要来源,在这些行业,技术研发部门就是企业的主战场。在不少国企和政府部门,也非常重视科技和技术工作,例如,我所知道的广州市市政园林局,就设有总工程师、副总工程师等技术职位,其中总工程师的职务级别相当于副局级,在这种氛围影响下,技术岗位人才和行政领导同样受人尊敬。所以,在一个尊重和重视技术工作的行业和企业中,发展成为研发经理、技术总监或总工程师都是一个很好的选择。  

方向四、做技术型销售和服务  

技术工作的领域其实非常广泛,如果感觉纯技术工作发展潜力不大,可以考虑转向做销售或技术支持方面。华为、中兴等通信技术公司的销售人员,很少是不具有专业技术背景的;甲骨文等软件巨头的市场推广,第一步常常是从销售工程师拜访客户开始的。这类高价值、高科技的产品销售推广,非常需要具有丰富技术经验的销售人员。  

技术人员转向售后服务,也是非常有前途的。我认识的一个朋友,大学是施工机械专业,毕业后一直在市政工程行业做非开挖顶管施工,在几年的工作中积累了丰富的地下顶进设备的应用和维修经验,一个合适的机会跳槽到著名的顶管设备生产商-德国海瑞克公司,成为其售后服务工程师,工作上得心应手,收入也有了数倍的增长。  

方向五、转向管理岗位  

总有一些人,虽然是理工科出身、从事着技术岗位工作,但他们似乎天生就是具有管理天赋的人。这些人会在工作中逐步展现出管理潜质和优秀的领导能力,他们往往更喜欢跟人打交道,更喜欢与外界沟通。在这种条件下,以技术经验为基础和依托,适当补充学习些管理方面的知识,例如可以在职攻读mba,假以时日,完全可以成长为出色的职业经理人。  


 

方向六、高级技术操作人员  

刚才所谈的职业发展方向,适用群体多为高校理工专业出身的人士,但对于数量众多的中等专科学校、技校毕业的一线技术工人来说,成为行业技术专家或研发总监的机会显然非常微小。这一群体的职业人士,最佳的技术发展路线是立足本职岗位,成为高级操作型技术人员。  

广州市2006年出台的各类岗位工资指导价格中,高级技师就业的工资比博士还要高出500元。出现这一现象的原因很简单,从全国层面来说,产业工人数量虽然巨大,但高级技工的比例却非常小,“高级技工”的缺乏已经成为制约许多企业发展的“瓶颈”。但随着政策环境、企业认识角度和培育机制方面的不断改善,这一现象将逐步得到改变,所以成为中高级技师将是一个非常有前途的职业发展方向。  

最后,我再次拿it行业为例来具体谈谈技术人员的职业轨迹。  

it(information   technology)行业的分类相当复杂,我这里仅仅分析最典型的三个部分:  

第一部分是软件开发,通俗来说就是编程。实际上我认为真正的软件开发人员和制鞋工厂中的工人处在一个地位,是企业产品的最终生产者(当然这里没有贬义)。  

第二个部分是mis:management   information   service/   system(管理信息系统),主要负责基础it建设、网络、通讯、软硬件支持、简单开发等职能,为公司其他部门提供it基础服务。  

第三部分是erp:enterprise   resource   planning(企业资源计划系统),主要涉及企业管理类软件施、维护、管理。通过是引入信息化手段在企业现实的实现企业的资源管理,协调企业各方面的生产运作,它对业务的规范和企业的管理机制有很大的依赖。  

让我们来分别看看这三部分人员的职业发展空间:  

1.开发人员  

我的观点是,在中小企业做纯粹的软件开发很可能走上一条不归路,长期从事开发的人一般处世能力不足,升任管理人员的机会不大。而还有一个更重要的问题是中国目前开发行业的环境很不好,正如我之前谈到的基本是在吃青春饭,30往后就很难做下去了。而在美国40岁的开发人员是正吃香的年龄。虽然可能业务越来越精,但可能会离it越来越远,向纯蓝领工人发展。  

如果真的要做开发,应该找一个更好的平台,最好是进入跨国企业或国内龙头企业。如果数据方面的技术很强,可以考虑转向互联网搜索方向;如果在电子和通信设备方面有优势,可以从简单的程序开发转向通信产品的开发。  

2.mis人员  

mis内容广泛,可从事的职业很多:网管、技术支持等,而且通过努力可以得到提升成为小小的主管(当然要有自身的素质),进而成为mismanager,但做到mismanager基本也就到头了,不过倒是可以考虑转到不同的行业或企业做mis。  

同样是做it服务,在不同公司内it部门的地位还是非常巨大的。就我所了解的,雅芳(中国)公司的it部门就有100多人,在公司总部的各职能部门中的地位相当高;而南方航空公司的it部门竟然达到800多人,这个规模已经远远超过一般的it公司,其it部门的总裁也是公司决策层的重要成员。所以,在这些公司内做it技术支持工作,既避免了纯编程式的软件开发人员遇到的“人老珠黄”的被动局面,也不必担心it产业泡沫破灭而产生的生存危机。  

3.erp类人员  

从事企业管理类软件的人员一般起点比较高(公司的起点就比较高),要求对财务、生产、销售等流程都有清楚地认识,从业人员不一定为it出身,而有可能是财务人员或理工科人员等转行而来。it的迅速发展和企业经营领域的不断拓展,为erp的推广和发展创造了良好的发展空间。事实上,一个从事企业管理类软件的技术人员完全可以胜任一个企业的管理者,在这一领域技术人员的前景可以说是非常广阔的。  

我认识的一位朋友,本科读的是工业装备控制专业,毕业后一直从事erp方面的应用推广和管理咨询,虽然他对纯粹的it技术了解并不是特别深刻,但在erp系统在企业中的应用方面经验非常丰富,在别人眼中他更像是一名管理咨询师,五年下来已经是这一领域的专家级人物,在个人收方面也非常可观。(x227)  

posted @ 2008-01-23 13:00 阿伟 阅读(221) | 评论 (0)编辑 收藏
转自:http://blog.csdn.net/jcc3120/archive/2007/12/26/1968677.aspx

本文列出了当今计算机软件开发和应用领域最重要十种关键技术排名,如果你想保证你现在以及未来的几年不失业,那么你最好跟上这些技术的发展。虽然你不必对这十种技术样样精通,但至少应该对它们非常熟悉。

  一、XML

  在十种技术中,最重要的一种技术我想应该非XML莫属。这里不仅仅指XML规范本身,还包括一系列有关的基于XML的语言:主要有XHTML,XSLT,XSL,DTDs,XML Schema(XSD),XPath,XQuery和SOAP.如果你现在还对XML一无所知,那么赶快狂补吧。XML是包含类似于HTML标签的一个文本文件,在这个文件中定义了一个树型结构来描述它所保存的数据

  XML最大的优点是你既可以在这个文本文件中存储结构化数据,也可以在其中存储非结构化数据——也就是说,它能包含和描述"粗糙的"文档数据,就象它描述"规则的"表格数据一样。

  XHTML是目前编写HTML的首选方法;因为XHTML本身就是格式良好的XML,与通常畸形的HTML文档相比, XHTML格式文档更容易处理。

  XSLT和XSL是对XML文档进行转换的语言。它们可以将XML文档转换成各种格式,比如另一个文本文件、PDF文件、HTML文件、逗号分割的文件,或者转换成其它的XML文档。

  DTDs 和XML Schema用来描述XML文件所包含的数据内容的类型,使你不用编写定制的代码就能对XML文档的内容进行"有效性"检查,使内容强行遵守给出的规则。

  XPath 和 XQuery是查询语言,用它们可以从XML文档中吸取单个的数据项或者数据项列表。XQuery的功能特别强大,因为它对XPath查询进行了扩展。实际上,XQuery和XML的关系就像SQL之于关系数据库一样。

  SOAP是Web services间进行通讯的标准协议。你不必知道SOAP协议的所有细节,但是你应该熟悉其常用规则及其工作原理,这样你才能使用它。

  二、Web Services

  Web服务是XML流行后的直接产物。因为XML可以描述数据和对象,XML大纲可以保证XML文档数据的有效性,因为XML的基于文本的规范,因而XML文档极其适合于作为一种跨平台通讯标准的基本格式。如果你还没有接触过Web服务,那么过不了多久你肯定会碰到它,所以必须熟练掌握Web服务,最好是精通它,因为它是迄今为止应用程序间跨不同种类机器、语言、平台和位置通讯的最简单的一种方式。不管你需不需要它,Web服务都会是将来互用性的主要趋势。

  XML工作组的John Bosak曾说过:"XML使得Java有事可做",那么,我们也可以说,Web服务使得所有语言都有事可做。Web服务让运行在大型机上的COBOL应用程序与运行在手持设备上的应用程序相互沟通;让Java小应用与。NET服务器相互通讯,让桌面应用与Web服务器进行无缝交互,不但为商业数据处理,同时也为商业功能提供了方便的实现——并且这种实现与语言、平台、和位置无关。

  三、面向对象编程

  许多程序员仍然认为OOP乃技术的象牙之塔,但是细细想一下过去十年里在面向对象领域里占据过统治地位的开发语言之后,你就不会这么认为了,OOP理念从Smalltalk开始,然后蔓延到C++和Pascal(Delphi),到Java成为真正的主流,几年之后,VB.NET 和 C#的出现可以说是OOP发展到了登峰造极的地步。虽然使用这些语言不必了解OOP的概念,但如果你缺乏一些OOP的基本知识和方法,我想你很难在逐渐疲软的就业市场中找到工作。

 四、Java, C++, C#, VB.NET

  如果你热衷于技术,并且热爱编程,那么我想你应该轻松玩转这些高级语言,我说的玩转并不一定要你成为超级编程高手。而是能看懂用这些语言编写的代码即可。如果你还有精力用它们编码那就更好了。其实这种机会甚少。但是看代码的机会很多,学习编程的最有效的一种方式就是看源代码——浩如烟海的源代码中很多都不是用你所钟爱的开发语言编写的。

  在过去的几年里,各个语言功能的发展基本上都差不多。现在你完全可以用VB.NET来写Windows服务、Web应用或者命令行程序。即使你只用其中的一种语言写程序。我认为也完全有必要学习另外一种语言,使自己能阅读和理解它们现有的例子代码,并且能将一种语言编写的代码转换成你首选的编程语言代码。这里列出的四种语言可谓是一个强大的开发语言工具箱,如果你掌握了它们,毫无疑问你一定是一个众人仰慕的高手。这里我要声明一下:那就是我并没有要忽略和排除其它的高级语言,如:FORTRAN、COBOL、APL、ADA、Perl和Lisp等等,根据你所从事的领域不同,应该选择适合的语言和工具。

  五、JavaScript

  Java 和JavaScript两者的名字尽管很类似,但它们之间并没有什么关系。为什么一种脚本语言会如此重要,以至于将它列入十种关键技术之一呢?仔细想一下就知道了,目前所有主流的浏览器都使用JavaScript.如果你要编写Web应用程序,那么JavaScript不可或缺。此外,JavaScript还能作为一种服务器端的脚本语言,如将它嵌入在ASP、ASP.NET中,或者嵌入XSLT来扩展功能。目前JavaScript在Mozilla/Netscape中是激活基于XUL界面的首选语言,它派生出了ActionScript,成为Flash MX应用的编程语言。还有就是JavaScript极有可能成为未来新设备的脚本语言以及主流应用的宏语言。

  相比之下,VBScript虽然在微软的产品中得到很好的支持,但从长远来看,没有迹象表明它会有美好前途。微软自己都趋向于用JavaScript(或者用由JavaScript派生的JScript)来编写其客户端脚本代码。因此,如果你要选择脚本语言,非JavaScript莫属。

  六、Regular Expressions

  从所周知,关系数据库的查询使用SQL,搜索XML文档用XPath 和XQuery,而正则表达式则用来搜索纯文本。例如,你可以用一个命令来查找或删除HTML格式文件中的注释内容。大家都用过"IndexOf"、"InStr"以及"Like"这些内建在JavaScript或VB中的文本搜索函数,这些函数虽然很容易使用,但是它们的功能却无法与正则表达式同日而语——现在每一种主流的开发语言都提供对正则表达式的存取。尽管有人认为正则表达式本身的读写艰涩难懂,但毕竟它的功能强大,使用它的领域也越来越多。

  七、Design Patterns

  就像OOP通过创建和分类对象来简化编程一样,设计模式将普通的对象交互分类成指定的模型,这是一个从一般到具体的过程。OOP的成分使用得越多,设计模式就显得越有用武之地。所以你必须理解它们,跟上其总体理论的发展。

  八、Flash MX

  当你需要比HTML和CSS所能提供的更多的客户端图形和编程能力时,Flash是最佳选择。在Flash中编程比用Java小应用或者。NET代码来得快得多,也容易得多。

  在最新版本中(MX),Flash不仅可以画图和进行动画打包,它还是个高度的可编程应用环境。具备强大的与SOAP Web服务沟通的能力,可以调用运行在远端服务器上的ColdFusion、Java或。NET代码。可以说Flash几乎无处不在,包括手持设备、置顶盒、甚至是新的平板电脑,你到处都可以见到它的身影,所以使用它实际上可以扩展和延伸你的应用程序使用领域。

 九、Linux/Windows

  这是当今PCs机操作系统的两大阵容,如果你想在计算机行业里混,就一定要熟悉它们。对于Linux,最好能自己安装,配置,下载它的图形用户界面以及一些应用程序。自己安装Apache并会编写Web应用程序。要清醒地认识到这个世界除了Windows之外,还有Linux的存在。并且这种局面将会长期存在。反过来,如果你是一个死忠的Linux开发者,不要再继续对Windows的憎恶,要相互学习,取长补短,看看Windows有什么好的东东可以采纳。记住Windows仍然是桌面之王。

  谁也说不准你们公司什么时候会决定从Linux转向Windows,或者从Windows转向Linux.谁也说不准什么时候你会跳槽跑到另外一个使用不同平台的公司上班——或者即便不跳槽,也有可能在不同平台上开始另外一个杀手级项目——所以最好在每个平台上都积累一些经验,而不要在一棵树上吊死。

  十、SQL

  尽管SQL在当今众多的技术中已不是什么新东西,而且在未来的十年里它的作用很有可能被削弱,甚至整个被淘汰,但它仍然是一种基本技能——别看它是一种基本技能,至今仍有许多开发人员不懂什么是SQL或对它了解不多。不要指望基于图形用户界面的SQL构造器会帮你的忙,还是自己亲手写SQL查询吧,确定你掌握了SQL的基本语法。现在理解了SQL,不仅对以后学习XQuery有所裨益,而且可以使你很快找到简化或改进当前开发项目的途径。

  尾声:培养对技术的好奇心

  其实,不管技术的发展趋势如何,每个人最重要的一个技能是好奇心。敢于面对挑战,在你目前或未来的工作中,新语言或新技术可能很重要,也可能不怎么重要,你所学习的东西并不一定非要针对你的工作。不要怕失败,任何新的技术对初学者来说都是困难的。大多数的失败都可以归咎于本身急功近利,希望速成。俗话说——千里之行,始于足下,应该脚踏实地,一步一个脚印地往前走。不要让时间来左右你行动,而是要利用时间来关注、研究、测试新的开发技术和工具。

 

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

posted @ 2008-01-23 12:44 阿伟 阅读(196) | 评论 (0)编辑 收藏

今天MSN死活登录不上,最后在网上查了资料,发现比较常见的问题是系统日期不对造成的,我也检查了系统日期,就是没发现什么问题,知道最后才发现年份错了,刚进入2008年,还没反应过来,系统日期是2007,系统时间改完后就直接登录上去了,网上有很多不同问题的解决方法,保存下来,以备日后使用:

最有可能的原因: 系统时间错误

返回信息:80048820,总是说防火墙设置阻止MSN的连接。但在MSN的网络连接测试中都是成功。

解决方法:系统日期不对造成的!!!!,请你认真查看是否在你升级到MSN7.5以后,系统日期变成了2004年,如果是直接将系统日期改成现在的时间。

点击右下角系统时间设置为当前正确时间。OK!

2、原因不明:系统为MSN 7.5

解决方法:打开“Internet Explorer”,点击“工具”里的“Internet选项”,选“高级”,点击“还原默认设置”,再点击“应用”,最后“确定”,一切搞定,就这么简单


3、原因不明:

解决方法:当登陆MSN返回“重试”,“取消”和“帮助”三个选项时,先选择“帮助”,再选择“重试”,这样很快就登陆成功了。

这种方法是某网友WINDOWS 2000,ADSL上网,安装了FW。



4、80048820 错误

故障现象:80048820 错误,用MSN连接检测一下说端口有问题,检查时间是正确的

解决方法:把INTERNET 选项里的 检查服务器证书吊销状态的勾去掉就可以了。



谢谢,我的也是报的这样的错,用这个方法成功了

5、由于病毒防火墙引起

解决方法:如果用的是norton病毒防火墙,在Norton个人防火墙设置中,将程序列表中有MSN MESSAGE程序,左击中间下拉菜单,将其改为全部允许.


6、封包长度不对
故障现象:80048820


解决方法:MSN 7.5,adsl路由器,问题出在封包上,路由器的封包长度由1496调到1420后一切就OK 了

供参考:
登录路由器-〉网络参数-〉WAN口设置-〉在PPPoE高级设置里,把数据包MTU 1492改成1480。
此办法也可解决Foxmail无法发送附件和无法在网页邮件中粘贴附件的问题。

网友提供的其他一些解决方法:


可能存在以下情况:
- 您的 Microsoft .NET Passport 设置不正确。
- 防火墙设置阻止了 MSN Messenger。
- 安全设置阻止了 MSN Messenger。
- 您的时间日期设置可能不正确。
- 一个反病毒程序可能与MSN Messsenger相冲突。
- 您在使用不正确的密码或电子邮件地址尝试登录。

请按照所列顺序尝试以下解决方法:
1. 使用“连接问题疑难解答程序”解决问题。
a. 启动 MSN Messenger。
b. 在“工具”菜单上,单击“选项”。
c. 在“选项”对话框中,单击“连接”,然后在“连接设置”下单击“连接测试”。
注意:对于MSN Messenger 7.5,单击“连接”,然后在“连接问题疑难解答程序”在单击“开始”。
d. 按照“连接问题疑难解答程序”中的步骤进行操作。

2. 确认MSN Messenger是否被防火墙所阻止。请移至http://webmessenger.msn.com/ 登录Web Messenger。点击“启动MSN Web Messenger”确认您是否可以登录。如果可以,那么MSN Messenger有可能被防火墙所阻止。如果您的计算机运行的是第三方(非 Microsoft)软件或防火墙软件(例如,Zone Alarm,Norton网络安全专家,或McAfee),请确保该软件配置为允许 Messenger 运行,然后再次尝试登录 MSN Messenger。请移至http://messenger.msn.com/help/issues.aspx 参阅相关信息。

3. 通过执行下列操作调整 Internet Explorer 中的代理服务器设置:
a. 打开 Internet Explorer。
b. 在“工具”菜单上,单击“Internet 选项”。
c. 单击“连接”选项卡,然后单击“局域网设置”。
d. 清除“自动检测设置”复选框。
e. 单击“确定”,然后再次单击“确定”。

4. 请按如下步骤在MSN Messenger中清除代理服务器设置:

-MSN Messenger6.2
a. 开启MSN Messenger6.2
b. 在“工具”菜单上单击“选项”。
c. 在“选项”对话框中单击“连接”选项卡。清除“我使用代理服务器”设置。请不要选择此选项,除非网络管理员建议您这样做。
d. 连续按两次“确定”。

-MSN Messenger7.0
a. 开启MSN Messenger7.0
b. 单击“工具”菜单上的“选项”。
c. 在“选项”对话框左侧的主题列表中单击“连接”,然后单击“高级设置”。
d. 在SOCKS 4下删除内容
e. 在SOCKS 5下删除内容
f. 在HTTP代理服务器下删除内容
g. 连续按两次“确定”保存设置。

-MSN Messenger7.5
a. 开启MSN Messenger7.5
b. 单击“工具”菜单上的“选项”。
c. 单击“连接”,然后点击“高级设置”
d. 在SOCKS 下删除内容
e. 连续按两次“确定”保存设置。

5. 调整 Microsoft Internet Explorer 安全设置:
a. 启动 Internet Explorer。
b. 在“工具”菜单上,单击“Internet 选项”,然后单击“高级”选项卡。
c. 在“安全”部分,确保选中了以下所有复选框:
- 检查服务器证书吊销
- 使用 SSL 2.0
- 使用 SSL 3.0
d. 单击“确定”关闭窗口。
e. 注册 SSL 安全库。要执行此操作,请单击“开始”,单击“运行”,然后按照适用于您的操作系统的步骤进行操作。

注意 在成功执行每个命令后,您都会收到“DllRegisterServer succeeded.”消息。请在收到此消息后再执行下一条命令。

- Microsoft Windows XP 和 Microsoft Windows 2000:
i. 键入 %windir%\system32\REGSVR32 softpub.dll,然后按 ENTER 键。
ii. 键入 %windir%\system32\REGSVR32 wintrust.dll,然后按 ENTER 键。
iii. 键入 %windir%\system32\REGSVR32 initpki.dll,然后按 ENTER 键。

- Microsoft Windows Millennium Edition (Me) 和 Microsoft Windows 98:
i. 键入 %windir%\system\REGSVR32 softpub.dll,然后按 ENTER 键。
ii. 键入 %windir%\system\REGSVR32 wintrust.dll,然后按 ENTER 键。
iii. 键入 %windir%\system\REGSVR32 initpki.dll,然后按 ENTER 键。

f. 如果您使用的是 Windows XP,请清除安全套接字层 (SSL) 状态和自动完成历史记录:
i. 启动 Internet Explorer。
ii. 在“工具”菜单上,单击“Internet 选项”,然后单击“内容”选项卡。
iii. 在“证书”下,单击“清除 SSL 状态”。
iv. 收到报告 SSL 缓存成功清除的消息后单击“确定”。

6. 双击屏幕右下角的时区验证您的计算机的日期和时间设置正确无误。

7. 请再次尝试登录MSN Messenger

8. 如果您正在运行反病毒程序,请先关闭,看是否能登录MSN Messenger。如果可以,请联系您的软件制造厂商或查看相关文件如何配置解决此冲突。

9. 如果您收到“无效的用户名或密码”或“81000303”错误信息,请确保您使用的是正确的用户名和密码。确认您可以使用此帐户登录任何站点,请移至http://www.passport.com 点击“登录”,如果您可以成功登录,您会看见“登出”按钮。如果失败,请更改您的密码,您可以到http://memberservices.passport.net/default.srf/ 。 如果此方法有效,尝试再次登录MSN Messenger,请按如下步骤:

-MSN Messenger7.0或更早的版本
a. 在MSN Messenger主窗口的“文件”菜单中点击“登录”
b.输入电子邮件地址和密码
c.对于Microsoft Windows XP 和Microsoft Server2003,选择“自动登录”,然后按“确定”。
对于Microsoft Windows98,Microsoft Windows ME,和 Windows2000,选择“在这台电脑上保存我的用户名和密码”,然后按“确定”。

-MSN Messenger7.5
a. 在MSN Messenger 登录窗口,先清除“记住我的密码”复选框
b. 输入密码
c. 选择“记住我的密码”保存新的密码
d. 再选择“自动为我登录”

10. 如果您仍然无法登录MSN Messenger, .NET Messenger服务可能临时不可用。请等待几分钟后再尝试登录。或者移至visit http://messenger.msn.com/status.aspx 查看服务器状态。


再试试

在运行菜单中运行以下程序:
regsvr32 softpub.dll /s
regsvr32 wintrust.dll /s
regsvr32 initpki.dll /s
regsvr32 dssenh.dll /s
regsvr32 rsaenh.dll /s
regsvr32 gpkcsp.dll /s
regsvr32 sccbase.dll /s
regsvr32 slbcsp.dll /s
regsvr32 cryptdlg.dll /s

posted @ 2008-01-11 12:51 阿伟 阅读(2419) | 评论 (0)编辑 收藏