随笔 - 9, 文章 - 0, 评论 - 3, 引用 - 0
数据加载中……

2007年11月7日

初探spring applicationContext在web容器中加载过程

     摘要: 转载自www.javaworld.com.tw 袁杰 原文 首先从WEB.XML入手 ==>web.xml 1 2 3 4 5 6 ...  阅读全文

posted @ 2007-11-07 15:06 空杯 阅读(10729) | 评论 (1)编辑 收藏

2007年10月29日

JUnit 4 抢先看

from: http://www.ibm.com/developerworks/cn/java/j-junit4.html

JUnit 由 Kent Beck 和 Erich Gamma 开发,几乎毫无疑问是迄今所开发的最重要的第三方 Java 库。正如 Martin Fowler 所说,“在软件开发领域,从来就没有如此少的代码起到了如此重要的作用”。JUnit 引导并促进了测试的盛行。由于 JUnit,Java 代码变得更健壮,更可靠,bug 也比以前更少。JUnit(它本身的灵感来自 Smalltalk 的 SUnit)衍生了许多 xUnit 工具,将单元测试的优势应用于各种语言。nUnit (.NET)、pyUnit (Python)、CppUnit (C++)、dUnit (Delphi) 以及其他工具,影响了各种平台和语言上的程序员的测试工作。

然而,JUnit 仅仅是一个工具而已。真正的优势来自于 JUnit 所采用的思想和技术,而不是框架本身。单元测试、测试先行的编程和测试驱动的开发并非都要在 JUnit 中实现,任何比较 GUI 的编程都必须用 Swing 来完成。JUnit 本身的最后一次更新差不多是三年以前了。尽管它被证明比大多数框架更健壮、更持久,但是也发现了 bug;而更重要的是,Java 不断在发展。Java 语言现在支持泛型、枚举、可变长度参数列表和注释,这些特性为可重用的框架设计带来了新的可能。

JUnit 的停滞不前并没有被那些想要废弃它的程序员所打败。挑战者包括 Bill Venners 的 Artima SuiteRunner 以及 Cedric Beust 的 TestNG 等。这些库有一些可圈可点的特性,但是都没有达到 JUnit 的知名度和市场占有份额。它们都没有在诸如 Ant、Maven 或 Eclipse 之类的产品中具有广泛的开箱即用支持。所以 Beck 和 Gamma 着手开发了一个新版本的 JUnit,它利用 Java 5 的新特性(尤其是注释)的优势,使得单元测试比起用最初的 JUnit 来说更加简单。用 Beck 的话来说,“JUnit 4 的主题是通过进一步简化 JUnit,鼓励更多的开发人员编写更多的测试。”JUnit 4 尽管保持了与现有 JUnit 3.8 测试套件的向后兼容,但是它仍然承诺是自 JUnit 1.0 以来 Java 单元测试方面最重大的改进。

注意:该框架的改进是相当前沿的。尽管 JUnit 4 的大轮廓很清晰,但是其细节仍然可以改变。这意味着本文是对 JUnit 4 抢先看,而不是它的最终效果。

测试方法

以前所有版本的 JUnit 都使用命名约定和反射来定位测试。例如,下面的代码测试 1+1 等于 2:

import junit.framework.TestCase;
            public class AdditionTest extends TestCase {
            private int x = 1;
            private int y = 1;
            public void testAddition() {
            int z = x + y;
            assertEquals(2, z);
            }
            }

而在 JUnit 4 中,测试是由 @Test 注释来识别的,如下所示:

import org.junit.Test;
            import junit.framework.TestCase;
            public class AdditionTest extends TestCase {
            private int x = 1;
            private int y = 1;
            @Test public void testAddition() {
            int z = x + y;
            assertEquals(2, z);
            }
            }

使用注释的优点是不再需要将所有的方法命名为 testFoo()testBar(),等等。例如,下面的方法也可以工作:

import org.junit.Test;
            import junit.framework.TestCase;
            public class AdditionTest extends TestCase {
            private int x = 1;
            private int y = 1;
            @Test public void additionTest() {
            int z = x + y;
            assertEquals(2, z);
            }
            }

