java中struts 框架的实现

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

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

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

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

首先,在struts2框架中,请求的实现、跳转主要是通过在struts.xml进行相关配置。 一个<action>标签表示一个请求的定义,action中包含了①请求的名称“name”;②请求对应的实现类“class” ;③同时还可通过“method”属性自定义执行的方法,若没配置默认执行execute0方法。<result》标签定义了①结果的类型“name”,包括'SUCCESS'、'NONE'、'LOGIN'、'INPUT'、'ERROR';②请求的类型“type”,包括'dispatcher(默认)'、'chain'、'redirect'、'redirectAction'、'stream';③结果的跳转。 在配置完struts.xml后,界面中的表单就可以通过action属性与action定义的name属性值相匹配找到对应的action标签,从而找到对应的class以及执行的方法。再根据执行方法返回的string字符串同result标签中的name相匹配,根据定义的type类型,进行下一步请求操作。

好了,在了解了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<ResultType, String> 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<ResultType, String> map = new HashMap<ResultType, String>();
            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<String, String[]> map = request.getParameterMap();
            for(Iterator<String> 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请求

  <servlet>
    <servlet-name>StrutsInitServlet</servlet-name>
    <servlet-class>com.bayern.struts.one.servlet.StrutsInitServlet</servlet-class>
    <init-param>
      <param-name>scan_package</param-name>
      <param-value>com.bayern.struts.one</param-value>
    </init-param>
    <load-on-startup>10</load-on-startup>
   </servlet> 

   <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>com.bayern.struts.one.servlet.DispatcherServlet</servlet-class>
   </servlet>
   <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>*.action</url-pattern>
   </servlet-mapping>

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<ResultType,String> 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框架的请求转发的功能。功能写得很粗糙,很多情况都还未考虑进来,希望大家多多指点~

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

(0)

相关推荐

  • java中struts2实现文件上传下载功能实例解析

    本文实例讲述了java中struts2实现文件上传下载功能实现方法.分享给大家供大家参考.具体分析如下: 1.文件上传 首先是jsp页面的代码 在jsp页面中定义一个上传标签 复制代码 代码如下: <tr>      <td align="right" bgcolor="#F5F8F9"><b>附件:</b></td>      <td bgcolor="#FFFFFF">

  • struts2的select标签用法实例分析

    本文实例讲述了struts2的select标签用法.分享给大家供大家参考.具体如下: 项目中遇到个小问题,总结下. 关于struts2 select标签的使用. struts2 中从别的表中遍历数据 填充进入下拉菜单 用<s:select>标签显示. struts2的版本为2.1.8 <s:select       list=""       name=""       value=""       headerKey=&quo

  • JAVA+Struts2获取服务器地址的方法

    本文实例讲述了JAVA+Struts2获取服务器地址的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: HttpServletRequest request=ServletActionContext.getRequest();  String path=request.getRequestURI();  String actionPath=".."+path.substring(9);  //访问服务器所带有的参数信息  String queryInfo=reque

  • Java Web实现的基本MVC实例分析

    本文实例讲述了Java Web实现的基本MVC.分享给大家供大家参考.具体如下: login.jsp--视图部分的输入文件 success.jsp--视图部分的输出文件 failure.jsp--视图部分的输出文件 LoginBean.java--模型部分 LoginServlet.java--控制器部分 web.xml--web应用的配置文件 下面分别介绍: 1.login.jsp 该功能的输入文件,用户首先访问这个文件.主要用于输入用户名和口令. 代码如下: <%@ page content

  • 详谈java集合框架

    1.为什么使用集合框架 当我们并不知道程序运行时会需要多少对象,或者需要更复杂方式存储对象--可以使用Java集合框架 2.Java集合框架包含的内容 接口:(父类)Collection接口下包含List(子类 )接口和Set(子类) 接口 List接口下又包含(ArrayList集合实现类和LinkedList集合实现类) Set接口下又包含(HashSet集合实现类和TreeSet集合实现类) 接口:(父类)Map接口下包含(HashMap集合实现类和TreeMap 集合实现类) *Coll

  • Java简单实现SpringMVC+MyBatis分页插件

    1.封装分页Page类 package com.framework.common.page.impl; import java.io.Serializable; import com.framework.common.page.IPage; /** * * * */ public abstract class BasePage implements IPage, Serializable { /** * */ private static final long serialVersionUID

  • struts2入门Demo示例

    本文讲述了struts2入门Demo示例.分享给大家供大家参考.具体如下: 1.新建Web Project, 名称:struts2Demo; 2.建立一个用户库struts2, 包含最少的struts2的最少的6个jar文件; 其实呢, 对于MyEclipse8以上来说, 是不必须的, 因为它直接支持struts2了.不需要另外导包. 3.用Build Path将struts2的库加进来; 4.在web.xml中加入以下配置: <?xml version="1.0" encodi

  • java中struts 框架的实现

    该文章主要简单粗暴的实现了struts的请求转发功能. 其他的功能后续会慢慢补上. 最近在学习javassist的内容,看到一篇文章  大家一起写mvc  主要简单的描述了mvc的工作流程,同时实现了简单的struts2功能. 这里仿照的写了个简单的struts2框架,同时加上了自己的一些理解. 该文章主要简单粗暴的实现了struts的请求转发功能. 其他的功能后续会慢慢补上. 首先,在struts2框架中,请求的实现.跳转主要是通过在struts.xml进行相关配置. 一个<action>标

  • Java下Struts框架中的ActionForm类详解

    ActionForm的应用 (1) .创建一个form类必须继承四个父类中的一个.比如继承ActionForm. (2) .一个form类中的每一个属性都将和页面中form 表单中的每一个元素一一对应 例如. 一个表单为: <form> <input type="text" name="username"></input> <input type="password" name="passwor

  • java中ssj框架的项目搭建流程

    1.新建一个maven项目 2.在pom.xml中,配置所需的jar包及其版本号 <!-- 设置自定义属性和值 --> <properties> <spring.version>4.1.7.RELEASE</spring.version> <hibernate.version>4.3.11.Final</hibernate.version> </properties> <dependencies> <!-

  • Java中批处理框架spring batch详细介绍

    spring batch简介 spring batch是spring提供的一个数据处理框架.企业域中的许多应用程序需要批量处理才能在关键任务环境中执行业务操作. 这些业务运营包括: 无需用户交互即可最有效地处理大量信息的自动化,复杂处理. 这些操作通常包括基于时间的事件(例如月末计算,通知或通信). 在非常大的数据集中重复处理复杂业务规则的定期应用(例如,保险利益确定或费率调整). 集成从内部和外部系统接收的信息,这些信息通常需要以事务方式格式化,验证和处理到记录系统中. 批处理用于每天为企业处

  • Java中SSM框架实现增删改查功能代码详解

    记录一下自己第一次整合smm框架的步骤. 参考博客和网站有:我没有三颗心脏 How2J学习网站 1.数据库使用的是mySql,首先创建数据库ssm1,并创建表student create database ssm1; use ssm1; CREATE TABLE student( id int(11) NOT NULL AUTO_INCREMENT, student_id int(11) NOT NULL UNIQUE, name varchar(255) NOT NULL, age int(1

  • Java中JFinal框架动态切换数据库的方法

    需求:需要根据企业ID切换对应的数据库,同时,后期可动态增加数据库配置 JFinal框架中对于对于多数据源配置有两种方式: 1.通过配置文件配置,有多少数据库就要配置多少,服务启动时加载所有数据库,缺点:不能动态增加数据库 2.只配置一个主数据库信息就可以了,其他数据库信息保存在表中,通过读取表数据加载数据库连接,优点:在数据表中增加数据库配置即可动态增加数据库连接. 本次主要介绍第2种方法: 一.新建数据表:保存数据库连接信息 配置表对应的实体类 public class DbDto { /*

  • Java的Struts框架中的主题模板和国际化设置

    主题模板 如果不指定一个主题,然后Struts2中会使用默认的XHTML主题.例如Struts 2中选择标签: <s:textfield name="name" label="Name" /> 生成HTML标记: <tr> <td class="tdLabel"> <label for="empinfo_name" class="label">Name:<

  • Java的Struts框架中登陆功能的实现和表单处理器的使用

    实现Struts登录 1.jar包拷贝 首先是建立java web项目,之后打开我们我们下载好strtus框架,Struts-1.2.9-bin文件夹和struts-1.2.9.src源文件文件夹.在bin文件夹中的lib文件中拷贝struts的jar包,拷贝到我们自己项目struts_login –>lib文件夹下. 2.web.xml文件配置 找到Struts-1.2.9-bin中Struts-1.2.9-bin-->webapps下的struts实例struts-blank中的strut

  • 深入解析Java的Struts框架中的控制器DispatchAction

    Struts中的表单处理器为ActionForm,而struts中的控制器主要是Action,以及DispatchAction控制器等. Action 在struts中,所有的用户都会经过ActionServlet的处理,而实际的工作是交给Action对象来处理的,ActionServlet可以从配置文件中创建ActionMapping对象,从ActionMapping对象中找到对应使用的Action,然后将用户请求转交给Action. 对Struts一个ActionMapping只能生成一个A

  • Java的Struts框架简介与环境配置教程

    Struts2是流行和成熟的基于MVC设计模式的Web应用程序框架. Struts2不只是Struts1下一个版本,它是一个完全重写的Struts架构. WebWork框架开始以Struts框架为基础,其目标是提供一个加强和改进框架Struts来使web开发的开发人员更容易. 一段时间后,WebWork框架和Struts社区联手打造的著名的Struts2框架. Struts 2框架的特点: 这里有一些强大的功能,可能会迫使你考虑Struts2: POJO表单和POJO动作 - Struts2的S

随机推荐