Struts2简单开发流程

来源:互联网 发布:整理数据 英语 编辑:程序博客网 时间:2024/06/06 03:47
  1. Struts1的执行流程是什么;
  2. Struts2的执行流程是什么;
  3. 我们的Action如何编写;
  4. Action的配置问题;
  5. Action中操作Servlet Api;

1. Struts1的执行流程

大致思路如下:
当web客户端的浏览器发出http请求,然后到达tomcat的web应用服务器,将http请求头封装成HttpServletRequest和HttpServletResponse对象,然后doPost(req,resp)或者doGet(req,resp)到Tomcat的Servlet容器的前端控制Servlet, 也就是ActionServlet; 然后在其service中会调用RequestProcessor的process()方法,在这个主要的方法中,
1;会通过方法 String path = processPath(request, response) 截取出URL,也就是struts-config.xml的action的path部分;
2;processLocale(request, response) 处理国际化用到的Local相关信息;
3;ActionMapping mapping = processMapping(request, response, path); 根据path从ModuleConfig中取出Action的东西封装成ActionMapping;
4;ActionForm form = processActionForm(request, response, mapping); 根据ActionMapping 中的name属性查找ActionForm, 如果要是配置了ActionForm,那么就到request或者session中查找,如果在这两个中都没有找到,那么就根据ActionForm的路径采用反射来创建出ActionForm,并根据scope值将其放入到request或者session中;
5;processPopulate(request, response, form, mapping); 主要是将表单的数据收集转型到ActionForm中,在这个过程中会用到一个一个第三方组件BeanUtils将Map的值(将表单中的数据放入map中了)根据ActionForm中的字段类型转好,再调用setter方法将其放入到ActionForm上;
6; Action action = processActionCreate(request, response, mapping); 根据Action的完整类名称(type)到一个Map中去找,如果没有找到,就用反射创建一个,再将创建好的Action的放到Map中,所以Struts1的Action是单例的存在线程安全问题;
7; ActionForward forward = processActionPerform(request, response, action, form, mapping); 执行我们自定义的Action的execute方法,并将ActionForward返回;
8;processForwardConfig(request, response, forward); 根据上面的ActionForm完成相应的转发和转向;


3. Struts2的大致执行流程

这里写图片描述

Struts2的中央控制器是StrutsPreparedAndExecuteFilter这个类就类似Struts1中的ActionServlet; 这个中央控制器会创建一个Action的代理对象,这个ActionProxy会做一系列的工作,然后再调用真正的Action上去;这个类中有一个主要方法:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

1; ActionMapping mapping = prepare.findActionMapping(request, response, true); 取得ActionMapping;
2; 执行ExecuteOperators.execute.executeAction(request, response, mapping);
3; 在executeAction中会调用Dispatcher的serviceAction;execute.executeAction(request, response, mapping); 会调用一个很关键的方法:

 ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(                    namespace, name, method, extraContext, true, false);

这个ActionProxy是生产的StrutsActionProxy的父类;同时;
在生成ActionProxy代理的方法中会创建一个关键类:DefaultActionInvocation

public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {        DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);        container.inject(proxy);        proxy.prepare();        return proxy;    }

同时,会调用DefaultActionProxy类的prepare()方法;在这个方法中会调用ActionInvocation invocation的init()方法;
在init()方法中有两个关键步骤:
createAction(contextMap);
List interceptorList = new ArrayList(proxy.getConfig().getInterceptors());
interceptors = interceptorList.iterator();
先说第一个createAction(contextMap);
会调用ObjectFactory的buildAction方法
action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
会采用反射机制创建出Action,并且把Action赋值给ActionInvocttion成员变量中
其次第二个关键步骤:拿到18个拦截器;也放到ActionInvocation的成员变量interceptors中

也就是,在创建这个ActionProxy的过程中干了两个比较重要的是,第一创建了一个ActionInvocation 并且将创建的Action和18个拦截器放入了ActionInvocation的成员变量中;
最后在Dispatcher中生成了ActionProxy;
4;在Dispatcher的serviceAction的方法中调用生成代理类(StrutsActionProxy)的execute()方法;在这个execute()方法中会执行一个关键的操作,ActionInvocation的invoke();
5;ActionInvocation的invoke(); 进而会执行ActionInvocation中已经装入成员变量的拦截器interceptors的intercept方法;invokeActionOnly()方法;在invokeActionOnly()方法中会调用invokeAction(getAction(), proxy.getConfig());调用Action方法,返回转向的字符串;然后还是在这个invoke()方法中进而执行executeResult(); 在executeResult()中最终又会通过Struts2的ObjectFactory objectFactory.buildResult(resultConfig, invocationContext.getContextMap()); 创建一个Result对象,然后在executeResult()中,执行Result的result.execute(this);转向或者重定向到相应的视图模块;


3、Struts2中的Action如何编写
在Struts1中,我们可以继承Action覆盖execute方法:

