该文章主要简单粗暴的实现了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框架的请求转发的功能。功能写得很粗糙,很多情况都还未考虑进来,希望大家多多指点~

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

java struts 框架_java中struts 框架的实现相关推荐

  1. java reactor框架_Java反应式框架Reactor中的Mono和Flux

    1. 前言 最近写关于响应式编程的东西有点多,很多同学反映对Flux和Mono这两个Reactor中的概念有点懵逼.但是目前Java响应式编程中我们对这两个对象的接触又最多,诸如Spring WebF ...

  2. java开发后端框架_java开发后端框架

    1 java开发后端框架 java从推出到现在技术不断发展,语言也优化的越来越好,对于java工程师来说技术的不断发展,他们需要不断学习java进阶,而对于新手来说就能从基础到核心.那么新手该怎么学习 ...

  3. java php quercus,php中Quercus框架的安装

    我们在之前的学习中,已经知道Quercus的作用非常强大,能够在php和java程序中进行使用.从使用范围上来看,这个框架的适用性是比较高的.想必很多小伙伴还不会安装Quercus框架,这里我们进行了 ...

  4. java分布式爬虫_Java分布式爬虫框架:Gecco 入门

    什么是Gecco ? Gecco 是一款用java语言开发的轻量化的易用的网络爬虫,整合了jsoup.httpclient.fastjson.spring.htmlunit.redission等优秀框 ...

  5. java 注解开发_Java中的注解到底是如何工作的?

    作者:人晓 www.importnew.com/10294.html 自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Over ...

  6. java list对象_JAVA中list

    Java 查找 List 中的最大值.最小值 Java 查找 List 中的最大值.最小值 java> List list = new ArrayList(); java.util.List l ...

  7. java mod %区别_Java中 % 与Math.floorMod() 区别详解

    %为取余(rem),Math.floorMod()为取模(mod) 取余取模有什么区别呢? 对于整型数a,b来说,取模运算或者取余运算的方法都是: 1.求 整数商: c = a/b; 2.计算模或者余 ...

  8. java show过时_Java中show() 方法被那个方法代替了? java编程 显示类中信

    你说的show是swing里的吧,在老版本中Component这个超类确实有show这个方法,而且这个方法也相当有用,使一个窗口可见,并放到最前面.在jdk5.0中阻止了这个方法,普遍用setVisi ...

  9. java判断类型_Java中类型判断的几种方式 - 码农小胖哥 - 博客园

    1. 前言 在Java这种强类型语言中类型转换.类型判断是经常遇到的.今天就细数一下Java中类型判断的方法方式. 2. instanceof instanceof是Java的一个运算符,用来判断一个 ...

最新文章

  1. leetcode算法题--K站中转内最便宜的航班★
  2. 基于PHP7的提供数据管理工具框架Meloy 1.0.3 发布
  3. WebSocket——stomp连接错误[Whoops! Lost connection to XXX]解决方案
  4. LVM基本应用 扩展及缩减实现
  5. https://cwiki.apache.org/confluence/display/FLINK/FLIP-24+-+SQL+Client
  6. ldap基本dn_LDAP 中 DN CN DC OU
  7. Crontab- Linux必学的60个命令
  8. 带你快速了解ISO27001信息安全管理体系认证
  9. 新闻发布系统(java实现)+论文
  10. 小技巧:visio 如何让箭头完全水平
  11. 数据采集笔记(八爪鱼)-task1
  12. 组成原理之全加器实验
  13. C语言英尺和英寸换算米
  14. centos mysql 大小写_linux 、centos 安装MySQL及踩坑大小写敏感
  15. 基于Android的校园图书共享app
  16. 支持DoH的DNS服务器,使用 Docker 自建支持 DoH、DoT 的 DNS 服务器
  17. php一点通,编程一点通下载-编程一点通最新安卓版下载-99wo下载站
  18. c、c++的getchar()函数
  19. JVM调优专题-JVM调优参数
  20. 【Flutter】如何完成一个透明沉浸式状态栏

热门文章

  1. python 函数式编程 库_使用Python的toolz库开始函数式编程的方法
  2. java 自动加载jar_JAVA 动态(手动)加载jar文件
  3. svn如何取消某个文件的版本管理_微服务架构如何统一管理工程配置文件
  4. 世界之窗浏览器怎么隐藏收藏栏
  5. win7系统5分钟自动注销的解决方法
  6. html背景图片尺寸位置百分比,css – 如何计算背景大小百分比?
  7. linux 为什么要安装gcc和gcc-c++(又叫做g++)
  8. 发明喂饭机器人_人类又懒出新高度,老美发明自动喂饭机器人,“君子”动嘴不动手...
  9. 基坑监测日报模板_刚刚!温州瓯海突发塌陷,初步判断为临近地块地下室基坑支护桩移位...
  10. java数组更新_java刷新数组到jList