iLeichun

当前位置:首页

分享基于J2EE的Web可视化开发工具

分类:J2EE  来源:网络  时间:2010-10-21 23:25:09

  这是一款跨平台、数据库和浏览器的Web应用开发和部署平台,可以在您原有使用的技术框架上混合使用,可以使用Eclipse开发调试。这个版本是没有任何限制的正式完全版本。

  该软件能提高应用系统的开发效率,并降低成本。完善的基础架构,具有应用系统必须的完整功能,使企业仅致力于业务的开发。

  软件的功能如下:

  应用开发:提供可视化的WebBuilder集成开发环境,帮助应用系统的快速开发,支持使用Eclipse等开发工具的开发和调试。

  应用部署:使用基于Web的资源管理器进行应用的部署,支持Java,.Net,PHP等大部分Web应用的部署。

  应用描述语言:基于XML的Web应用描述语言,屏蔽不同平台、数据库和浏览器之间的差异。

  完整的组件框架:提供应用开发所需的经过封装的前后台组件、开发框架以及应用模块。

  另外是一个基于WebBuilder开发的基于web的资源管理器,可方便管理服务器上的文件系统,支持国际化,非常适合远程管理服务器上的文件,上传下载等,分享给大家。

Java EE 6核心特征:Bean Validation解析

分类:J2EE  来源:网络  时间:2010-10-21 23:24:11

  Bean Validation是Java EE 6数据验证新框架,Validation API并不依赖特定的应用层或是编程模型,这样同一套验证可由应用的所有层共享。它还提供了通过扩展Validation API来增加客户化验证约束的机制以及查询约束元数据仓库的手段。

  在Java EE 6的Bean Validation出现之前,开发者不得不在表示层框架、业务层以及持久层中编写验证规则以保证这些规则的同步性,但这么做非常浪费时间而且极易出错。Bean Validation是通过约束实现的,这些约束以注解的形式出现,注解可以放在JavaBean(如backing bean)的属性、方法或是类上面。约束既可以是内建的注解(位于javax.validation.constraints包下面),也可以由用户定义。一些常用的内建注解列举如下:

  ◆Min:被@Min所注解的元素必须是个数字,其值要大于或等于给定的最小值。

  ◆Max:被@Max所注解的元素必须是个数字,其值要小于或等于给定的最大值。

  ◆Size:@Size表示被注解的元素必须位于给定的最小值和最大值之间。支持Size验证的数据类型有String、Collection(计算集合的大小)、Map以及数组。

  ◆NotNull:@NotNull确保被注解的元素不能为null。

  ◆Null:@Null确保被注解的元素一定为null。

  ◆Pattern:@Pattern确保被注解的元素(String)一定会匹配给定的Java正则表达式。

  代码中通过Bean Validation注解声明了一些约束:


public class Address {   
       @NotNull @Size(max=30)   
       private String addressline1;   
 
       @Size(max=30)   
       private String addressline2;   
 
       public String getAddressline1() {   
          return addressline1;   
       }   
 
       public void setAddressline1(String addressline1) {   
          this.addressline1 = addressline1;   
       }   
   } 

  @NotNull指定被注解的元素addressline1不能为null;@Size指定被注解的元素addressline1和addressline2不能超过给定的最大值,即30个字符。

  在验证Address对象时,addressline1的值被传递到针对@NotNull约束的验证类以及针对@Size约束的验证类中,而addressline2的值被传递到针对@Size约束的验证类中,由相关的验证类进行验证。如下代码自定义了一个名为ZipCode的约束:


@Size(min=5, max=5)   
   @ConstraintValidator(ZipcodeValidator.class)   
   @Documented   
   @Target({ANNOTATION_TYPE, METHOD, FIELD})   
   @Retention(RUNTIME)   
   public @interface ZipCode {   
       String message() default "Wrong zipcode";   
       String[] groups() default {};   
   }

 

  可以将@ZipCode用在类、属性或是方法上,就像其他约束一样。


public class Address {   
       @ZipCode   
       private String zipCode;   
 
       public String getZipCode() {   
          return zipCode;   
       }   
 
       public void setZipCode(String zipCode) {   
          this.zipCode = zipCode;   
       }   
   } 

 

  Validation API

  开发者可以借助于Validation API以编程的方式验证JavaBean。Bean Validation API的默认包是javax.validation。下面对该包中的一些类进行说明:

  ConstraintValidator:这是一个接口,具体的约束验证类需要实现该接口。该接口定义了相关的逻辑以验证给定对象类型中的约束。

  Validator:Validahttp://java.sun.com/javaee/6/docs/api/index.html?javax/validation/Validator.htmltor接口持有对象验证图的契约。该接口的实现必须是线程安全的。

  ConstraintViolation:ConstraintViolation接口表示给定bean上的约束验证失败,它公开了约束违背上下文以及描述该违背情况的信息。

  ValidationException:如果在验证过程中出现了某些不可恢复的错误就会抛出ValidationException异常。某些情况下可以指定该异常,如不合法的分组(group)定义、不合法的约束定义以及不合法的约束声明等等。

  约束元数据请求API

  Bean Validation规范提供了查询约束仓库的手段。该API主要用于工具支持和与其他框架、库以及JSR的集成。Bean Validation规范旨在为对象约束提供一个验证引擎和元数据仓库。需要进行约束定义、验证和元数据的框架(Java EE或Java SE)可以利用Bean Validation规范完成这些功能,从应用或是基础设施的角度来看,这么做可以避免不必要的重复工作。

  Bean Validation已经集成到了JSF 2.0和JPA 2.0中。在JSF中可以将表单输入域与域对象的属性绑定起来。JSF 2和Bean Validation可以判断出绑定的是哪个属性并执行与之相关的验证,还会将约束违背的信息显示给用户。Hibernate Validator 4是Bean Validation规范的参考实现框架,其最新版增加了不少新特性,如分组验证、与JPA 2和JSF 2的自然集成以及扩展的注解集等等。