public class MyAction extends Action {    @Override    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,            HttpServletResponse response) throws Exception {    }}

在Struts2中,我们有三种方法来开发自己的Action;
第一种:就是一个POJO类无需继承,无需实现任何接口和类,但是需要在类中添加execute方法就可以

public String execute(){return "success";}

第二种:通常实现com.opensymphony.xwork2.Action接口,并且实现的其execute方法,

public class LoginAction implements Action {    private LoginForm loginForm;    private LoginDao loginDao;    @Override    public String execute() throws Exception{        //以后使用Spring IOC实现;        String result = loginDao.checkUser(loginForm);        if(result!=null)            return SUCCESS;        return LOGIN;    }}

第三种:还有一种方式是继承com.opensymphony.xwork2下的ActionSupport类,并覆盖其execute方法;
ActionSupport已经实现了Action接口, 还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2的Action开发。
总结:
struts2不要求我们自己设计的action类继承任何的struts基类或struts接口, 但是我们为了方便实现我们自己的action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并重写此类里的public String execute() throws Exception方法。 因为此类中实现了很多的实用借口,提供了很多默认方法,这些默认方法包括国际化信息的方法、默认的处理用户请求的方法等,这样可以大大的简化Acion的开发。在action中并非一定需要execute方法,也可以指定自己需要的方法,action编写完毕后,就需要在struts.xml文件中编写配置文件了;


4.Action类的配置问题;
4.1 Action类配置涉及到几个关键属性如下:

  • name : action的名字,用于匹配请求的url;
  • class : Action实现类的完整类名;
  • method : 调用Action实现类中指定的方法;

    4.2 Action配置通配符使用:
    首先对 method 属性进行说明:
    通常action的作用是完成一个功能点,但是例如CRUD这样的操作使用四个action类显然不划算,在struts 2中可以将这四个功能映射到一个action中进行处理,这里就需要使用method属性了。具体的做法是:在struts.xml配置文件中为一个action使用method属性和name属性指定不同别名,就可以实现CRUD映射到同一个action了。

import com.opensymphony.xwork2.ActionSupport;public class UserAction extends ActionSupport{    private static final long serialVersionUID = 1L;    //查询    public String listUser() throws Exception {        return SUCCESS;    }    //修改    public String updateUser(){        return SUCCESS;    }    //删除    public String deleteUser(){        return SUCCESS;    }    //添加    public String addUser(){        return SUCCESS;    }}
<package name="user" namespace="/user" extends="struts-default">        <!-- name class method 识别同一个Action中的不同方法-->        <action name="list_User" class="action.UserAction" method="listUser">            <result>/list_User.jsp</result>        </action>        <action name="add_User" class="action.UserAction" method="addUser">            <result>/add_User.jsp</result>        </action>        <action name="delete_User" class="action.UserAction" method="deleteUser">            <result>/delete_User.jsp</result>        </action>        <action name="update_User" class="action.UserAction" method="updateUser">            <result>/update_User.jsp</result>        </action></package>

使用通配符映射的方式可以大大减少action的数量,所谓通配符就是使用,用于匹配0个或多个字符。在action的配置中,可以为name属性使用来匹配任意的字符。比如下面的配置:

<action name="*_*" class="action.{1}Action" method="{1}User">     <result>/{1}_{2}.jsp</result></action>

5. Action中操作Servlet Api

方法一: Struts2提供了一个ActionContext类,Struts2的Action可以通过该类来访问Servlet API。类中常用方法如下:

  • Object get(Object
    key):相当于HttpServletRequest的getAttribute(Stringname)方法。
  • Map getApplication():返回一个Map对象,该对象模拟了该应用的ServletContext实例。
  • static ActionContext getContext():静态方法,获取系统的ActionContext实例。
  • Map getParameters():获取所有请求参数。类似于HttpServletRequest的getParameterMap().
  • Map getSession():返回一个Map对象,该Map对象模拟了HttpSession实例。
  • void setApplication(Map
    application):传入一个Map的key-value,转换成application的属性名、属性值。
  • void setSession(Map session):传入一个Map的key-value,转换成session的属性名、属性值。

方法二: Struts2提供如下几个接口(需要implements并实现方法):

  • ServletContextAware:实现该接口的Action可以直接访问Web应用的ServletContext实例。
  • ServletRequestAware:实现该接口的Action可以直接访问用户请求的HttpServletRequest实例。
  • ServletResponseAware:实现该接口的Action可以直接访问服务器响应的HttpServletResponse实例。

    方法三: 使用ServletActionContext(工具类)访问Servlet API:

  • static PageContext getPageContext():取得Web应用的PageContext对象。

  • Static HttpServletRequest getRequest():取得Web应用的HttpServletRequest对象。

  • Static HttpServletResponse getResponse
    ():取得Web应用的HttpServletResponse对象。

  • Static ServletContext getServletContext():取得Web应用的ServletContext对象。