自己实现Struts2(四)实现ActionInvocation

2024-04-09 22:48

本文主要是介绍自己实现Struts2(四)实现ActionInvocation,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一章自己实现Struts2(三)实现ActionContext我已经实现好了Struts2的数据中心ActionContext,现在就要来实现一下action和拦截器的调用者ActionInvocation

再把Struts2框架流程图贴上来

大家可以发现拦截器链和action都是通过ActionInvocation来调用的,要实现这个功能,就必须准备好拦截器链和要被调用的action实例以及该action对应的配置信息(要通过配置信息知道调用什么方法),下面就来实现一下。

#ActionInvocation类成员变量介绍
现在我就来创建一个ActionInvocation类,当然了,在Struts2中ActionInvocation是个接口,不过接口是为了方便扩展,我又没打算扩展,就直接定义类了。

package edu.jyu.invocation;import java.util.Iterator;import edu.jyu.config.ActionConfig;
import edu.jyu.context.ActionContext;
import edu.jyu.interceptor.Interceptor;/*** 拦截器链和action的调用类* * @author Jason*/
public class ActionInvocation {// 拦截器链private Iterator<Interceptor> interceptors;// 即将要被调用的action实例private Object action;// action配置信息private ActionConfig config;// 数据中心ActionContextprivate ActionContext invocationContext;}

其中Interceptor可以用Struts2自带的Interceptor接口,不过在这里我自己写了一个,没什么差别的

package edu.jyu.interceptor;import edu.jyu.invocation.ActionInvocation;/*** 拦截器接口
* @author Jason*/
public interface Interceptor {/*** 执行拦截器初始化工作*/public void init();/*** 拦截功能,在请求前或请求后执行一些处理* @param invocation* @return */public String intercept(ActionInvocation invocation);/*** 让拦截器做一些释放资源工作*/public void destory();
}

可以看到上面的ActionInvocation类定义了四个成员变量,现在我就简单介绍一下这个几个变量

  1. interceptors:很明显这就是拦截器链了,存放着需要执行的拦截器,用Iterator类型是为了在后面调用的时候方便取出来。
  2. action:要调用的action实例。
  3. config:要调用的action实例对应的配置信息,要根据配置信息去调用action的方法。
  4. invocationContext:本次请求的数据中心,为action实例准备好。

下面就要来做一下准备工作了,把这几个数据都准备好。

#准备工作
数据准备工作放在构造器中,代码如下

/*** 准备各种需要的数据* * @param interceptorClassNames*            存放着拦截器链每个拦截器的全限定类名* @param config*            需要调用的action的配置信息* @param request* @param response*/
public ActionInvocation(List<String> interceptorClassNames, ActionConfig config, HttpServletRequest request,HttpServletResponse response) {// 准备Interceptor链if (interceptorClassNames != null && interceptorClassNames.size() > 0) {List<Interceptor> list = new ArrayList<Interceptor>();for (String className : interceptorClassNames) {try {Interceptor interceptor = (Interceptor) Class.forName(className).newInstance();interceptor.init();list.add(interceptor);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Interceptor失败:" + className);}}interceptors = list.iterator();}// 准备action实例this.config = config;try {action = Class.forName(config.getClassName()).newInstance();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Action失败:" + config.getClassName());}// 准备数据中心ActionContextinvocationContext = new ActionContext(request, response, action);
}

现在就来介绍一下准备工作。

一、准备拦截器链:构造方法会接受一个集合,里面存放着全部需要调用的拦截器的全限定类名,根据拦截器的全限定类名反射生成对应的实例,执行拦截器的初始化方法init然后添加到另外一个集合中,最后调用interceptors = list.iterator();赋值给interceptors,至此拦截器链就准备完毕了。

二、准备action实例:构造方法会接受一个ActionConfig对象,这个对象存放的就是需要调用的action实例的配置信息,根据配置信息反射生成action实例。

三、准备ActionContext:这个没什么好讲的,直接new一个ActionContext对象将request、response和 action实例传进去,其中request和response对象是通过ActionInvocation的构造方法传进来的。

数据准备完成后就要开始调用了

#调用拦截器链和action

根据Struts2的框架流程图可以很清楚地看到,在调用action之前会先调用一系列的拦截器,在调用完action之后会逆序调用拦截器(其实就是执行Interceptor中intercept方法中的invocation.invoke()方法之后的代码),就是一个递归嘛,如果你会回溯法,对这个理解起来毫无压力。

不过需要注意的是,有可能拦截器直接返回一个字符串作为结果,这样action就不会被调用到了。

那么思路就是这样的:

  1. 如果拦截器链中还有其他的Interceptor,并且未被拦截器拦截(即未返回一个结果串),那么久调用下一个拦截器的拦截方法。

  2. 如果拦截器链中没有下一个拦截器了,那么根据action配置信息即config调用action实例的处理方法。