下面这个方法也同样能够工作:

import org.junit.Test;
            import junit.framework.TestCase;
            public class AdditionTest extends TestCase {
            private int x = 1;
            private int y = 1;
            @Test public void addition() {
            int z = x + y;
            assertEquals(2, z);
            }
            }

这允许您遵循最适合您的应用程序的命名约定。例如,我介绍的一些例子采用的约定是,测试类对其测试方法使用与被测试的类相同的名称。例如,List.contains()ListTest.contains() 测试,List.add()ListTest.addAll() 测试,等等。

TestCase 类仍然可以工作,但是您不再需要扩展它了。只要您用 @Test 来注释测试方法,就可以将测试方法放到任何类中。但是您需要导入 junit.Assert 类以访问各种 assert 方法,如下所示:

import org.junit.Assert;
            public class AdditionTest {
            private int x = 1;
            private int y = 1;
            @Test public void addition() {
            int z = x + y;
            Assert.assertEquals(2, z);
            }
            }

您也可以使用 JDK 5 中新特性(static import),使得与以前版本一样简单:

import static org.junit.Assert.assertEquals;
            public class AdditionTest {
            private int x = 1;
            private int y = 1;
            @Test public void addition() {
            int z = x + y;
            assertEquals(2, z);
            }
            }

这种方法使得测试受保护的方法非常容易,因为测试案例类现在可以扩展包含受保护方法的类了。





回页首


SetUp 和 TearDown

JUnit 3 测试运行程序(test runner)会在运行每个测试之前自动调用 setUp() 方法。该方法一般会初始化字段,打开日志记录,重置环境变量,等等。例如,下面是摘自 XOM 的 XSLTransformTest 中的 setUp() 方法:

protected void setUp() {
            System.setErr(new PrintStream(new ByteArrayOutputStream()));
            inputDir = new File("data");
            inputDir = new File(inputDir, "xslt");
            inputDir = new File(inputDir, "input");
            }

在 JUnit 4 中,您仍然可以在每个测试方法运行之前初始化字段和配置环境。然而,完成这些操作的方法不再需要叫做 setUp(),只要用 @Before 注释来指示即可,如下所示:

@Before protected void initialize() {
            System.setErr(new PrintStream(new ByteArrayOutputStream()));
            inputDir = new File("data");
            inputDir = new File(inputDir, "xslt");
            inputDir = new File(inputDir, "input");
            }

甚至可以用 @Before 来注释多个方法,这些方法都在每个测试之前运行:

@Before protected void findTestDataDirectory() {
            inputDir = new File("data");
            inputDir = new File(inputDir, "xslt");
            inputDir = new File(inputDir, "input");
            }
            @Before protected void redirectStderr() {
            System.setErr(new PrintStream(new ByteArrayOutputStream()));
            }

清除方法与此类似。在 JUnit 3 中,您使用 tearDown() 方法,该方法类似于我在 XOM 中为消耗大量内存的测试所使用的方法:

protected void tearDown() {
            doc = null;
            System.gc();
            } 

对于 JUnit 4,我可以给它取一个更自然的名称,并用 @After 注释它:

@After protected void disposeDocument() {
            doc = null;
            System.gc();
            } 

@Before 一样,也可以用 @After 来注释多个清除方法,这些方法都在每个测试之后运行。

最后,您不再需要在超类中显式调用初始化和清除方法,只要它们不被覆盖即可,测试运行程序将根据需要自动为您调用这些方法。超类中的 @Before 方法在子类中的 @Before 方法之前被调用(这反映了构造函数调用的顺序)。@After 方法以反方向运行:子类中的方法在超类中的方法之前被调用。否则,多个 @Before@After 方法的相对顺序就得不到保证。

套件范围的初始化

JUnit 4 也引入了一个 JUnit 3 中没有的新特性:类范围的 setUp()tearDown() 方法。任何用 @BeforeClass 注释的方法都将在该类中的测试方法运行之前刚好运行一次,而任何用 @AfterClass 注释的方法都将在该类中的所有测试都运行之后刚好运行一次。

