Struts1框架七之DispatchAction的说明

struts 专栏收录该内容
8 篇文章 0 订阅

只要看过我之前的项目的同学一定会发现,哪些项目的配置相当复杂、繁琐!并且一个类对应一个请求,一个请求对应一个ActionForm,这对于真正的项目开发来说是一个巨大的BUG般的存在,不合理、非常不合理、完全不合理!这些不合理在Struts1当然不能存在。所以我们今天就讲讲怎么让一个类可以对应多个请求,多个请求怎么对应一个ActionForm。这样开发效率、配置量都会大大的减少.
首先,我们从配置文件里面开始讲怎么利用DispatchAction写Struts1项目,这个配置文件和我上文讲的没有多大的区别,只不过多加这个标签,启动这个parameter对应的值可以随便你取


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>

    <!-- 配置所有的formbean,每个formbean都可以用一个<form-bean>类指定-->
    <form-beans>
        <form-bean name="UserBean" type="com.xingyao.model.UserBean"></form-bean>
    </form-beans>

    <!-- 配置具体接受action请求的信息,每一个action请求都可以用一个<action>来指定 -->
    <action-mappings>
        <!-- 配置action信息,其中
            path表示用户form请求路径;
            type表示服务器组件action的类;
            name表示formBean组件;
            scope表示将FormBean封装到那个域中
            validate表示是否要验证该formBean
         -->
        <action 
            path="/user/test" 
            type="com.xingyao.action.LoginAction"
            name="UserBean" 
            scope="request" 
            parameter="command1"
        >
            <!-- 具体请求的时候,得到返回结果,需要跳转(转发)的页面 -->
            <forward name="success" path="/WEB-INF/JSP/success.jsp"></forward>
            <forward name="error" path="/WEB-INF/JSP/error.jsp"></forward>
        </action>
    </action-mappings>
</struts-config>

然后我们来看看jsp页面的设计,这里我们需要注意的是:你请求的do?后面的command这个字符串需要与你配置文件里面 对应,然后就是需要注意jsp页面的command=”属性值”不能为execute或者为perform。为什么下面讲解源码会列出来


<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
  </head>
  <body>
    <a href="user/test.do?command=add">添加功能</a>
    <a href="user/test.do?command=delete">删除功能</a>
  </body>
</html>

我们在来看看DispatchAction吧,其实这里并没有什么需要讲的,用法和实现Action类是一样的,只不过可以用方法接受用户的请求。需要注意的是:方法名要和jsp页面配置的command的属性值一样

package com.xingyao.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

/**
 * 登入功能的action
 * @author xingyao
 * @since 2016-8-24
 */
@SuppressWarnings("all")
public class LoginAction extends DispatchAction{

    /**
     * 添加用户功能
     */
    public ActionForward add(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        request.setAttribute("message", "添加成功");
        //返回结果,拥有返回页面的判断,参照配置文件(struts-config.xml)里面的<forward name="success" path="/WEB-INF/JSP/success.jsp"></forward>
        return mapping.findForward("success");
    }


    /**
     * 删除用户功能
     */
    public ActionForward delete(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
                    throws Exception {
        request.setAttribute("message", "删除成功");
        //返回结果,拥有返回页面的判断,参照配置文件(struts-config.xml)里面的<forward name="success" path="/WEB-INF/JSP/success.jsp"></forward>
        return mapping.findForward("success");
    }

}
啦啦啦啦啦,讲到源码分析了,源码分析主要讲解两个问题:DispatchAction的执行原理;和为什么不能使用execute和perform属性,如果使用了会产生什么样的情况
1、DispatchAction的实现原理

  /**
     *    1、通过ActionMapping得到设置的parameter的属性值,假设为A
     *    2、通过A得到表单参数对应的值。如果xxx.do?A="add",
     *    3、通过反射调用add方法
     */
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
            throws Exception {

//这里是得到<action paramter="属性值">
        String parameter = mapping.getParameter();
//判断属性值是否为null
        if (parameter == null) {
            String message =
                    messages.getMessage("dispatch.handler", mapping.getPath());

            log.error(message);

            throw new ServletException(message);
        }
//通过上面得到是属性值再从request域里面得到表单参数的值,这个就是在DispatcherAction里面对应的方法名
        String name = getMethodName(mapping, form, request, response, parameter);


//这里就是为什么方法名不能为execute和perform的原因
    if ("execute".equals(name) || "perform".equals(name)){
        String message =
            messages.getMessage("dispatch.recursive", mapping.getPath());

        log.error(message);
        throw new ServletException(message);
    }


        // Invoke the named method, and return the result
        return dispatchMethod(mapping, form, request, response, name);--------------------------见详细讲解1
    }

—————————————————————详细讲解1—————————————————————–

/**
     * Dispatch to the specified method.
     * @since Struts 1.1
     */
    protected ActionForward dispatchMethod(ActionMapping mapping,
                                           ActionForm form,
                                           HttpServletRequest request,
                                           HttpServletResponse response,
                                           String name) throws Exception {



        Method method = null;
        try {
//通过方法名,得到方法对象------------------------------------------------具体的见详细讲解2
            method = getMethod(name);
        } catch(NoSuchMethodException e) {}

        ActionForward forward = null;
        try {
//封装方法调用需要的参数
            Object args[] = {mapping, form, request, response};
//利用反射调用方法,得到方法返回的对象
            forward = (ActionForward) method.invoke(this, args);

        } catch(ClassCastException e) {
               ******省略其他的异常代码
        } 
        return (forward);
    }

————————————————————具体的见详细讲解2———————————————————–
我们先来了解下这个方法用到的全局变量

public abstract class DispatchAction extends Action {
//这里的this,是你继承了DisPatchAction的类的对象的引用
    protected Class clazz = this.getClass();
//这个methods存放了你继承DispatchAction类里面的所有方法
    protected HashMap methods = new HashMap();
//存放了方法里面参数的类型
    protected Class[] types =
            {
                ActionMapping.class,
                ActionForm.class,
                HttpServletRequest.class,
                HttpServletResponse.class
    };


    protected Method getMethod(String name)
            throws NoSuchMethodException {
        synchronized(methods) {
//这个方法先通过name到methods里面得到Method对象
            Method method = (Method) methods.get(name);
            if (method == null) {
//如果为空,这通过反射方法名,以及方法参数对象到this类里面对应name的方法对象
                method = clazz.getMethod(name, types);
//然后在将该方法对象存入到methods里面
                methods.put(name, method);
            }
            return (method);
        }
    }

将完了DispatchAction的执行原理了,我们也了解了为什么不能使用Execute和perform做方法名了,那么如果用了怎么办呢?当你用了execute方法做为方法名,那么就相当于你重写了Action的execute方法,这样就相当于你这个action只能执行一个方法,也就是execute方法,你配置的其他方法名是作为一个参数被request接受,而不能作为方法的反射对象的name被程序执行。
讲到这里,大家是不是爱上了
转载请标明出处
感谢苏波老师的指导
个人见解、错误请指出!请莫怪

  • 2
    点赞
  • 1
    评论
  • 2
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

丹顶鹤是码农

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值