  3. 最后将结果串返回。

代码实现:

/*** 调用拦截器链和action处理方法* @param invocation * @return*/
public String invoke(ActionInvocation invocation) {// 结果串String result = null;// 判断拦截器链是否还有下一个拦截器或者未被拦截器拦截(result不等于null的话说明已经有拦截器直接返回结果串了)if (interceptors!=null && interceptors.hasNext() && result==null) {// 有下一个拦截器,调用下一个拦截器的拦截方法Interceptor next = interceptors.next();result = next.intercept(invocation);} else {// 没有下一个拦截器,调用action实例的处理方法// 获取处理的方法名String methodName = config.getMethod();try {Method method = action.getClass().getMethod(methodName);result = (String) method.invoke(action);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("action方法调用失败:" + methodName);}}return result;
}

拦截器链和action的整个调用流程就是这样子的了。

#获取ActionContext
在Struts2中ActionInvocation类有个方法ActionContext getInvocationContext()会返回一个ActionContext对象,其实这个对象就是我们上面定义的invocationContext,为action实例的调用而准备的,我们也可以提供获取它的方法。

public ActionContext getInvocationContext() {return invocationContext;
}

到了这里,整个ActionInvocation就完成了

ActionInvocation类完整代码:

package edu.jyu.invocation;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import edu.jyu.config.ActionConfig;
import edu.jyu.context.ActionContext;
import edu.jyu.interceptor.Interceptor;/*** 拦截器链和action的调用类* * @author Jason*/
public class ActionInvocation {// 拦截器链private Iterator<Interceptor> interceptors;// 即将要被调用的action实例private Object action;// action配置信息private ActionConfig config;// 数据中心ActionContextprivate ActionContext invocationContext;/*** 准备各种需要的数据* * @param interceptorClassNames*            存放着拦截器链每个拦截器的全限定类名* @param config*            需要调用的action的配置信息* @param request* @param response*/public ActionInvocation(List<String> interceptorClassNames, ActionConfig config, HttpServletRequest request,HttpServletResponse response) {// 准备Interceptor链if (interceptorClassNames != null && interceptorClassNames.size() > 0) {List<Interceptor> list = new ArrayList<Interceptor>();for (String className : interceptorClassNames) {try {Interceptor interceptor = (Interceptor) Class.forName(className).newInstance();interceptor.init();list.add(interceptor);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Interceptor失败:" + className);}}interceptors = list.iterator();}// 准备action实例this.config = config;try {action = Class.forName(config.getClassName()).newInstance();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Action失败:" + config.getClassName());}// 准备数据中心ActionContextinvocationContext = new ActionContext(request, response, action);}/*** 调用拦截器链和action处理方法* @param invocation * @return*/public String invoke(ActionInvocation invocation) {// 结果串String result = null;// 判断拦截器链是否还有下一个拦截器或者未被拦截器拦截(result不等于null的话说明已经有拦截器直接返回结果串了)if (interceptors!=null && interceptors.hasNext() && result==null) {// 有下一个拦截器,调用下一个拦截器的拦截方法Interceptor next = interceptors.next();result = next.intercept(invocation);} else {// 没有下一个拦截器,调用action实例的处理方法// 获取处理的方法名String methodName = config.getMethod();try {Method method = action.getClass().getMethod(methodName);result = (String) method.invoke(action);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("action方法调用失败:" + methodName);}}return result;}public ActionContext getInvocationContext() {return invocationContext;}
}

好了,ActionInvocation大功告成,项目已经上传到Github上
https://github.com/HuangFromJYU/JStruts2

如果大家有什么问题或者发现什么错误可以发邮件到jasonwong_hjj@qq.com,共同学习共同进步

这篇关于自己实现Struts2(四)实现ActionInvocation的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/889420

相关文章

Java根据IP地址实现归属地获取

《Java根据IP地址实现归属地获取》Ip2region是一个离线IP地址定位库和IP定位数据管理框架,这篇文章主要为大家详细介绍了Java如何使用Ip2region实现根据IP地址获取归属地,感兴趣... 目录一、使用Ip2region离线获取1、Ip2region简介2、导包3、下编程载xdb文件4、J

PyQt5+Python-docx实现一键生成测试报告

《PyQt5+Python-docx实现一键生成测试报告》作为一名测试工程师,你是否经历过手动填写测试报告的痛苦,本文将用Python的PyQt5和python-docx库,打造一款测试报告一键生成工... 目录引言工具功能亮点工具设计思路1. 界面设计:PyQt5实现数据输入2. 文档生成:python-

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整

浅析如何使用xstream实现javaBean与xml互转

《浅析如何使用xstream实现javaBean与xml互转》XStream是一个用于将Java对象与XML之间进行转换的库,它非常简单易用,下面将详细介绍如何使用XStream实现JavaBean与... 目录1. 引入依赖2. 定义 JavaBean3. JavaBean 转 XML4. XML 转 J

Flutter实现文字镂空效果的详细步骤

《Flutter实现文字镂空效果的详细步骤》:本文主要介绍如何使用Flutter实现文字镂空效果,包括创建基础应用结构、实现自定义绘制器、构建UI界面以及实现颜色选择按钮等步骤,并详细解析了混合模... 目录引言实现原理开始实现步骤1:创建基础应用结构步骤2:创建主屏幕步骤3:实现自定义绘制器步骤4:构建U

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句