例如,假设类中的每个测试都使用一个数据库连接、一个网络连接、一个非常大的数据结构,或者还有一些对于初始化和事情安排来说比较昂贵的其他资源。不要在每个测试之前都重新创建它,您可以创建它一次,并还原它一次。该方法将使得有些测试案例运行起来快得多。例如,当我测试调用第三方库的代码中的错误处理时,我通常喜欢在测试开始之前重定向 System.err,以便输出不被预期的错误消息打乱。然后我在测试结束后还原它,如下所示:

// This class tests a lot of error conditions, which
            // Xalan annoyingly logs to System.err. This hides System.err
            // before each test and restores it after each test.
            private PrintStream systemErr;
            @BeforeClass protected void redirectStderr() {
            systemErr = System.err; // Hold on to the original value
            System.setErr(new PrintStream(new ByteArrayOutputStream()));
            }
            @AfterClass protected void tearDown() {
            // restore the original value
            System.setErr(systemErr);
            }

没有必要在每个测试之前和之后都这样做。但是一定要小心对待这个特性。它有可能会违反测试的独立性,并引入非预期的混乱。如果一个测试在某种程度上改变了 @BeforeClass 所初始化的一个对象,那么它有可能会影响其他测试的结果。它有可能在测试套件中引入顺序依赖,并隐藏 bug。与任何优化一样,只在剖析和基准测试证明您具有实际的问题之后才实现这一点。这就是说,我看到了不止一个测试套件运行时间如此之长,以至不能像它所需要的那样经常运行,尤其是那些需要建立很多网络和数据库连接的测试。(例如,LimeWire 测试套件运行时间超过两小时。)要加快这些测试套件,以便程序员可以更加经常地运行它们,您可以做的就是减少 bug。





回页首


测试异常

异常测试是 JUnit 4 中的最大改进。旧式的异常测试是在抛出异常的代码中放入 try 块,然后在 try 块的末尾加入一个 fail() 语句。例如,该方法测试被零除抛出一个 ArithmeticException

public void testDivisionByZero() {
            try {
            int n = 2 / 0;
            fail("Divided by zero!");
            }
            catch (ArithmeticException success) {
            assertNotNull(success.getMessage());
            }
            }

该方法不仅难看,而且试图挑战代码覆盖工具,因为不管测试是通过还是失败,总有一些代码不被执行。在 JUnit 4 中,您现在可以编写抛出异常的代码,并使用注释来声明该异常是预期的:

@Test(expected=ArithmeticException.class)
            public void divideByZero() {
            int n = 2 / 0;
            }

如果该异常没有抛出(或者抛出了一个不同的异常),那么测试就将失败。但是如果您想要测试异常的详细消息或其他属性,则仍然需要使用旧式的 try-catch 样式。





回页首


被忽略的测试

也许您有一个测试运行的时间非常地长。不是说这个测试应该运行得更快,而是说它所做的工作从根本上比较复杂或缓慢。需要访问远程网络服务器的测试通常都属于这一类。如果您不在做可能会中断该类测试的事情,那么您可能想要跳过运行时间长的测试方法,以缩短编译-测试-调试周期。或者也许是一个因为超出您的控制范围的原因而失败的测试。例如,W3C XInclude 测试套件测试 Java 还不支持的一些 Unicode 编码的自动识别。不必老是被迫盯住那些红色波浪线,这类测试可以被注释为 @Ignore,如下所示:

// Java doesn't yet support
            // the UTF-32BE and UTF32LE encodings
            @Ignore public void testUTF32BE()
            throws ParsingException, IOException, XIncludeException {
            File input = new File(
            "data/xinclude/input/UTF32BE.xml"
            );
            Document doc = builder.build(input);
            Document result = XIncluder.resolve(doc);
            Document expectedResult = builder.build(
            new File(outputDir, "UTF32BE.xml")
            );
            assertEquals(expectedResult, result);
            }

测试运行程序将不运行这些测试,但是它会指出这些测试被跳过了。例如,当使用文本界面时,会输出一个“I”(代表 ignore),而不是为通过的测试输出所经历的时间,也不是为失败的测试输出“E”:

$ java -classpath .:junit.jar org.junit.runner.JUnitCore
            nu.xom.tests.XIncludeTest
            JUnit version 4.0rc1
            .....I..
            Time: 1.149
            OK (7 tests)

但是一定要小心。最初编写这些测试可能有一定的原因。如果永远忽略这些测试,那么它们期望测试的代码可能会中断,并且这样的中断可能不能被检测到。忽略测试只是一个权宜之计,不是任何问题的真正解决方案。





回页首


时间测试

测试性能是单元测试最为痛苦的方面之一。JUnit 4 没有完全解决这个问题,但是它对这个问题有所帮助。测试可以用一个超时参数来注释。如果测试运行的时间超过指定的毫秒数,则测试失败。例如,如果测试花费超过半秒时间去查找以前设置的一个文档中的所有元素,那么该测试失败:

@Test(timeout=500) public void retrieveAllElementsInDocument() {
            doc.query("//*");
            } 

除了简单的基准测试之外,时间测试也对网络测试很有用。在一个测试试图连接到的远程主机或数据库宕机或变慢时,您可以忽略该测试,以便不阻塞所有其他的测试。好的测试套件执行得足够快,以至程序员可以在每个测试发生重大变化之后运行这些测试,有可能一天运行几十次。设置一个超时使得这一点更加可行。例如,如果解析 http://www.ibiblio.org/xml 花费了超过 2 秒,那么下面的测试就会超时:

@Test(timeout=2000)
            public void remoteBaseRelativeResolutionWithDirectory()
            throws IOException, ParsingException {
            builder.build("http://www.ibiblio.org/xml");
            } 





回页首


新的断言

JUnit 4 为比较数组添加了两个 assert() 方法:

public static void assertEquals(Object[] expected, Object[] actual)
            public static void assertEquals(String message, Object[] expected,
            Object[] actual)
            

这两个方法以最直接的方式比较数组:如果数组长度相同,且每个对应的元素相同,则两个数组相等,否则不相等。数组为空的情况也作了考虑。





回页首


需要补充的地方

JUnit 4 基本上是一个新框架,而不是旧框架的升级版本。JUnit 3 开发人员可能会找到一些原来没有的特性。

最明显的删节就是 GUI 测试运行程序。如果您想在测试通过时看到赏心悦目的绿色波浪线,或者在测试失败时看到令人焦虑的红色波浪线,那么您需要一个具有集成 JUnit 支持的 IDE,比如 Eclipse。不管是 Swing 还是 AWT 测试运行程序都不会被升级或捆绑到 JUnit 4 中。

下一个惊喜是,失败(assert 方法检测到的预期的错误)与错误(异常指出的非预期的错误)之间不再有任何差别。尽管 JUnit 3 测试运行程序仍然可以区别这些情况,而 JUnit 4 运行程序将不再能够区分。

最后,JUnit 4 没有 suite() 方法,这些方法用于从多个测试类构建一个测试套件。相反,可变长参数列表用于允许将不确定数量的测试传递给测试运行程序。

我对消除了 GUI 测试运行程序并不感到太高兴,但是其他更改似乎有可能增加 JUnit 的简单性。只要考虑有多少文档和 FAQ 当前专门用于解释这几点,然后考虑对于 JUnit 4,您不再需要解释这几点了。





回页首


编译和运行 JUnit 4

当前,还没有 JUnit 4 的库版本。如果您想要体验新的版本,那么您需要从 SourceForge 上的 CVS 知识库获取它。分支(branch)是“Version4”(参见 参考资料)。注意,很多的文档没有升级,仍然是指以旧式的 3.x 方式做事。Java 5 对于编译 JUnit 4 是必需的,因为 JUnit 4 大量用到注释、泛型以及 Java 5 语言级的其他特性。

自 JUnit 3 以来,从命令行运行测试的语法发生了一点变化。您现在使用 org.junit.runner.JUnitCore 类:

$ java -classpath .:junit.jar org.junit.runner.JUnitCore
            TestA TestB TestC...
            JUnit version 4.0rc1
            Time: 0.003
            OK (0 tests)

兼容性

