本程序是关于"某考试系统"中的aop应用.说实话,aop在spring应该算是个难点,它主是起到了"代理"的作 用,aop会为你调用的方法的对象生成代理,这个代理是继承调用 MethodInterceptor这个拦截器的对象的,所以,具备原有对象的所有方法与特性.AOP不神秘,它就是EJB的进化,只是EJB需要显式的实现接 口,而AOP不用,它会自动帮你生成代理,来做很多事情,AOP,我觉得它在处理事务 的时候用的比较多所谓声明式的事务就是由此而来. 当系统管理员进行后台管理或考生前台进行考试时,提交的请求都交给系统的控制器处理.例如在struts- config.xml文件中并未配置Action的实现类,仅仅配置了每个Action的url以及对应的局部forward映射. 所有的Action都交给Spring容器进行管理,用户请求发送到ActionServlet 后,ActionServlet将请求转发到Spring容器里的控制器.Spring的AOP 魔法发生在这个地方,当ActionServlet将请求发送到控制器时,并不是转给程序员实现的控制器,而是转给了控制器代理 -------------控制器代理会先执行权限检查,如果用户已经登录,回调程序员实现的控制器,否则直接进入登录页面. 部分源代码如下 public class AuthorityInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { HttpServletRequest request = null; ActionMapping mapping = null; Object[] args = invocation.getArguments(); for (int i = 0 ; i < args.length ; i++ ) { if (args[i] instanceof HttpServletRequest) request = (HttpServletRequest)args[i]; if (args[i] instanceof ActionMapping) mapping = (ActionMapping)args[i]; } Object admin = request.getSession().getAttribute("admin"); if ( admin != null && ((String)admin).equals("admin")) { return invocation.proceed(); } else { request.setAttribute("msg" , "您还没有登录,请先登录"); return mapping.findForward("admin"); } } } 该应用是在*.xml中来调用的..(用struts的mvc,然后托管给spring的ioc容器来管理的,配置也是由spring来处理的) <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>/processAddStudent</value> <value>/listStudent</value> <value>/delStudent</value> <value>/processAddTest</value> <value>/addQuestion</value> <value>/delQuestion</value> <value>/processAddQuestion</value> </list> </property> <property name="interceptorNames"> <list> <value>authorityInterceptor</value> </list> </property> </bean> <bean id="authorityInterceptor" class="org.yeeku.action.authority.AuthorityInterceptor"/> //解释后的代码 public class AuthorityInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { HttpServletRequest request = null; ActionMapping mapping = null; -----------注解1开始 通过invocation.getArguments()可以获取代理对象的参数 代理的参数是ActionMapping, ActionForm ,HttpServletRequest , HttpServletResponse 四个 只不过,这里根据实际情况,我们只需要使用HttpServletRequest,ActionMapping罢了 因为这里你要通过request获取session和通过mapping跳转页面 因为 Object[] args = invocation.getArguments(); 规定,返回的必须是一个数组 所以,没办法,只能迭代把要用的找出来 而我们在XML配置的对象都是Struts Action 每一个Struts Action方法都形如这样, public ActionForward addBlog(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) 所以,通过 for (int i = 0 ; i < args.length ; i++ ) { if (args[i] instanceof HttpServletRequest) request = (HttpServletRequest)args [i]; if (args[i] instanceof ActionMapping) mapping = (ActionMapping)args[i]; } 可以从那里迭代出来 你既然都有调用 Struts 了, mapping, form, request, response 肯定都已经注入了,咱们运行Struts, 是在 mapping, form, request, response 都具备的情况下,使用的 所以, Object[] args = invocation.getArguments(); 得到应该对象的所有参数是完全可以的 --------注解1结束 Object[] args = invocation.getArguments(); ---------加这两句是因为要通过request获取session 并且在判断没有权限的时候要通过mapping跳转页面 for (int i = 0 ; i < args.length ; i++ ) { if (args[i] instanceof HttpServletRequest) request = (HttpServletRequest)args[i]; if (args[i] instanceof ActionMapping) mapping = (ActionMapping)args[i]; } Object admin = request.getSession().getAttribute("admin"); ---------- 如果权限有问题, 那么invocation.procceed() 就不会执行,意味着你的那个 Action 对象**方法也不会执行, 但此时 mapping 是存在的, 来一下findForward("admin"); ---------- if ( admin != null && ((String)admin).equals("admin")) { return invocation.proceed(); } else { request.setAttribute("msg" , "您还没有登录,请先登录"); return mapping.findForward("admin"); } } } 拦截器(Interceptor)是Struts 2的核心组成部分。很多功能(Feature)都是构建在拦截器基础之上的,例如文件的上传和下载、国际化、转换器和数据校验等,Struts 2利用内建的拦截器,完成了框架内的大部分操作。 在Struts 2文档中对拦截器的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制,使开发者可以定义一个特定的功能模块,这个模块可以在Action执行之前或者之后运行,也可以在一个Action执行之前阻止Action执行。同时也提供了一种可以提取Action中可重用的部分的方式。 Struts 2拦截器 通过上一节的介绍,读者会对拦截器的原理有了一个基本的理解,本节来介绍Struts 2架构中的拦截器。 5.2.1 Struts 2拦截器原理 读者可以通过Struts 2官方文档说明来理解拦截器,如果读者具有较强的英文阅读能力,建议查阅官方使用文档(http://struts.apache.org/2.0.11/docs/interceptors.html)。如图5.4所示,是拦截器在Struts 2中的示意图。 图5.4 Struts 2拦截器 从图5.4所示内容中可以看出,Struts 2架构的Action被一个或者多个拦截器(拦截器栈)所包围,所有的用户请求都会被拦截器所拦截,然后交给Action处理,处理结果以逻辑视图方式返回给用户。而这个调用执行流程,是由Struts 2的配置文件来实现的,后面会详细介绍。拦截器是Struts 2核心部分之一。 当用户请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(List),最后一个一个地调用列表中的拦截器。拦截器时序图如图5.5所示。 图5.5 Struts 2拦截器时序图 在Struts 2架构中,Action的调用都是通过拦截器来实现的。有的读者可能会疑惑,前几章的介绍中,没有明确说明拦截器,为什么可以直接调用Action?那是因为Struts 2架构如果不做显式的拦截器配置,则系统会调用默认的拦截器来调用Action,在用户看来,好像没有配置拦截器。系统默认的拦截器笔者后面会详细介绍。 5.2.2 HelloWorld拦截器 读者可以按照笔者的步骤,一步一步建立第一个拦截器示例,来体验Struts 2框架中拦截器带给读者的惊喜。 (1) 在配置文件中增加拦截器定义和在Action中声明拦截器。笔者建立了一个目录ch5来对应本章,ch5.xml配置文件内容如代码5.8所示。 代码5.8 HelloWorld拦截器配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- 定义包--> <package name="ch5" extends="struts-default" namespace="/ch5"> <!-- 定义拦截器--> <interceptors> <interceptor name="Myinterceptor" class="ch5.Myintercepor"> </interceptor> </interceptors> <action name="Reg" class="ch5.Reg"> <result name="success">/ch5/success.jsp</result> <result name="input">/ch5/reg.jsp</result> <!-- 引用默认拦截器--> <interceptor-ref name="defaultStack"></interceptor-ref> <!-- 引用自定义默认拦截器--> <interceptor-ref name="Myinterceptor"></interceptor-ref> </action> </package> </struts> ★ 注意 ★ 需要读者在struts.xml文件中使用<include file="/ch5/ch5.xml"></include>将该配置文件包含进去。 (2)在ch5包内建立一个拦截器类Myintercepor,如代码5.9所示。 代码5.9 Helloworld拦截器类Myintercepor package ch5; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class Myintercepor extends AbstractInterceptor { //拦截方法 public String intercept(ActionInvocation arg0) throws Exception { Reg reg = (Reg) arg0.getAction(); System.out.println("拦截器信息:HelloWorld拦截器!"); //执行Action或者执行下一个拦截器 String result = arg0.invoke(); //提示Action执行完毕 System.out.println("拦截器信息:Action执行完毕!"); return result; } } (3)在ch5包内建立一个业务控制器Reg,如代码5.10所示。 代码5.10 HelloWorld拦截器示例的业务控制器 package ch5; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class Reg extends ActionSupport { //定义用户名属性 private String username; //定义处理信息:注意同http中的msg不同名称 private String mymsg; //定义密码属性 private String password1; //定义确认密码 private String password2; //定义生日属性 private Date birthday; public String execute() throws Exception { if (username != null && getPassword1().equals(getPassword2()) && !getUsername().trim().equals("")) { //输出调试信息 System.out.println("Action信息:正在执行Actiion... ..."); return SUCCESS; } else { return INPUT; } } //getter和setter方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getMymsg() { return mymsg; } public void setMymsg(String mymsg) { this.mymsg = mymsg; } public String getPassword1() { return password1; } public void setPassword1(String password1) { this.password1 = password1; } public String getPassword2() { return password2; } public void setPassword2(String password2) { this.password2 = password2; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } } (4)同样在ch5包内,建立一个用户注册reg.jsp文件和一个用于显示注册成功信息的success.jsp文件。内容分别如代码5.11和代码5.12所示。 代码5.11 用户注册界面reg.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>用户注册</title> <s:head /> </head> <body> <table> <s:form id="id" action="Reg"> <s:textfield name="username" label="用户名:"/> <s:password name="password1" label="密码:"/> <s:password name="password2" label="确认密码:"/> <s:datetimepicker name="birthday" label="生日:"/> <s:submit value="注册"/> </s:form> </table> </body> </html> 代码5.12 注册成功界面success.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>注册成功界面</title> <s:head /> </head> <body> <table> <h2>用户名:<s:property value="username" /></h2> <h2>密码:<s:property value="password1" /></h2> <h2>生日:<s:property value="birthday" /></h2> </table> </body> </html> (5) 启动Tomcat服务器,在浏览器中输入:http://localhost:8080/bookcode/ch5/reg.jsp,运行界面如图5.6所示。