通过JVM原理理解字符串的比较

分类:J2EE  来源:网络  时间:2010-10-21 23:23:10

  Java中的字符串也是一连串的字符,但是与许多其他的计算机语言将字符串作为字符数组处理不同,Java将字符串作为String类型对象来处理。将字符串作为内置的对象处理允许Java提供十分丰富的功能特性以方便处理字符串。

  JVM运行时数据区的内存模型由五部分组成:

  (1)方法区

  (2)堆

  (3)JAVA栈

  (4)PC寄存器

  (5)本地方法栈

  对于String s = "haha" ,它的虚拟机指令:

  0: ldc "16; //String haha 2: astore_1 3: return

  ldc指令格式:

  ldc,index

  ldc指令过程:要执行ldc指令,JVM首先查找index所指定的常量池入口,在index指向的JVM常量池入口,JVM将会查找CONSTANT_Integer_info,CONSTANT_Float_info和CONSTANT_String_info入口。如果还没有这些入口,JVM会解析它们。而对于上面的hahaJVM会找到CONSTANT_String_info入口,同时,将把指向被拘留String对象(由解析该入口的进程产生)的引用压入操作数栈。

  astore_1指令格式:

  astore_1

  astore_1指令过程:要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1。

  return 指令的过程:

  从上面的ldc指令的执行过程可以得出:s的值是来自被拘留String对象(由解析该入口的进程产生)的引用,即可以理解为是从被拘留String对象的引用复制而来的,故我个人的理解是s的值是存在栈当中。上面是对于s值得分析,接着是对于"haha"值的分析,我们知道,对于String s = "haha" 其中"haha"值在JAVA程序编译期就确定下来了的。简单一点说,就是haha的值在程序编译成class文件后,就在class文件中生成了(大家可以用UE编辑器或其它文本编辑工具在打开class文件后的字节码文件中看到这个haha值)。执行JAVA程序的过程中,第一步是class文件生成,然后被JVM装载到内存执行。那么JVM装载这个class到内存中,其中的haha这个值,在内存中是怎么为其开辟空间并存储在哪个区域中呢?

  JVM常量池

  虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。对于String常量,它的值是在常量池中的。而JVM常量池在内存当中是以表的形式存在的,对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。说到这里,对JVM常量池中的字符串值的存储位置应该有一个比较明了的理解了。

  在介绍完JVM常量池的概念后,接着谈开始提到的"haha"的值的内存分布的位置。对于haha的值,实际上是在class文件被JVM装载到内存当中并被引擎在解析ldc指令并执行ldc指令之前,JVM就已经为haha这个字符串在常量池的CONSTANT_String_info表中分配了空间来存储haha这个值。

  既然haha这个字符串常量存储在常量池中,常量池是属于类型信息的一部分,类型信息也就是每一个被转载的类型,这个类型反映到JVM内存模型中是对应存在于JVM内存模型的方法区中,也就是这个类型信息中的JVM常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的。所以,haha的值是应该是存在堆空间中的。而对于String s = new String("haha") ,它的JVM指令:


0:   new             "16; //class String   
3:   dup   
4:   ldc             "18; //String haha   
6:   invokespecial   "20; //Method java/lang/String."":(Ljava/lang/String;)V   
9:   astore_1   
10:  return 

  new指令格式:new indexbyte1,indexbyte2

  new指令过程:

  要执行new指令,Jvm通过计算(indextype1<<8)|indextype2生成一个指向常量池的无符号16位索引。然后JVM根据计算出的索引查找JVM常量池入口。该索引所指向的常量池入口必须为CONSTANT_Class_info。如果该入口尚不存在,那么JVM将解析这个常量池入口,该入口类型必须是类。JVM从堆中为新对象映像分配足够大的空间,并将对象的实例变量设为默认值。最后JVM将指向新对象的引用objectref压入操作数栈。

  dup指令格式:dup

  dup指令过程:

  要执行dup指令,JVM复制了操作数栈顶部一个字长的内容,然后再将复制内容压入栈。本指令能够从操作数栈顶部复制任何单位字长的值。但绝对不要使用它来复制操作数栈顶部任何两个字长(long型或double型)中的一个字长。上面例中,即复制引用objectref,这时在操作数栈存在2个引用。

  ldc指令格式:ldc,index

  ldc指令过程:

  要执行ldc指令,JVM首先查找index所指定的常量池入口,在index指向的JVM常量池入口,JVM将会查找CONSTANT_Integer_info,CONSTANT_Float_info和CONSTANT_String_info入口。如果还没有这些入口,JVM会解析它们。而对于上面的haha,JVM会找到CONSTANT_String_info入口,同时,将把指向被拘留String对象(由解析该入口的进程产生)的引用压入操作数栈。

  invokespecial指令格式:invokespecial,indextype1,indextype2

  invokespecial指令过程:对于该类而言,该指令是用来进行实例初始化方法的调用。上面例子中,即通过其中一个引用调用String类的构造器,初始化对象实例,让另一个相同的引用指向这个被初始化的对象实例,然后前一个引用弹出操作数栈。

  astore_1指令格式:astore_1

  astore_1指令过程:

  要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1。

  return 指令的过程:

  从方法中返回,返回值为void,要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中,即将引用类型或者returnAddress类型值存入局部变量1。

  通过上面6个指令,可以看出,String s = new String("haha");中的haha存储在堆空间中,而s则是在操作数栈中。上面是对s和haha值的内存情况的分析和理解;那对于String s = new String("haha");语句,到底创建了几个对象呢?这里"haha"本身就是JVM常量池中的一个对象,而在运行时执行new String()时,将JVM常量池中的对象复制一份放到堆中,并且把堆中的这个对象的引用交给s持有。所以这条语句就创建了2个String对象。下面是一些String相关的常见问题:

  String中的final用法和理解

  final StringBuffer a = new StringBuffer("111"); final StringBuffer b = new StringBuffer("222"); a=b;//此句编译不通过 final StringBuffer a = new StringBuffer("111"); a.append("222");//编译通过

  可见,final只对引用的"值"(即内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。

  String 常量池问题的几个例子

  下面是几个常见例子的比较分析和理解:


final StringBuffer a = new StringBuffer("111");   
final StringBuffer b = new StringBuffer("222");   
a=b;//此句编译不通过   
final StringBuffer a = new StringBuffer("111");   
a.append("222");//编译通过 

 

  分析:JVM对于字符串常量的"+"号连接,将程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值,拿"a" + 1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。


String a = "ab";
String bb = "b"; String b = "a" + bb; 
System.out.println((a == b)); 
//result = false

  分析:JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。


String a = "ab"; 
final String bb = "b"; 
String b = "a" + bb; 
System.out.println((a == b));
 //result = true

  分析:和[3]中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。


String a = "ab"; final String bb = getBB(); 
String b = "a" + bb; 
System.out.println((a == b)); 
//result = false private static String getBB() { return "b"; }

  分析:JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面程序的结果为false。通过上面4个例子可以得出得知:


String s = "a" + "b" + "c"; 
就等价于String s = "abc"; 
String a = "a"; String b = "b"; 
String c = "c"; 
String s = a + b + c;

  这个就不一样了,最终结果等于:


StringBuffer temp = new StringBuffer(); 
temp.append(a).append(b).append(c); 
String s = temp.toString();

  由上面的分析结果,可就不难推断出String 采用连接运算符(+)效率低下原因分析,形如这样的代码:


public class Test { public static void main(String args[]) {
 String s = null; 
for(int i = 0; i < 100; i++) { s += "a"; } } }

  每做一次 + 就产生个StringBuilder对象,然后append后就扔掉。下次循环再到达时重新产生个StringBuilder对象,然后 append 字符串,如此循环直至结束。 如果我们直接采用 StringBuilder 对象进行 append 的话,我们可以节省 N - 1 次创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider对象来进行append操作。String对象的intern方法理解和分析:


public class Test4 {   
private static String a = "ab";    
public static void main(String[] args){   
String s1 = "a";   
String s2 = "b";   
String s = s1 + s2;   
System.out.println(s == a);//false   
System.out.println(s.intern() == a);//true     
}   

  这里用到Java里面是一个常量池的问题。对于s1+s2操作,其实是在堆里面重新创建了一个新的对象,s保存的是这个新对象在堆空间的的内容,所以s与a的值是不相等的。而当调用s.intern()方法,却可以返回s在JVM常量池中的地址值,因为a的值存储在常量池中,故s.intern和a的值相等。

J2EE开发中几个主流框架的简短使用总结

分类:J2EE  来源:网络  时间:2010-10-21 23:21:24

  spring,SSH框架处于一个难于撼动的地位,spring以其轻量级,易操作的,开发高效等优点,被业界内广泛应用。IOC及AOP是spring被重要应用的两点,由于struts,struts2,webword等一系列view框架的存在,springMVC的应用显得有些力不从心,不能被广为推广使用。AOP使用中目前主要用,配置ehcache的时候用到过一次,其它地方应用不是太多,更多的是IOC的操作。与hibernate,struts结合使用,采用不同的设计模式,面向接口编程,已经成为业界公认的框架模式。struts的action交由spring配置bean文件来完成,由spring代理其action的操作,数据源/数据库连接池也在其配置文件里完成。

  spring更重要的是完成了应用间的解耦,更加有利于程序的维护,扩展。

  hibernate,ORM领域中的经典之作。OO与关系型数据库处于不协调发展的局面,数据库如今却成了OO编程路上的绊脚石,阻碍着OO向前发展,ORM于此解决了关系型数据库与对象间的映射。hibernate自动生成sql语句封装在内部,开发人员无须写SQL语句,HQL语法又相当简单,大大简化了开发的步骤。由于hibernate处理持久层的角色,只要数据库设计合理,更多的是利用IDE(MyEclipse)就可以生成相对的持久类POJO以及映射配置文件,与数据库关联起来,操作POJO类即操作数据库。spring对hibernate提供了很好的兼容性,在hibernate配置二级缓存,可以对系统应用起到良好的效果。

  Ibatis,ORM领域中一个框架,相对hibernate而言,ibatis更加小巧,更易于学习,对数据库设计不太友好的,使用IBATIS比hibernate更合适。ibatis不会像hibernate一样生成SQL,而是需要开发人员自己去写SQL语句,这一点也给于了开发人员更灵活的设计与操作。hibernate相对来说,在一些复杂的数据处理方,并不如IBATIS灵活。struts+ibatis+spring与SSH相比,也是一种不错的组合,巧手(7iaoshou)就是基于此框架组合。

  struts,MVC经典的一个实现,近阶段依然于其它框架无法超载的地位,不是说struts有多强大,完美,而是struts似乎成为了MVC开发的标准。主要应用有以下这些:对于大中型的企业级应用,多模块开发必然应用到,很多模块只有分开在不同的配置文件里写,才能更有利于书写,维护;自身FORM的验证,validate;struts丰富的页面标签书写页面更加灵活强大;与spring,hibernate完美的结合在一起使用,快速高效开发。

  其它WEB开发框架还有JSF,Struts 2.0,webwork等等,由于只是简单了解,并未投入生产使用,只能由读者自己去体会了。

JNDI 在 J2EE 中的角色收藏

分类:J2EE  来源:网络  时间:2010-10-21 23:20:35

  掌握 J2EE 是件令人生畏的事,因为它包含的技术和缩略语在不断地增长。Java 命名和目录接口(Java Naming and Directory Interface,JNDI)从一开始就一直是 Java 2 平台企业版(JEE)的核心,但是 J2EE 开发新手经常用不好它。本文将消除 JNDI 在 J2EE 应用程序中所扮演角色的神秘性,并展示它如何帮助应用程序从部署细节中解脱出来。

  虽然 J2EE 平台提高了普通企业开发人员的生活水平,但是这种提高是以不得不学习许多规范和技术为代价的,这些规范和技术则是 J2EE 为了成为无所不包的分布式计算平台而整合进来的。Dolly Developer 是众多开发人员中的一员,她已经发现了一个特性,该特性有助于缓解随企业级应用程序部署而带来的负担,这个特性就是 JNDI,即 Java 命名与目录接口(Java Naming and Directory Interface)。让我们来看看 Dolly 在没有 JNDI 的时候是怎么做的,以及她是如何正确地应用 JNDI 来改善其状况的。

  所有人都非常熟悉的旅程

  Dolly Developer 正在编写使用 JDBC 数据源的 Web 应用程序。她知道自己正在使用 MySQL,所以她将一个对 MySQL JDBC 驱动程序类的引用进行了编码,并通过使用适当的 JDBC URL 连接到其 Web 应用程序中的数据库。她认识到数据库连接池的重要性,所以她包含了一个连接池包,并把它配置成最多使用 64 个连接;她知道数据库服务器已经被设置成最多允许 128 台客户机进行连接。

  Dolly 在走向灾难

  在开发阶段,每件事都进行得很顺利。但是,在部署的时候,开始失控。Dolly 的网络管理员告诉她,她不能从她的桌面机访问生产服务器或登台服务器(staging server),所以她不得不为每个部署阶段开发不同的代码版本。因为这种情况,她需要一个新的 JDBC URL,所以还要为测试、阶段和生产进行独立的部署。(一听到要在每个环境中建立单独部署,熟悉配置管理的人会战战兢兢的,但是既然这是种非常普遍的情况,所以他们也只好硬着头皮上了。)

  就在 Dolly 认为通过不同的 URL 建立彼此独立的部署已经解决了自己的配置问题时,她发现她的数据库管理员不想在生产环境中运行 MySQL 实例。他说,MySQL 用作开发还可以,但是对于任务关键型数据而言,业务标准是 DB2®。现在她的构建不仅在数据库 URL 方面有所不同,而且还需要不同的驱动程序。

  事情越变越糟。她的应用程序非常有用,并且变得非常关键,以致于它从应用服务器那里得到了故障恢复的能力,并被复制到 4 个服务器集群。但是数据库管理员提出了抗议,因为她的应用程序的每个实例都要使用 64 个连接,而数据库服务器总共只有 200 个可用连接 —— 全部都被 Dolly 的应用程序占用了。更麻烦的是,DBA 已经确定 Dolly 的应用程序只需要 32 个连接,而且每天只有一个小时在使用。随着她的应用程序规模扩大,应用程序遇到了数据库级的争用问题,而她的惟一选择就是改变集群的连接数量,而且还要做好准备,在集群数量增长或者应用程序复制到另一个集群时再重复一次这样的操作。看来她已经决定了如何配置应用程序,应用程序的配置最好是留给系统管理员和数据库管理员来做。

Java构造函数的执行情况

分类:Java  来源:网络  时间:2010-10-21 23:18:51

  Java 在创建对象的时候会要执行它的构造函数。不仅如此,Java 还要执行父类的构造函数,往上一级一级直到没有父类为止。对于初学者来说,有三个问题不容易搞懂:

  1、父类的构造函数是否一定会执行?

  2、是先执行子类的构造函数还是先执行父类的构造函数?

  3、如果父类有多个构造函数,那么 Java 会选择哪一个?

  - 父类的构造函数是否一定会执行?

  是的,父类的构造函数一定会执行。所以如果某个类的层次很深,那么它创建对象时就会要执行一大堆的构造函数。

  - 是先执行子类的构造函数还是先执行父类的构造函数?

  Java 会顺着继承结构往上一直找到 Object,然后从 Object 开始往下依次执行构造函数。先执行父类的构造函数,那么子类的构造函数执行的时候就不需要担心父类的成员是否初始化好了。

  - 如果父类有多个构造函数,那么 Java 会选择哪一个?

  如果父类有多个构造函数,那么子类可以在构造函数中选择其中一个(且最多只能选择一个)来执行。如果子类没有选择,那么 Java 将会执行父类的缺省构造函数。下面是一个例子:

  父类:


 view plaincopy to clipboardprint?
  public class SuperClass {
  public SuperClass() {
  System.out.println("super class constructed.");
  }
  public SuperClass(String name) {
  System.out.println("super class constructed with name: " + name);
  }
  }
  public class SuperClass {
  public SuperClass() {
  System.out.println("super class constructed.");
  }
  public SuperClass(String name) {
  System.out.println("super class constructed with name: " + name);
  }
  }

  子类:


 view plaincopy to clipboardprint?
  public class SubClass extends SuperClass {
  public SubClass() {
  System.out.println("sub class constructed.");
  }
  public SubClass(String name) {
  //这一句在语法上不是必须的。但有没有这一句,执行起来不一样。有了这一句,就表示子类的构造过程中调用
  //的是父类的带字符串参数的构造函数,也就是 public SuperClass(String name) 这个方法。如果没有这一
  //句,就表示子类的构造过程中调用的是父类的缺省构造函数。
  super(name);
  System.out.println("sub class constructed with name: " + name);
  }
  public static void main(String[] args) {
  new SubClass();
  new SubClass("world");
  }
  }
  public class SubClass extends SuperClass {
  public SubClass() {
  System.out.println("sub class constructed.");
  }
  public SubClass(String name) {
  super(name);
  System.out.println("sub class constructed with name: " + name);
  }
  public static void main(String[] args) {
  new SubClass();
  new SubClass("world");
  }
  }

  

使用ActionForward优化Struts应用程序

分类:Struts  来源:网络  时间:2010-10-21 23:13:11

  从一个servlet内部,通过运用javax.servlet.RequestDispatcher类的forward方法你就可以将控制流程引导到一个目的资源。在login应用程序的action类中,该代码形式如下:


  RequestDispatcher rd = request.getRequestDispatcher(destination);
  rd.forward(request, response);

  其中destination就是到一个目的资源的路径。

  但是在一个典型的Struts应用程序中,你可以用ActionForward类作为替代。运用这个类的好处就是你不再需要创建一个RequestDispatcher对象并调用它的forward方法了。

  你可以将ActionForward类用于一个Action类的execute方法中。注意,其中一个重载的execute方法有如下的定义,它返回一个ActionForward对象:


  public ActionForward execute(
  ActionMapping mapping,
  ActionForm form, HttpServletRequest request,
  HttpServletResponse response)
  throws Exception

  因为当时我们还没有讲到ActionForward类,所以在本系列的第一部分和第二部分中所有Action类的execute方法都只返回了空值。现在,在一个Action类的execute方法中,你就可以用ActionForward类来代替下面这个RequestDispatcher对象实例了:


 RequestDispatcher rd = request.getRequestDispatcher(destination);
  rd.forward(request, response);

  新的代码变成:return (new ActionForward(destination));

  构建ActionForward对象

  ActionForward类提供了下面五种构造器:


    public ActionForward()
  public ActionForward(String path)
  public ActionForward(String path, boolean redirect)
  public ActionForward(String name, String path, boolean redirect)
  public ActionForward(String name, String path, boolean redirect, boolean contextRelative)

  虽然这些构造器是不需要说明的,但我们应该注意下面几点。在这些构造器中,第二种可能是最常用的。后四种构造器中的path参数表示的是到目的资源的路径。后三种构造器中的redirect布尔值表示的是是否执行了一个重定向(redirect)。(缺省情况下,这个值设置为false,因为redirect比forward慢。)最后,第五个构造器中的contextRelative布尔值表示该路径是否应该是context-relative的,而不是module-relative的。

  同样,一个ActionForward实例也可以有一个逻辑名称,你可以用这个名称来查找与一个特殊的ActionMapping对象相关的实例。(参见本系列第四部分关于ActionMapping的讲述。)

  学习ActionForward类的方法

  ActionForward类定义了三个保护字段——name、path和redirect——它们构成了ActionForward的三个属性。ActionForward类提供getter和setter方法来从这些字段读值、给这些字段赋值。这些方法是不需要说明的,定义如下:


 public boolean getContextRelative()
  public void setContextRelative(boolean contextRelative)
  public String getName()
  public void setName(String name)
  public String getPath()
  public void setPath(String path)
  public boolean getRedirect()
  public void setRedirect(boolean redirect)

  除此之外,ActionForward类还重载了toString方法并返回:"ActionForward[" + name + "]"其中name是名称字段。

  最后,还有一个freeze方法,它固定了一个组件的配置。

  再次运用Login应用程序

  要完全了解ActionForward类,我们需要再次运用在本系列第一部分和第二部分构建的login应用程序。你可以下载完整的应用程序,把它重命名为myStrutsApp2。它的web.xml和struts-config.xml文件同myStrutsApp1中的文件是一样的,JSP页面也没有改变。只有action类同以前不同。

  注意下面这行代码是新的:return (new ActionForward("/mainMenu.jsp"));

  它替代了下面这些代码,现在它们都被注释出来了:


 RequestDispatcher rd = request.getRequestDispatcher("/mainMenu.jsp");
  rd.forward(request, response);

  同样,下面这些代码也都被重写了:


 // RequestDispatcher rd = request.getRequestDispatcher("/login.jsp");
  // rd.forward(request, response);

  新的代码变成:return (new ActionForward("/login.jsp"));

  ViewSecretAction类

  ViewSecretAction也变得更好了。execute方法最后的这三行代码现在由一行来处理了,返回(new ActionForward (“/viewSecret.jsp”)):


 //RequestDispatcher rd =request.getRequestDispatcher("/viewSecret.jsp");
  //rd.forward(request, response);
  //  return null;

  接下来,我们来重新查看LogoutAction类(见列表3)。注意execute方法中下面这些代码已经被替代了:


 // RequestDispatcher rd = request.getRequestDispatcher("/login.jsp");
  // rd.forward(request, response);
  // return null;

  你只需要用下面这一行代码来取代它就行了:return (new ActionForward("/login.jsp"));

  ActionForward是个很有用、功能很多的类,它可以让你更简单、更快、更直接地完成许多事情,这可能就是它很受欢迎的原因。在本系列的第四部分,你可以了解另一个重要的类org.apache.struts.action.ActionMapping,它可以使你的代码更有效、更漂亮。

Struts 查看文件内容功能的方法

分类:Struts  来源:网络  时间:2010-10-21 23:11:14

  1.Action 代码

 


 /*
  * $Id: ShowFileAction.java 471754 2006-11-06 14:55:09Z husted $
  *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements. See the NOTICE file
  * distributed with this work for additional information
  * regarding copyright ownership. The ASF licenses this file
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied. See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
  package org.apache.struts.webapp.validator;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import org.apache.struts.action.Action;
  import org.apache.struts.action.ActionForm;
  import org.apache.struts.action.ActionForward;
  import org.apache.struts.action.ActionMapping;
  import org.apache.commons.logging.LogFactory;
  import org.apache.commons.logging.Log;
  /**
  * Action which retrieves a file specified in the parameter
  * and stores its contents in the request, so that they
  * can be displayed.
  */
  public class ShowFileAction extends Action {
  /** Logging Instance. */
  private static final Log log = LogFactory.getLog(ShowFileAction.class);
  public ActionForward execute(ActionMapping mapping,
  ActionForm form,
  HttpServletRequest request,
  HttpServletResponse response)
  throws Exception {
  // Get the file name
  String fileName = mapping.getParameter();
  StringBuffer fileContents = new StringBuffer();
  if(fileName != null) {
  InputStream input = servlet.getServletContext().getResourceAsStream(fileName);
  if (input == null) {
  log.warn("File Not Found: "+fileName);
  } else {
  InputStreamReader inputReader = new InputStreamReader(input);
  char[] buffer = new char[1000];
  while (true) {
  int lth = inputReader.read(buffer);
  if (lth < 0) {
  break;
  } else {
  fileContents.append(buffer, 0, lth);
  }
  }
  }
  } else {
  log.error("No file name specified.");
  }
  // Store the File contents and name in the Request
  request.setAttribute("fileName", fileName);
  request.setAttribute("fileContents", fileContents.toString());
  return mapping.findForward("success");
  }
  }

  分析:


 String fileName = mapping.getParameter();

  其中mapping 是ActionMapping 对象,是ActionConfig的子对象。 其中ActionConfig封装了Struts-config.xml 中的配置信息。

  inputStream input = servlet.getServletContext().getResourceAsStream(fileName);

  每个Web应用程序都是一个独立的Servlet容器,每个Web应用程序分别用一个ServletContext对象。ServletContext对象包含在ServletConfig对象中,

  调用ServletConfig.getServletContext()方法获取ServletContext对象。

  1、 getResourcePath 返回一个包含该目录和文件路径名称的Set集合

  2、 getResource 返回映射到资源上的URL对象。

  3、 getResourceAsStream 返回连接到某资源上的InputStream对象

  InputStreamReader inputReader = new InputStreamReader(input);

  需要重新包装成字符处理。

  【2】配置文件


    <!-- Show validations.xml --> 
        <action path="/showValidation"    
                        type="org.apache.struts.webapp.validator.ShowFileAction"    
                        scope="request"    
                        parameter="/WEB-INF/validator/validation.xml"> 
                <forward name="success" path="/showFile.jsp" /> 
        </action>

  通过传递不同的parameter,读取不同的文件。

  【3】在JSP页面 读取信息


    <!-- Show validations.xml --> 
        <action path="/showValidation"    
                        type="org.apache.struts.webapp.validator.ShowFileAction"    
                        scope="request"    
                        parameter="/WEB-INF/validator/validation.xml"> 
                <forward name="success" path="/showFile.jsp" /> 
        </action>

  bean:write 标签 有个filter属性。如果为true 的话,则表示

  将把输出内容中的特殊HTML符号作为普通字符串来显示;如果filter属性为false,则不会把输出内容中的HTML符号转化为普通字符串.

Struts2拦截器execAndWait简介

分类:Struts  来源:网络  时间:2010-10-21 23:09:35
  1、在struts.xml
 

<action name="registerclass="com.abc">
<interceptor-ref name="defaultStack"></interceptor-ref>
      <interceptor-ref name="execAndWait">
      <param name="excludeMethods">input</param>
      <!-- 等待时间,执行时间没有超过此值,将不显示等待画面 (毫秒)
      <param name="delay">1000</param>-->
      <!-- 间隔检查时间,检查后台进程有没有执行完毕,如果完成了它就立刻返回,不用等到等待,用户不会看到等待画面 
      <param name="delaySleepInterval">50</param>-->
      </interceptor-ref>
</action>
 
@Override
 public String execute() throws Exception
 {
  while(process<total){
  process++;
  Thread.sleep(900);
  System.out.println(process);
  }
  return SUCCESS;
 }
  
2、增加result

    <result name="wait">wait.jsp</result>
  3、

<%@page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>  
<%@taglib prefix="s"uri="/struts-tags"%>  
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">  
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">  
<meta http-equiv="refresh" content="1;url=<s:url includeParams="none" />"/>  
<title>
</title>
</head>
<body>
<h1>数据处理中,请稍等......</h1>
process:${process }  total:${total }
<br>
如果没有自动跳转请<a href="<s:url includeParams="all" />">点这里</a>.
其中的includeParams参数取值为:<br>
none,不把参数加入到url参数中<br>
all,是把get和post中的参数加入到url参数中<br>
get,是只把get中的参数加入到url参数中
</body>
</html>
  4、Action实现SessionAware接口
  因为这个action将会以单独的线程执行,所以你不能用ActionContext,因为它是ThreadLocal.这也就是说如果你要访问session数据,你必须实现 SessionAware结构而不是调用ActionContext.getSesion() 。

 public interface SessionAware{
  public void setSession(Map map);
  }
  public abstract class AbsBasicAction extends ActionSupport implements SessionAware{
  /** 当前 Session */
  protected Map session ;
  public void setSession(Map session) {
  this.session = session ;
  }
  }
 

Java中JTable的用法简介

分类:Java  来源:网络  时间:2010-10-21 22:57:39

  Swing颇受欢迎的JTable类为显示大块数据提供了一种简单的机制。JTable有很多东西是用于数据的生成和编辑,其中的很多东西还可以自定义,从而更进一步增强其功能。本文会引导你一步步地进入JTable的世界。

  Listing A包含了一个简单示例的代码,这个示例会说明常用JTable的行为。用户能够更改JTable的布局、拖放它的栏,或者通过拖动标题的分隔线来改变其大小。

  这些列被保存在一个String数组里:


  String[] columnNames = {"Product","Number of Boxes","Price"};

  数据被初始化并保存在一个二维的对象数组里:


 Object[][] data =
  {
  {"Apples", new Integer(5),"5.00"},
  {"Oranges", new Integer(3),"6.00"},
  {"Pears", new Integer(2),"4.00"},
  {"Grapes", new Integer(3),"2.00"},
  };

  JTable是使用data和columnNames构成的:


 JTable table = new JTable(data, columnNames);

  查看JTable

  JTable的高度和宽度按照下面的方法来设定:


 table.setPreferredScrollableViewportSize(new Dimension(300, 80));

  如果JTable的一个列或者JTable窗口自身的大小被重新确定,那么其他列会被相应的缩小或者放大,以适应新的窗口。使用setAutoResizeMode()方法就能够控制这种行为:


 table.setAutoResizeMode(int mode);

  mode整数字段可能的值有:


    AUTO_RESIZE_OFF
  AUTO_RESIZE_NEXT_COLUMN
  AUTO_RESIZE_SUBSEQUENT_COLUMNS
  AUTO_RESIZE_LAST_COLUMN
  AUTO_RESIZE_ALL_COLUMNS

  表格的缺省值

  单元格内方格坐标线的缺省颜色是Color.gray。要更改这些方格坐标线的颜色,就要用到:


 table.setGridColor(Color.black);

  你可以用下面的方法来改变行的高度:


 table.setRowHeight(intpixelHeight);

  各个单元格的高度将等于行的高度减去行间的距离。

  在缺省情况下,内容的前景颜色和背景颜色的选择都是由Swing的所见即所得的实现来确定的。你可以使用下面的方法来更改选择的颜色:


 table.setSelectionBackground(Color.black); table.setSelectionForeground(Color.white);

  你也可以隐藏单元格的方格坐标线,就像下面这样:


 table.setShowHorizontalLines(false);
  table.setShowVerticalLines(false);

  列的宽度

  JTable组件有几个控制表格特性的类和接口。TableColumn会不断追踪列的宽度,并负责列大小的调整,包括最大和最小宽度。

  TableColumnModel管理着TableColumns的集合以及列的选择。要设置某个列的宽度,就要为表格列的模型设置一个参照。然后,取得想要的TableColumn并调用其setPreferredWidth()方法:


 TableColumncolumn = table.getColumnModel().getColumn(0);
  column.setPreferredWidth(100);

  当用户拖放列的时候,列的索引并不会发生改变。getColumn(0)方法会一直返回正确的列,无论它出现在屏幕的哪个地方。

  标题

  JtableHeader会处理JTable标题的显示。你可以细分JtableHeader以获得自定义的布局。例如,如果你的应用程序需要一个跨越多个列的标题,那么只用简单地细分JtableHeader并将它集成到你的JTable里就行了。

  你可以通过为当前JTable的JtableHeader设置一个参照或者调用其setReorderingAllowed()方法,来指定标题的重新排序是否被允许:


 table.getTableHeader().setReorderingAllowed(false);

  类似地,你可以确信列不会因为在列标题之间拖动而改变大小。要达到这个目的,你就要使用setResizingAllowed()方法:


 table.getTableHeader().setResizingAllowed(false);

  选择模式

  在缺省状况下,当用户在JTable里选择一个单元格的时候,整个行都被选中了。有多种方法能够让用户自定义选择的方式。利用ListSelectionModel接口,你可以允许用户选择单个或者多个行:


 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

  ListSelectionModel有下面这些字段:

  SINGLE_SELECTION允许一次选择一行。

  SINGLE_INTERVAL_SELECTION允许选择相邻的一系列行。

  MULTIPLE_INTERVAL_SELECTION也允许选择相邻的列,但是带有扩展功能。它允许用户使用[Ctrl]键进行多个互不相邻的选择(即选择不相邻的行)。

  setCellSelectionEnabled()方法让用户能够同时选择单个单元格或者整个行:

  table.setCellSelectionEnabled(true);

  如果被设置为是,setCellSelectionEnabled()方法还会允许在选择行和单个单元格的同时选择列,如果图B所示。

  编辑单元格

  我们这个简单的表格允许用户编辑表格里的任何单元格。Listing B列出了一个表格,它允许由程序员来决定哪些单元格能够被编辑。第一步是创建一个自定义的TableModel:


 class SimpleTableModel extends AbstractTableModel {}

  数据被封装在TableModel里,当JTable初始化的时候,自定义的TableModel就被作为一个参数传递给JTable的构造函数而不是那个二维的对象数组:


 SimpleTableModelmyModel = new SimpleTableModel();
  JTable table = new JTable(myModel);

  如果想让第二列和第三列也变得可以编辑,并把第一列变成恒定的,那么你就要强制替代TableModel的isCellEditable()方法:


 public booleanisCellEditable(int row, intcol){
  if (col == 0) {return false;}
  else {return true; }
  }

  简单的表格验证

  你需要确保用户只输入整数值,假如说,向第二列(“盒子的数量”这一列)输入值来强制替代setValueAt()方法,并将验证逻辑包括进这个新方法里。首先,你要检查列是否是整数,以及这个列是否只应该包含整数值:


 if (data[0][col] instanceof Integer && !(value instanceof Integer))
  {… } else { data[row][col] = value;}

  然后,检查被插入的值是否是个整数。如果它不是的,那么这个字段就不应该被更新,而且应该要显示一条错误信息:


 try {
  data[row][col] = new Integer(value.toString());
  } catch (NumberFormatException e) {
  JOptionPane.showMessageDialog(SimpleTable.this,
  "Please enter only integer values.");
  }

  背景颜色

  Listing C包含了用于ColorTable.java的代码,它说明了如何向JTable加入颜色。你可以通过强制替代其prepareRenderer()方法来向JTable加入背景颜色:


 JTable table = new JTable(data, columnNames){
  public Component prepareRenderer(TableCellRenderer r, int row, intcol){}
  };

  然后,插入决定哪些列应该有颜色以及应该是什么颜色的逻辑:


 if (col == 2 && !isCellSelected(row, col)){
  Color bg = new Color(200, 100, 30);
  c.setBackground(bg);
  c.setForeground(Color.white);

  }要注意,当你更改单元格背景颜色的时候,你还应该更该单元格里所显示的文本的颜色,让其变得更加易读。图C显示了一个第一列和第二列加上了颜色的JTable。

  一切皆在掌握中

  我们的例子只是JTable其他部分的基础。通过使用这些工具,你能够快速和轻易地掌控对Java应用程序所生成的表格的格式化,这样就能够让你的用户在进行正常使用的时候不碰到障碍。

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

 


 import java.awt.Dimension;
  import javax.swing.JFrame;
  import javax.swing.JScrollPane;
  import javax.swing.JPanel;
  import javax.swing.JTable;
  import java.awt.Color;
  import java.awt.GridLayout;
  import javax.swing.table.TableColumn;
  public class JTableDemo
  {
  public static void main (String[] args)
  {
  /*
  构造函数有很多下面先介绍几个:
  JTable()
  JTable(int numRows, int numColumns)
  JTable(Object[][] rowData, Object[] columnNames)
  */
  JTable example1 = new JTable ();//看不到但存在
  JTable example2 = new JTable (8, 6);
  final Object[] columnNames = {"姓名", "性别", "家庭地址",//列名最好用final修饰
  "电话号码", "生日", "工作", "收入", "婚姻状况","恋爱状况"};
  Object[][] rowData = {
  {"ddd", "男", "江苏南京", "1378313210", "03/24/1985", "学生", "寄生中", "未婚", "没"},
  {"eee", "女", "江苏南京", "13645181705", "xx/xx/1985", "家教", "未知", "未婚", "好象没"},
  {"fff", "男", "江苏南京", "13585331486", "12/08/1985", "汽车推销员", "不确定", "未婚", "有"},
  {"ggg", "女", "江苏南京", "81513779", "xx/xx/1986", "宾馆服务员", "确定但未知", "未婚", "有"},
  {"hhh", "男", "江苏南京", "13651545936", "xx/xx/1985", "学生", "流放中", "未婚", "无数次分手后没有"}
  };
  JTable friends = new JTable (rowData, columnNames);
  friends.setPreferredScrollableViewportSize(new Dimension(600, 100));//设置表格的大小
  friends.setRowHeight (30);//设置每行的高度为20
  friends.setRowHeight (0, 20);//设置第1行的高度为15
  friends.setRowMargin (5);//设置相邻两行单元格的距离
  friends.setRowSelectionAllowed (true);//设置可否被选择.默认为false
  friends.setSelectionBackground (Color.white);//设置所选择行的背景色
  friends.setSelectionForeground (Color.red);//设置所选择行的前景色
  friends.setGridColor (Color.black);//设置网格线的颜色
  friends.selectAll ();//选择所有行
  friends.setRowSelectionInterval (0,2);//设置初始的选择行,这里是1到3行都处于选择状态
  friends.clearSelection ();//取消选择
  friends.setDragEnabled (false);//不懂这个
  friends.setShowGrid (false);//是否显示网格线
  friends.setShowHorizontalLines (false);//是否显示水平的网格线
  friends.setShowVerticalLines (true);//是否显示垂直的网格线
  friends.setValueAt ("tt", 0, 0);//设置某个单元格的值,这个值是一个对象
  friends.doLayout ();
  friends.setBackground (Color.lightGray);
  JScrollPane pane1 = new JScrollPane (example1);//JTable最好加在JScrollPane上
  JScrollPane pane2 = new JScrollPane (example2);
  JScrollPane pane3 = new JScrollPane (friends);
  JPanel panel = new JPanel (new GridLayout (0, 1));
  panel.setPreferredSize (new Dimension (600,400));
  panel.setBackground (Color.black);
  panel.add (pane1);
  panel.add (pane2);
  panel.add (pane3);
  JFrame frame = new JFrame ("JTableDemo");
  frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
  frame.setContentPane (panel);
  frame.pack();
  frame.show();
  };

  • 60
  • |<
  • <<
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • >>
  • >|