java struts 框架_java中struts 框架的实现

该文章主要简单粗暴的实现了struts的请求转发功能。 其他的功能后续会慢慢补上。

最近在学习javassist的内容,看到一篇文章  大家一起写mvc  主要简单的描述了mvc的工作流程,同时实现了简单的struts2功能。

这里仿照的写了个简单的struts2框架,同时加上了自己的一些理解。

该文章主要简单粗暴的实现了struts的请求转发功能。 其他的功能后续会慢慢补上。

首先,在struts2框架中,请求的实现、跳转主要是通过在struts.xml进行相关配置。 一个标签表示一个请求的定义,action中包含了①请求的名称“name”;②请求对应的实现类“class” ;③同时还可通过“method”属性自定义执行的方法,若没配置默认执行execute0方法。

好了,在了解了struts2是怎么将界面请求同程序功能相连接后,我们通过自己的代码来实现这部分的功能。

那么,我们该如何下手了?

我们将需要实现的功能简单的分为两部分 ①action部分 ②result部分

action部分

①我们需要根据界面的请求找到对应的类以及执行的方法

result部分

①我们需要根据方法执行的逻辑返回'SUCCESS'、'NONE'、'LOGIN'、'INPUT'、'ERROR'这类型的字符串

②需要对不同的返回类型,指定不同的下一步请求地址

③需要定义请求的类型,包括'dispatcher(默认)'、'chain'、'redirect'、'redirectAction'、'stream'

在本文章中,result的返回类型只实现了'SUCCESS'、'LOGIN'两种,并且暂不考虑请求类型,实现的是默认的dispatcher请求转发类型。完善的功能后期会再补充。

那么,下面我们来通过代码看怎么实现如上功能。

首先定义了ActionAnnotation和ResultAnnotation 两个自定义注解来请求需要对应的方法以及方法返回的字符串对应的跳转请求

/**

* action注解:ActionName相当于web.xml配置中的url-pattern

* @author linling

*

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface ActionAnnotation

{

String ActionName() default "";

ResultAnnotation[] results() default {};

}

/**

* 返回注解对象:name相当于struts配置中的result的name,包括'SUCCESS'、'NONE'、'ERROR'、'INPUT'、'LOGIN';value相当于struts配置中对应返回跳转内容

* @author linling

*

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface ResultAnnotation

{

ResultType name() default ResultType.SUCCESS;

String value() default "index.jsp";

}

然后我们定义一个ActionContext类,来保存一个请求所需要的内容

/**

* 实现模拟struts根据配置文件跳转至action执行相应方法中需要的内容

* @author linling

*

*/

public class ActionContext