Beck 和 Gamma 努力维持向前和向后兼容。JUnit 4 测试运行程序可以运行 JUnit 3 测试,不用做任何更改。只要将您想要运行的每个测试的全限定类名传递给测试运行程序,就像针对 JUnit 4 测试一样。运行程序足够智能,可以分辨出哪个测试类依赖于哪个版本的 JUnit,并适当地调用它。

向后兼容要困难一些,但是也可以在 JUnit 3 测试运行程序中运行 JUnit 4 测试。这一点很重要,所以诸如 Eclipse 之类具有集成 JUnit 支持的工具可以处理 JUnit 4,而不需要更新。为了使 JUnit 4 测试可以运行在 JUnit 3 环境中,可以将它们包装在 JUnit4TestAdapter 中。将下面的方法添加到您的 JUnit 4 测试类中应该就足够了:

public static junit.framework.Test suite() {
            return new JUnit4TestAdapter(AssertionTest.class);
            }

但是由于 Java 比较多变,所以 JUnit 4 一点都不向后兼容。JUnit 4 完全依赖于 Java 5 特性。对于 Java 1.4 或更早版本,它将不会编译或运行。





回页首


前景

JUnit 4 远没有结束。很多重要的方面没有提及,包括大部分的文档。我不推荐现在就将您的测试套件转换成注释和 JUnit 4。即使如此,开发仍在快速进行,并且 JUnit 4 前景非常看好。尽管 Java 2 程序员在可预见的未来仍然需要使用 JUnit 3.8,但是那些已经转移到 Java 5 的程序员则应该很快考虑使他们的测试套件适合于这个新的框架,以便匹配。

posted @ 2007-10-29 16:09 空杯 阅读(295) | 评论 (0)编辑 收藏

Spring 与Hibernate的延迟加载和Dao模式

     摘要: Hibernate 与延迟加载: Hibernate 对象关系映射提供延迟的与非延迟的对象初始化。非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来。这有时会导致成百的(如果不是成千的话) select 语句在读取对象的时候执行。这个问题有时出现在使用双向关系的时候,经常会导致整个数据库都在初始化的阶段被读出来了。当然,你可以不厌其烦地检查每一个对象与其他对象的关系...  阅读全文

posted @ 2007-10-29 16:07 空杯 阅读(806) | 评论 (1)编辑 收藏

Hibernate的检索方式

 

Hibernate的检索方式Hibernate的检索方式:
 1.导航对象图检索方式
    根据已经加载的对象,导航到其他对象.
 2.OID检索方式
    按照对象的OID来检索对象
 3.HQL检索方式
    使用面向对象的HQL查询语言.
 4.QBC检索方式
    使用QBC API来检索对象,这种API封装了基于字符串形式的查询语句,提供了更加面向对象的接口.
    它主要由Criteria接口,Criterion接口和Expression类组合,它支持在运行时动态生成的查询语句:
    以下程序代码用于检索姓名以字符"T"开头,并且年龄为21的Customer对象:
      ///调用Session的createCriteria()方法创建一个Criteria对象
      Creteria criteria=session.createCriteria(Customer.class);
      //设置查询条件,Expression类提供了一系列用于设定查询条件的静态方法,这些静态方法都
       返回Criterion实例,每个Criterion实例代表一个查询条件
      Criterion criterion1=Expression.like("name","T%");
      Criterion criterion2=Expression.eq("age",new Integer(21));
      ////Criteria的add()方法用于加入查询条件.
      criteria=criteria.add(criterion1);
      criteria=criteria.add(criterion2);
      /////调用Criteria的list()方法执行查询语句,该方法返回List类型的查询结果,在List集合中存放
        了符合查询条件的持久化对象
      List result=criteria.list();
      对于以上代码执行的SQL语句为:select * from CUSTOMERS where NAME like"T%" and AGE=21;
      Criteria接口支持方法链编程风格,它的add()方法返回自身实例,而不是返回void类型
 5.本地SQL检索方式:
 6.QBE检索方式:
   它是QBC的子功能,QBE允许先创建一个对象样板,然后检索出所有和这个样板相同的对象.如下:
    //创建一个CUstomer样板对象
      Customer exampleCustomer=new Customer();
      exampleCustoemr.setAge(21);
      List result=session.createCriteria(Custoemr.class).add(Example.create(exampleCustomer)).list();
    因为QBE只支持"="和"like"比较运算符,所以一般采用HQL检索方式或者QBC检索方式.

