Struts1.3-DispatchAction类-根据请求参数实现业务分派

来源:互联网 发布:外汇黄金走势软件 编辑:程序博客网 时间:2024/06/06 03:45

本文将着重来理解下org.apache.struts.actions.DispatchAction类。

在有些时候一个Action可能有多种操作,比如查询,增加,删除等,都集中在了一个Action中,每个操作都会被封装在一个独立的方法中,此时需要使用某个变量来区分Action接收到的请求需要执行哪个操作,根据操作类型再去调用相应的方法。

DispatchAction类

DispatchAction类为我们实现了这个根据请求动态的分发业务给不同的方法。

比如某个Action地址为”hello.do”,当访问”hello.do?method=add”时,将调用Action类中的add方法;访问”hello.do?method=show”时,将调用Action类中show方法。

这里的请求路径参数”?method=add”,

前者参数名”method”需要在struts-config.xml配置文件中的action元素中使用parameter属性定义,

后者参数值对应着Action类中的同名方法。

我们需要将自己的Action继承DispatchAction类,DispacthAction类又是继承Action类的。然后需要声明自己的业务处理方法,

public class HelloAction extends DispatchAction{    public ActionForward add (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response)    {        System.out.println("HelloAction.add()");        return null;    }    public ActionForward show (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response)    {        System.out.println("HelloAction.show()");        return null;    }}

这里需要注意的是,自定义的业务处理方法的格式为:

public ActionForward methodName (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response)

{

}

方法的返回类型与方法参数都是固定的,方法名可以自定义。

对应的struts-config.xml文件中action元素:

<action          attribute="helloForm"          input="/index.jsp"          name="helloForm"          path="/hello"          scope="request"          type="com.yourcompany.struts.action.HelloAction"          cancellable="yes"          parameter="method"  />

最后一个parameter属性是关键。

当访问 “/hello.do?method=add”时,将调用add方法,输出”HelloAction.add()”

当访问”/hello.do?method=show”时,将调用show方法,输出”HelloAction.show()”

上面的例子是比较简单的一个DispacthAction。我们还可以重写DispacthAction类中的某些方法,比如unspecified方法,cancelled方法,execute方法等。

image

cancelled方法,默认方法内容为空,返回null

protected ActionForward cancelled (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response) throws Exception{    return null;}

当JSP页面上的<html:cancel />被按下时,cancelled方法被调用,可以重写这个方法,实现cancel按钮点击的事件处理。