{

/**

* 相当于web.xml中url-pattern,唯一的

*/

private String Url;

/**

* ActionAnnotation注解对应方法,也就是action中要执行的方法

*/

private String method;

/**

* ActionAnnotation中的Result,对应action方法返回的类型。例如:key:'SUCCESS';value:'index.jsp'

*/

private Map results;

/**

* action的类

*/

private Class> classType;

/**

* action的对象

*/

private Object action;

/**

* 方法参数类型

*/

private Class>[] paramsType;

/**

* 方法参数的名称,注意这里方法名称需要和上面paramType参数一一对应

* 可以理解为是struts中action中的属性

*/

private String[] actionParamsName;

/**

* 本次请求的HttpServletRequest

*/

private HttpServletRequest request;

/**

* 本次请求的HttpServletResponse

*/

private HttpServletResponse response;

analysePackage是在组装ActionContext需要的方法

/**

* 遍历scan_package包下的class文件,将使用了ActionAnnotation注解的方法进行解析,组装成ActionContext对象 并放入urlMap中

* @param real_path

* @param scan_package

* @throws ClassNotFoundException

* @throws InstantiationException

* @throws IllegalAccessException

* @throws NotFoundException

*/

public static void analysePackage(String real_path, String scan_package) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NotFoundException

{

File file = new File(real_path);

if(file.isDirectory())

{

File[] files = file.listFiles();

for(File f : files)

{

analysePackage(f.getAbsolutePath(),scan_package);

}

}

else

{

String str = real_path.replaceAll("/", ".");

if (str.indexOf("classes." + scan_package) <= 0 || !str.endsWith(".class"))

{

return;

}

String fileName = str.substring(str.indexOf(scan_package),str.lastIndexOf(".class"));

Class> classType = Class.forName(fileName);

Method[] methods = classType.getMethods();

for(Method method : methods)

{

if(method.isAnnotationPresent(ActionAnnotation.class))

{

ActionContext actionContext = new ActionContext();

ActionAnnotation actionAnnotation = (ActionAnnotation)method.getAnnotation(ActionAnnotation.class);

String url = actionAnnotation.ActionName();

ResultAnnotation[] results = actionAnnotation.results();

if(url.isEmpty() || results.length < 1)

{

throw new RuntimeException("method annotation error! method:" + method + " , ActionName:" + url + " , result.length:" + results.length);

}

actionContext.setUrl(url);

actionContext.setMethod(method.getName());

Map map = new HashMap();

for(ResultAnnotation result : results)

{

String value = result.value();

if(value.isEmpty())

{

throw new RuntimeException("Result name() is null");

}

map.put(result.name(), value);

}

actionContext.setResults(map);

actionContext.setClassType(classType);

actionContext.setAction(classType.newInstance());

actionContext.setParamsType(method.getParameterTypes());

actionContext.setActionParamsName(getActionParamsName(classType, method.getName()));

urlMap.put(url, actionContext);

}

}

}

}

getParams是根据httpServletRequest请求中的请求内容获得请求参数数组,该参数数组为调用方法体的参数内容

/**

* 根据 参数类型parasType 和 参数名actinParamsName 来解析请求request 构建参数object[]

* @param request

* @param paramsType

* @param actionParamsName

* @return

* @throws InstantiationException

* @throws IllegalAccessException

* @throws IllegalArgumentException

* @throws InvocationTargetException

* @throws NoSuchMethodException

* @throws SecurityException

*/

public static Object[] getParams(HttpServletRequest request, Class>[] paramsType, String[] actionParamsName) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException

{

Object[] objects = new Object[paramsType.length];

for(int i = 0; i < paramsType.length; i++)

{

Object object = null;

if(ParamsUtils.isBasicType(paramsType[i]))

{

objects[i] = ParamsUtils.getParam(request, paramsType[i], actionParamsName[i]);

}

else

{

Class> classType = paramsType[i];

object = classType.newInstance();

Field[] fields = classType.getDeclaredFields();

for(Field field : fields)

{

Map map = request.getParameterMap();

for(Iterator iterator = map.keySet().iterator(); iterator.hasNext();)

{

String key = iterator.next();

if(key.indexOf(".") <= 0)

{

continue;

}

String[] strs = key.split("\\.");

if(strs.length != 2)

{

continue;

}

if(!actionParamsName[i].equals(strs[0]))

{

continue;

}

if(!field.getName().equals(strs[1]))

{

continue;

}

String value = map.get(key)[0];

classType.getMethod(convertoFieldToSetMethod(field.getName()), field.getType()).invoke(object, value);

break;

}

}

objects[i] = object;

}

}

return objects;

}

好了,接下来。我们可以来实现action方法了

public class LoginAction

{

@ActionAnnotation(ActionName="login.action",results={@ResultAnnotation(name=ResultType.SUCCESS,value="index.jsp"),@ResultAnnotation(name=ResultType.LOGIN,value="login.jsp")})

public ResultType login(String name, String password)

{

if("hello".equals(name) && "world".equals(password))

{

return ResultType.SUCCESS;

}

return ResultType.LOGIN;

}

@ActionAnnotation(ActionName="loginForUser.action",results={@ResultAnnotation(name=ResultType.SUCCESS,value="index.jsp"),@ResultAnnotation(name=ResultType.LOGIN,value="login.jsp")})

public ResultType loginForUser(int number, LoginPojo loginPojo)

{

if("hello".equals(loginPojo.getUsername()) && "world".equals(loginPojo.getPassword()))

{

return ResultType.SUCCESS;

}

return ResultType.LOGIN;

}

}

接下来,我们需要做的是让程序在启动的时候去遍历工作目录下所有类的方法,将使用了ActionAnnotation的方法找出来组装成ActionContext,这就是我们请求需要执行的方法。这样在请求到了的时候我们就可以根据请求的地址找到对应的ActionContext,并通过反射的机制进行方法的调用。

我们定了两个Servlet。一个用于执行初始化程序。一个用来过滤所有的action请求

StrutsInitServlet

com.bayern.struts.one.servlet.StrutsInitServlet

scan_package

com.bayern.struts.one

10

DispatcherServlet

com.bayern.struts.one.servlet.DispatcherServlet

DispatcherServlet

*.action

DispatcherServlet实现了对所用action请求的过滤,并使之执行对应的action方法,以及进行下一步的跳转

ublic void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException

{

request.setCharacterEncoding("utf-8");

String url = request.getServletPath().substring(1);

ActionContext actionContext = DispatcherServletUtil.urlMap.get(url);

if(actionContext != null)

{

actionContext.setRequest(request);

actionContext.setResponse(response);

try

{

Object[] params = DispatcherServletUtil.getParams(request, actionContext.getParamsType(), actionContext.getActionParamsName());

Class> classType = actionContext.getClassType();

Method method = classType.getMethod(actionContext.getMethod(), actionContext.getParamsType());

ResultType result = (ResultType)method.invoke(actionContext.getAction(), params);

Map results = actionContext.getResults();

if(results.containsKey(result))

{

String toUrl = results.get(result);

request.getRequestDispatcher(toUrl).forward(request, response);

}

else

{

throw new RuntimeException("result is error! result:" + result);

}

}

好了,现在我们已经实现了最简单的strut2框架的请求转发的功能。功能写得很粗糙,很多情况都还未考虑进来,希望大家多多指点~

以上所述就是本文的全部内容了,希望大家能够喜欢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/561562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

memcached 使用 java_使用Java java_memcached client的陷阱

这2天&#xff0c;才发现之前我们的某个开发人员使用java_memcached-release_2.0.1.jar是有问题的在我们的某个模块里&#xff0c;需要2个memcached&#xff0c;分别提供不同的服务于是&#xff0c;开发的人员就从网上粘贴来如下的码&#xff0c;分别生成2个MemcacheUtil类stat…

java final 变量只读_java final的使用总结

final 变量&#xff1a;是只读的&#xff1b;final 方法&#xff1a;是不能继承或者重写的。final 引用&#xff1a;引用不能修改&#xff0c;但是对象本身的属性可以修改&#xff1b;final class&#xff1a;不可继承&#xff1b;final MyObject o new MyObject();o.setValue…

java list 获取索引_java – 获取arrayList中元素的索引

我试图在arrayList minuteList中获得466的索引[288, 318, 346, 376, 406, 436, 466, 1006, 1036, 1066, 1096, 1126, 1156]但我收到这个错误&#xff1a;java.lang.IndexOutOfBoundsException: Index: 466, Size: 13at java.util.ArrayList.rangeCheck(ArrayList.java:635)at j…

java 如何调用static_java 关键字static详细介绍及如何使用

java 关键字static 详解一、 static代表着什么在Java中并不存在全局变量的概念&#xff0c;但是我们可以通过static来实现一个“伪全局”的概念&#xff0c;在Java中static表示“全局”或者“静态”的意思&#xff0c;用来修饰成员变量和成员方法&#xff0c;当然也可以修饰代码…

java xml setdoctype_如何在Java中使用DOM将自定义doctype标记添加到带有xhtml标记的xml中?...

我使用java中的DOM创建了一个XML文档,并将XHTML标记插入到XML文档中。现在我要添加如下doctype:]>我试着把它作为一个字符串追加,但没有成功。DocumentBuilderFactory docFactory DocumentBuilderFactory.newInstance();docFactory.setNamespaceAware(true);DocumentBuilde…

java 实验报告模板_java实验报告模板

java实验报告模板1 / 26java 实验报告模板河南工业大学实验报告课程 Java 程序设计 _ 实验名称 一、Java 程序流程控制 院 系____ ____ 专业班级__ _________ 姓 名_______________ 学 号____________ _ 指导老师&#xff1a; 日 期一.实验目的熟悉 Java 语言中的数据类型、变量…

Java写入磁盘阵列_磁盘阵列RAID介绍及计算公式

一、RAID介绍磁盘阵列(Redundant Arrays of Independent Disks&#xff0c;RAID)&#xff0c;有“独立磁盘构成的具有冗余能力的阵列”之意。磁盘阵列是由很多块独立的磁盘&#xff0c;组合成一个容量巨大的磁盘组&#xff0c;利用个别磁盘提供数据所产生加成效果提升整个磁盘系…

dbm和mysql使用场景_mysql基本用法总结

1 下载安装官网下载&#xff1a;http://www.mysql.com/注意需要一个Oracle账号才能下载。2 启动mysql将mysql安装目录&#xff1a;设置为环境变量&#xff0c;并将&#xff1a;\bin目录加入环境变量中。启动命令行&#xff0c;输入&#xff1a;mysqld以启动mysql的守护进程。3 …

java disposable_rx-java – RxJava中的CompositeDisposable是什么

复合一次性使处理(认为提前取消更容易).假设您有一个活动同时发生多个api调用&#xff1a;var disposable api.call1(arg1,arg2).subscribe(...)var disposable2 api.call2(arg1).subscribe(...)var disposable3 api.call3().subscribe()如果您需要提前处置(例如,用户导航远…

Java中implies_boolean implies(Permission p)

boolean implies(Permission p)描述 (Description)java.util.PropertyPermission.implies(Permission p)方法检查此PropertyPermission是否隐含指定的Permission 。 这是通过检查p是PropertyPermission对象来完成的&#xff0c; p动作是该对象的动作的子集&#xff0c;并且该对…

java.rmi.server.port_java.rmi.server.ExportException: internal error: ObjID already in use报错处理...

由于在server.xml文件中使用配置了在catalina.sh中也指定了对应CATALINA_OPTS"$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port12340 -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse -D…

java 易变变量_关于java:易变变量和其他变量

以下是经典Concurency in Practice的内容&#xff1a;When thread A writes to a volatile variable and subsequently thread Breads the same variable, the values of all variables that werevisible to A prior to writing to the volatile variable, become visibleto B …

java违反唯一约束异常_Caused by: java.sql.BatchUpdateException: ORA-00001: 违反唯一约束条件 (DSPACE.SYS_C007868)...

Caused by: java.sql.BatchUpdateException: ORA-00001: 违反唯一约束条件 (DSPACE.SYS_C007868).............................遇到这种问题解决方法1. 使用 约束条件查找包含的表明以及 表的字段select a.constraint_name,a.constraint_type,b.column_name,b.table_namefrom…

js中的if与Java中的if_JS直接if参数的用法JS中!和!!区别

经常在JS中见一些代码直接if(参数)&#xff0c;然后参数调用的时候是将元素自己传下去。例如下面代码:functiontest1(obj){if(obj){alert($(obj).val());}else{alert("has not obj");}}我们分别点击上面的两个输入框显示如下:解释:实际上相当于java中的重载&#xff…

vs2019能写Java吗_Visual studio2019打包程序过程

要想打包visual studio中的程序我们需要用到setup用于自定义安装部署的项目方案。但是在VS2019中不见了&#xff0c;微软是有意废除安装项目的&#xff0c;合作了一个第三方的安装项目单独使用。我们可以从官网上把Visual Studio Installer 项目扩展下载下来。地址&#xff1a;…

java各个版本的特性_Java各个版本的新特性

原链接&#xff1a;http://blog.csdn.net/shareus/article/details/507361591.51.自动装箱与拆箱&#xff1a;2.枚举(常用来设计单例模式)  http://www.jb51.net/article/78351.htm3.静态导入4.可变参数5.内省1.61.Web服务元数据2.脚本语言支持3.JTable的排序和过滤4.更简单,…

java继承的终极奥义_java学习笔记12-继承

继承就是子类继承父类的特征和行为有时候单一划分某个类别并不能处理所有情况&#xff0c;某些类别下有明显不同的子类&#xff0c;这些子类虽然拥有类似的行为和属性&#xff0c;但是他们各自发生的这些行为的方式或者属性对某些结果的影响是不一样的&#xff0c;这就需要划分…

flink java 并行度_flink solt和并行度

简介Flink运行时主要角色有两个&#xff1a;JobManager和TaskManager&#xff0c;无论是standalone集群&#xff0c;flink on yarn都是要启动这两个角色。JobManager主要是负责接受客户端的job&#xff0c;调度job&#xff0c;协调checkpoint等。TaskManager执行具体的Task。Ta…

php中多选提交如何获取,php中checkbox值获取,显示,多选值获取

php教程中checkbox值获取&#xff0c;显示&#xff0c;多选值获取最简单checkbox获取值代码checkboxdemocheckboxdemodemonstrates checkboxes"handleformcheckbox.php">"11.00">fries"chksoda" value "12.85">soda"ch…

php对mysql的操作教程,php与Mysql的一些简单的操作

先贴代码复制代码 代码如下:数据库相关$con mysql_connect("localhost","root","root"); //链接数据库if(!$con){die(连接失败&#xff01; . mysql_error()); //判断是否成功}/* if(mysql_query("CREATE DATABASE testdb&qu…