分页查询:
  Query和Criteria接口都提供了用于分页显示查询结果的方法:
   setFirstResult(int firstResult):设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0,
   在默认情况下,Query和Criteria接口从查询结果中的第一个对象,也就是索引位置为0的对象开始检索.
  setMaxResult(int maxResults):设定一次最多检索出的对象数目,在默认情况下,Query和Criteria接口检索出查询接口中所有的对象

检查单个对象:
 Query和Criteria接口都提供了以下用于执行查询语句并返回查询结果的方法:
list()方法:返回一个List类型的查询结果,在List集合中存放了所有满足查询条件的持久化对象
 uniqueResult()方法:返回单个对象.
 在某些情况下,如果只希望检索出一个对象,可以先调用Query或Criteria接口的setMaxResult(1)方法,把最大检索数目设为1,然后调用uniqueResult()方法,
 该方法返回一个Object类型的对象.
 // 采用HQL检索方式
 Customer customer=(Customer)session.createQuery("from Customer c order by c.name asc").setMaxResults(1).uniqueResult();
 //采用QBC检索方式
 Customer customer=(Customer)session.createCriteria(Customer.class).add(Order.asc("name")).setMaxResults(1).uniqueResult();

posted @ 2007-10-29 16:04 空杯 阅读(1011) | 评论 (0)编辑 收藏

MiddlegenIDE的使用

最近有朋友发信,说MiddlegenIDE的主页出了点状况,登陆上去显示的内容莫名其妙,给新手使用MiddlegenIDE带来了困难。本座去看了一下,果然是莫名其妙得厉害。下面总结一个MiddlegenIDE的使用教程吧。

MiddleGen for Hibernate加上Hibernate_Extension工具包,其实就是用来方便我们从先有的数据库导出表结构,生成对应的hbm、cfg文件与POJO类代码。MiddleGenIDE则是MiddleGen的Eclipse插件。整套东西已经有很久没有更新过了。所以虽然本座现在用的eclipse版本3.1.x也能与这个插件正常配合,但是它没有提供在线update的功能。需要你先下载middlegenide,安装插件之后重启Eclipse。如果新开启的eclipse没有变化,估计你得用"- clean"参数再重启一下,或者去删除configuration文件夹下面对应的文件。

OK,下面讲讲怎么去用。首先当然要搭建一个环境(我现在把MySQL更新到了5.0,Hibernate和当时一样是2.1),然后我们建一个表,装一点数据。MySQL下面建表的脚本如下:
1
2
3
4
5
6
DROP TABLE IF EXISTS `test`.`t_user`;
          CREATE TABLE  `test`.`t_user` (
          `id` int(11) NOT NULL auto_increment,
          `name` varchar(255) default NULL,
          PRIMARY KEY  (`id`)
         ) ENGINE=InnoDB DEFAULT CHARSET=gbk;


有了表之后,建立一个Java工程。然后在Src文件夹上面右键,选择“New-Other”



然后会弹出Middelgen Biuld File的选项。因为MiddleGen是一个使用Ant编译文件来调出IDE的包,所以这个插件实际上就是方便我们用完型填空的方式来编写这个Biuld File而已。



点击后出现下面的界面,对应的内容一目了然,按照自己的需要填写即可。



下面这张图是填好后的样子。和本座一样没有使用Hibernate 3的朋友,注意在画了红圈的Option选项中把hibernate的版本调低。不然生产的配置文件,会有一个非常诡异的"xml parser无法解析dtd"的错误。



填好所有的东西就点击Next进入MiddleGen界面,几乎不用改任何东西直接点击Generate就能得到配置文件和POJO类了。



另外,如果你需要在MiddleGen中生成的POJO直接带Xdoclet的标记的话,需要在找到它自带的模板文件:
1
eclipse\plugins\org.ultimania.middlegenide_1.3.2\resource\template\build-hibernate.xml.vm


