罪魁祸首是在表单里设置的name属性,因为设置了name属性,便要在struts中进行接收相应的值,而action里面是没有这个name值的,所以会出错,但是不影响运行的。
后来把<INPUT class=IbtnEnterCssClass id=IbtnEnter
style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px"
onclick="this.form.submit();" type=image src=/blog_article/"images/user_botton.gif </LI></UL>里的红字去掉就可以了
一、知识点
有时候,你可能有一组共享公共行为的类。在OOP中,它们必须扩展相同的基类或者实现相同的接口。这确实是可以用AOP模块化的一个横切关注点。此外,Java的单继承机制仅允许一个类最多继承一个基类。所以,你不能同时从多个实现类中继承行为。
引入(Introduction)是AOP中一种特殊类型的通知。通过为一个接口提供实现类,它允许对象动态地实现该接口。这看上去就像是对象在运行时继承了实现类。而且,你可以用多个实现类将多个接口同时引入对象。这可以实现与多重继承相同的效果。二、代码示例
MaxCalculator和MinCalculator接口,用于定义max()和min()运算。
package com.codeproject.jackie.springrecipesnote.springaop; /** * @author jackie * */ public interface MaxCalculator { public double max(double a, double b); }
package com.codeproject.jackie.springrecipesnote.springaop; /** * @author jackie * */ public interface MinCalculator { public double min(double a, double b); }相应的实现类
package com.codeproject.jackie.springrecipesnote.springaop; /** * @author jackie * */ public class MaxCalculatorImpl implements MaxCalculator { public double max(double a, double b) { double result = (a >= b) ? a : b; System.out.println("max(" + a + ", " + b + ") = " + result); return result; } }
package com.codeproject.jackie.springrecipesnote.springaop; /** * @author jackie * */ public class MinCalculatorImpl implements MinCalculator { public double min(double a, double b) { double result = (a <= b) ? a : b; System.out.println("min(" + a + ", " + b + ") = " + result); return result; } }如果希望ArithmeticCalculatorlmpl也执行max()和min()计算。由于Java语言仅支持单继承,让 ArithmeticCalculatorlmpl 类同时扩展 MaxCalculatorlmpl 和 MinCalculatorlmpl 是不可能的。唯一可能的方法是通过复制实现代码或者将处理委派给实际的实现类,扩展某个类 (例如MaxCalculatorlmpl)并实现另一个接口(例如MinCalculator)。在两种情况下,你都必须重复方法的声明。
有了引入,通过使用实现类MaxCalculatorlmpl和MinCalculatorlmpl,可以使ArithmeticCalculatorlmpl动态地实现MaxCalculator和MinCalculator接口。这和从 MaxCalculatorlmpl 和 MinCalculatorlmpl多重继承有相同的效果。引入的非凡之处在于不需要修改ArithmeticCalculatorlmpl类引入新的方法。
引入是通过动态代理在Spring AOP中实现这一切的。因为可以为动态代理指定一组需要实现的接口。引入就是通过向动态代理添加一个接口(例 如MaxCalculator)来工作的。当这个接口中声明的方法在代理对象上调用时,代理将把调用委派给后端实现类(例如MaxCalculatorlmpl)。
引入和通知类似,必须在一个aspect中声明。可以创建一个新的aspect或者重用现有的aspect。在下面这个aspect中,可以使用@DeclareParents注解任意一个字段来声明引入。
package com.codeproject.jackie.springrecipesnote.springaop; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * @author jackie * */ @Aspect public class CalculatorIntroduction { @DeclareParents(value = "com.codeproject.jackie.springrecipesnote.springaop.ArithmeticCalculatorlmpl", defaultImpl = MaxCaculatorImpl.class) public MaxCalculator maxCalculator; @DeclareParents(value = "com.codeproject.jackie.springrecipesnote.springaop.ArithmeticCalculatorlmpl", defaultImpl = MinCaculatorImpl.class) public MinCalculator minCalculator; }
@DeclareParents注解的value属性表示引入的目标类。引入的接口由被注解的字段类型确定。最后,用于新接口的实现类在defaultlmpl属性中指定。
通过这两个引入,你可以动态地为ArithmeticCalculatorlmpl类引入两个接口。实际上,可以在@DeclareParents注解的value属性中指定一个AspectJ类型匹配表达式,将一个接口引入多个类。最后需要在应用上下文中声明这个aspect的一个实例。
<bean class="com.codeproject.jackie.springrecipesnote.springaop.CalculatorIntroduction" />测试类
package com.codeproject.jackie.springrecipesnote.springaop; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author jackie * */ public class IntroductionTest { @Test public void testIntroduction() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator)applicationContext.getBean("arithmeticCalculator"); arithmeticCalculator.add(1, 2); arithmeticCalculator.sub(1, 2); arithmeticCalculator.mul(1, 2); arithmeticCalculator.div(1, 2); MaxCalculator maxCalculator = (MaxCalculator) arithmeticCalculator; maxCalculator.max(1, 2); MinCalculator minCalculator = (MinCalculator) arithmeticCalculator; minCalculator.min(1, 2); } }
一、知识点
有时候,你可能希望为一组现有的对象添加新的状态,跟踪它们的使用情况,如调用次数、最后修改日期等。如果所有对象都有相同的基类,这就不成问题。但是,如果不同的类不在相同的类层次结构中,添加这样的状态就很难。
可以为对象引入一个新的接口,它有一个带有状态字段的实现类。然后,编写另一个通知来根据特定的条件改变状态。
二、代码示例 假定你希望跟踪每个计算器对象的调用次数。由于在原来的计算器类当中没有保存计数器的字段,你需要使用Spring AOP引入一个。首先,为计算器的操作创建一个接口。
package com.codeproject.jackie.springrecipesnote.springaop; /** * @author jackie * */ public interface Counter { public void increase(); public int getCount(); }实现类Counterlmpl
package com.codeproject.jackie.springrecipesnote.springaop; public class CounterImpl implements Counter { // 存储计数器值 private int count; @Override public void increase() { count++; } @Override public int getCount() { return count; } }为了将以Counterlmpl为实现的Counter接口引入所有的计算器对象,可以编写如下的带有一个匹配所有计算器实现的类型匹配表达式的引入。
package com.codeproject.jackie.springrecipesnote.springaop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * @author jackie * */ @Aspect public class CalculatorIntroduction { @DeclareParents(value = "com.codeproject.jackie.springrecipesnote.springaop.*CalculatorImpl", defaultImpl = CounterImpl.class) public Counter counter; }这个引入为每个计算器类引入Counterlmpl。但是,它仍然不能够跟踪调用次数。必须在每次调用一个计算器方法时增加计数器值。为此,可以编写一个最终(After)通知。注意,必须取得this对象,而不是target对象,因为只有代理对象实现了Counter接口。
package com.codeproject.jackie.springrecipesnote.springaop; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; /** * @author jackie * */ @Aspect public class CalculatorIntroduction { 。。。。。 @After("execution(* com.codeproject.jackie.springrecipesnote.springaop.*Calculator.*(..)) && this(counter)") public void increaseCount(Counter counter) { counter.increase(); } }测试类如下
package com.codeproject.jackie.springrecipesnote.springaop; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author jackie * */ public class IntroduceStateTest { @Test public void testIntroduceState() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator)applicationContext.getBean("arithmeticCalculator"); arithmeticCalculator.add(1, 2); arithmeticCalculator.sub(1, 2); arithmeticCalculator.mul(1, 2); arithmeticCalculator.div(1, 2); UnitCalculator unitCalculator = (UnitCalculator) applicationContext.getBean("unitCalculator"); unitCalculator.kilogramToPound(100); unitCalculator.kilometerToMile(100); Counter arithmeticCounter = (Counter) arithmeticCalculator; System.out.println(arithmeticCounter.getCount()); Counter unitCounter = (Counter) unitCalculator; System.out.println(unitCounter.getCount()); } }