@Overridepublic ActionForward cancelled (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response) throws Exception{    System.out.println("HelloAction.cancelled()");    ...    return mapping.findForward("indexPage");//返回主页}

unspecified方法,如果当前Parameter名与配置中的parameter属性值不一样时,被调用。

比如访问地址 “/hello.do?action=add”,因为配置文件的Action元素的parameter属性值为”method”,与action不符合,此时将调用unspecified方法。

如果是参数值不同,找不到相应的方法,将抛出NoSuchMethodException异常。

默认的方法内容是直接抛出异常的:

protected ActionForward unspecified (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response) throws Exception{    String message = messages.getMessage("dispatch.parameter" , mapping.getPath() , mapping.getParameter());    //message:Request[{0}] does not contain handler parameter named '{1}'.  This may be caused by whitespace in the label text.    log.error(message);    throw new ServletException(message);}

execute方法,请求当前Action时,首先被调用的方法。关于方法内部细节,请看注释。

public ActionForward execute (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response) throws Exception{    if (isCancelled(request))    {        // 如果已经退出,调用cancelled方法。        ActionForward af = cancelled(mapping , form , request , response);        // 如果返回值不为null,则直接return,否则如果为null,继续执行后面的代码。        if (af != null)        {            return af;        }    }    // 获取参数名,使用ActionMapping.getParameter()方法,如果参数名为null,在getParameter方法内部会抛出ServletException异常。    String parameter = getParameter(mapping , form , request , response);    // 根据参数名获取参数值 使用request.getParameter(parameter) 方法,获得希望要访问的方法名    String name = getMethodName(mapping , form , request , response , parameter);    // 方法名不能为execute或者perform,否则将抛出ServletException异常。    if (("execute".equals(name)) || ("perform".equals(name)))    {        String message = messages.getMessage("dispatch.recursive" , mapping.getPath());        log.error(message);        throw new ServletException(message);    }    //调用dispatchMethod方法,参数name为希望要访问的方法名,在dispatchMethod方法内部将使用反射机制去调用与name同名的方法。    //如果name==null,将调用unspecified方法,并直接返回。    return dispatchMethod(mapping , form , request , response , name);}

我们可以重写execute方法,在利用反射调用相应的方法前,对mapping,form,request,response做一定的操作,最后再:

return super.execute(mapping,form,request,response);

使用Myeclipse自动生成的Action类,一般都会默认生成一个execute方法,此时必须手动修改代码(或者直接删除execute方法),调用super.execute方法,不然覆盖了父类的execute方法将导致分发功能失效。

getParameter方法,获取配置文件中的参数名。如果参数名为null,将抛出异常。

@Overrideprotected String getParameter (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response) throws Exception{    // 获取配置文件中parameter属性值    String parameter = mapping.getParameter();    // 如果为null,抛出ServletException异常。    if (parameter == null)    {        String message = messages.getMessage("dispatch.handler" , mapping.getPath());        // DispatchMapping[{0}] does not define a handler property        log.error(message);        throw new ServletException(message);    }    return parameter;}

getMethodName方法,根据参数名获得希望访问的方法名。

@Overrideprotected String getMethodName (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response , String parameter) throws Exception{    return request.getParameter(parameter);}

注意,在这里使用的parameter是从配置文件的parameter属性中获取的,并不是地址栏链接参数中等于号前面的参数名。

所以,如果配置文件中的parameter值和实际访问地址中的参数名不相同的话,返回的String为null。这个null值将传递到dispatchMethod方法…

dispatchMethod方法,方法内部使用反射调用相应的方法。具体细节,请看注释。

protected ActionForward dispatchMethod (ActionMapping mapping , ActionForm form , HttpServletRequest request , HttpServletResponse response , String name) throws Exception{    // 接在execute方法内部传过来的name,如果为null,将调用unspecified方法,并直接return。    if (name == null)    {        return unspecified(mapping , form , request , response);    }    Method method = null;    try    {        // 根据name值,获得一个Method对象,如果未找到相应的方法,将抛出NoSuchMethodException异常。        method = getMethod(name);    }    catch (NoSuchMethodException e)    {        String message = messages.getMessage("dispatch.method" , mapping.getPath() , name);        log.error(message , e);        String userMsg = messages.getMessage("dispatch.method.user" , mapping.getPath());        throw new NoSuchMethodException(userMsg);    }    ActionForward forward = null;    try    {        // 封装4个参数为Object数组,在利用反射调用方法时作为参数传递。        Object [] args = { mapping , form , request , response };        // 利用上面获得的Method对象使用invoke从当前类中调用方法。        // 返回的对象被强转为ActionForward。        forward = (ActionForward) method.invoke(this , args);    }    catch (ClassCastException e)    {// 当invoke方法返回的对象 无法强转为ActionForward时抛出。        String message = messages.getMessage("dispatch.return" , mapping.getPath() , name);        log.error(message , e);        throw e;    }    catch (IllegalAccessException e)    {// 无法访问 方法时抛出。在自定义方法时,方法不能为私有。        String message = messages.getMessage("dispatch.error" , mapping.getPath() , name);        log.error(message , e);        throw e;    }    catch (InvocationTargetException e)    {        Throwable t = e.getTargetException();        if ((t instanceof Exception))        {            throw ((Exception) t);        }        String message = messages.getMessage("dispatch.error" , mapping.getPath() , name);        log.error(message , e);        throw new ServletException(t);    }    // 最后返回我们自定义方法的返回结果    return forward;}

getMethod方法,根据方法名获取Method对象:

protected Class clazz = getClass();protected HashMap methods = new HashMap();protected Class[] types = { ActionMapping.class, ActionForm.class, HttpServletRequest.class, HttpServletResponse.class };@Overrideprotected Method getMethod (String name) throws NoSuchMethodException{   synchronized (this.methods)   {       Method method = (Method) this.methods.get(name);//根据name直接从HashhMap中直接获得Method对象        if (method == null)//如果为null       {           method = this.clazz.getMethod(name , this.types);//获取Method对象           this.methods.put(name , method);//保存在HashMap中。        }       return method;   }}

第一次访问时,会将获取的Method对象保存在hashMap中,下次获取时直接从HashMap中获取。


下面是综上所述形成的一个流程图…还是画的不是很好看,将就下了。

image