然后把下面这行生成xdoclet tag的值改成true:
1
<property name="gen.xdoclet-tag"      value="true">

posted @ 2007-10-29 16:03 空杯 阅读(2066) | 评论 (0)编辑 收藏

Open Session in Test 及自动Rollback

from: http://www.blogjava.net/rain1102/articles/117541.html

又是来自Spring这个神奇国度的东西, 你可以让testCase继承于AbstractTransactionalDataSourceSpringContextTests,就可以做到Open Session in Test ,解决Hibernate的lazy-load问题;而且接管原来的DAO里的事务控制定义,通过setDefaultRollback(boolean)方法控制最后回滚还是提交,如果默认为回滚,则测试产生数据变动不会影响数据库内数据。
 
如果不能继承于这个基类,可以自己简单编写,代码是这样的:
   protected PlatformTransactionManager transactionManager;
   protected TransactionStatus transactionStatus;
   protected boolean defaultRollback = true;
   public void setUp()
   {
        transactionManager = (PlatformTransactionManager) ctx.getBean("transactionManager");
        transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
   }
   public void tearDown()
   {
        if (defaultRollback)
            transactionManager.rollback(this.transactionStatus);
        else
           transactionManager.commit(this.transactionStatus);
    }
(注,hibernate太奸诈了,如果全部默认回滚,只会在session里干活,一点不写数据库,达不到完全的测试效果。)

posted @ 2007-10-29 16:00 空杯 阅读(277) | 评论 (0)编辑 收藏

ServletConfig与ServletContext的区别

from: http://www.blogjava.net/software5168/archive/2006/09/05/67752.html

HttpServletRequest,HttpServletResponse:这两个属性的作用范围最小。
    时间上:只是本身请求和应答完成就失效,当然转发是把当前的request对象取出来传给另一
          个资源,其实本身的request对象还是只生存到本次请求结束,response也同样。
    空间上:只能发送请求的客户端有效。

    HttpSession:一次连结到客户端关闭,时间作用范围比上面两个大,空间任用范围相同。

    ServletConfig:从一个servlet被实例化后,对任何客户端在任何时候访问有效,但仅对本servlet
    有效,一个servlet的ServletConfig对象不能被另一个servlet访问。

    ServletContext:对任何servlet,任何人在任何时间都有效,这才是真正全局的对象。

    那么,ServletConfig参数和ServletContext参数到底应该如何使用,如何取得?

    一般来说,对整个应用的配置,为了不使用“硬编码”,应该配置为ServletContext参数,比如字
    符集设定。
    <web-app>
        .................
        <init-param>
            <param-name>charset</param-name> 
            <param-value>GB2312</param-value> 
        </init-param>
        .................
    </web-app>
    注意以上格式只是2。0以后的标准格式,旧容器(引擎)采用服务商自己的格式配置。注意它的
    父元素应该是<web-app>也就是说它是对一个应用作用的。

    而如果只有一个特定的servlet要设定的参数,其它servlet不能共享,应该配置为ServletConfig
    参数,如一个读取附件的servlet要用到绝对目录,而别的servlet不会用到:
    <servlet>
            <servlet-name>GetAtt</servlet-name>
        <servlet-class>mail.GetAttServlet</servlet-class>
        <init-param>
            <param-name>absPath</param-name> 
            <param-value>/usr/mail/ax/axman/Maildir/</param-value> 
        </init-param>
    </servlet>
    不用说,因为在<servlet>标签中已经指定了name和class,也就是说只有mail.GetAttServlet这个
    servlet中才能取到path,而别的Servlet是不能取到的。

    那么如何访问这两个对象的参数呢?
    访问ServletConfig参数:
        首先要取得ServletConfig对象,然后调用它的getInitParameter();方法。要访问
    ServletConfig对象,jsp中直接使用config内置对象,但因为你的JSP编译后的servlet一般不会被
    加到web.xml中的,所以一般不会通过jsp来取对本JSP编译后的servlet的配置参数,那么在servlet
    中要得到ServletConfig对象有两种方法:

    在inii()方法中取到:通过init的重载方法传递

    .....
    public class Test extends HttpServlet 
    {
        ServletConfig config;
        public void init(ServletConfig config) throws ServletException {
            this.config = config;
        }
        ..................
    }
    然后在下面的方法中就可以访问config对象。但要注意,为了确保能从构造方法中到到当前servlet的
    config对象,应该调用父类的构造方法:
    .....
    public class Test extends HttpServlet 
    {
        ServletConfig config;
        public void init(ServletConfig config) throws ServletException {
            super.init(config);
            this.config = config;
        }
        ..................
    }

    通过getServletConfig()方法直接到时,这样做的好处是不必调手工传递属性,想在任何时候都可
    以得到。

    还有第三种方法,要自己实现一些接口,这里作为一般讨论就不介绍了。

    要访问ServletContext对象,只要从现有的ServletConfig对象getServletContext()就可以了,然后
    调用它的getInitParameter()方法就可以获取它的参数。

    按说:ServletContext对象的作用域比ServletConfig作用域大,为什么要从ServletConfig中到得
    ServletContext对象呢?我个人认为:容器保存了很多个ServletContext对象,请求时容器到底取哪一个
    给你呢?那就取其中包含ServletConfig信息的那个给你,就是说取ServletConfig对象的父级对象。就好
    象HttpSession要从requset中取得一样,就是取那个包含当前requese对象的session对象给你,这只是我
    的个人想法,还没有来得及看具体实现。反正就这么用吧。

posted @ 2007-10-29 15:59 空杯 阅读(2708) | 评论 (0)编辑 收藏

Struts 1.2 的 HTML 标签嵌套属性(如user.name)如何加入 JavaScript 表单验证

 

Struts 里面的 之类的表单域标签, 都有一个属性叫: property, 这个属性根据文档是可以嵌套的, 例如下面的 formBean 嵌套了一个属性 User:

public class User {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}

 

public class UserForm extends FormBean {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

 

那么对应的 JSP 页面里的  Tag 可以写成:

<html:text property="user.username" />

但是如果这时候有人还想给生成的表单加入 JavaScript 验证的话, 必须用下面的写法才能通过:

这是因为 Struts 标签最后产生的 HTML 如下所示:

 

<form onsubmit="return validateForm(this);">
<input name="user.username" />
form>

 

直接引用 元素.user.username 肯定会出错的. 正确的方法参考上上面的代码段即可.

posted @ 2007-10-29 15:57 空杯 阅读(1052) | 评论 (1)编辑 收藏

FormBean 与 POJO 的集成

 
代码
<form-bean name="loginForm" type="org.apache.struts.validator.DynaValidatorForm">

<form-property name="user" type="org.layout.model.User"/>

</form-bean>

在校验文件validation.xml中:

代码
<form name="loginForm">
<field property="user.name" depends="required,minlength,maxlength">
<arg0 key="label.username"/>
<arg1 key="${var:minlength}" name="minlength" resource="false"/>
<arg2 key="${var:maxlength}" name="maxlength" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>2</var-value>
</var>
</field>
<field property="user.password" 
depends
="required,minlength,maxlength">
<arg0 key="label.password"/>
<arg1 key="${var:minlength}" name="minlength" resource="false"/>
<arg2 key="${var:maxlength}" name="maxlength" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>2</var-value>
</var>
</field>
</form>
在action中如下调用:
代码
        DynaActionForm aForm = (DynaActionForm)form;
        ActionMessages messages 
= form.validate(mapping, request);
        
if(!messages.isEmpty())
        
{
            saveMessages(request, messages);
            
return mapping.findForward("prompt");
        }

        User user 
= (User)aForm.get("user");
        UserDAO userDAO 
= (UserDAO)getWebApplicationContext().getBean("userDAO");
        user 
= userDAO.get(user.getName(), user.getPassword());
其实这样子的集成感觉很不错的,除了少了dto和转换(至少你要用一个copyProperty吧),pojo实现了序列化,
甚至可以直接深入到Hibernate底层,这样子就省缺了以前一直讨论formbean和po是不是合并或者在哪个层面上进
行转换。

posted @ 2007-10-29 15:54 空杯 阅读(319) | 评论 (0)编辑 收藏