Struts1 部分源码学习

  Struts1工作原理 
   1.系统初始化(读取配置):初始化ModuleConfig对象 
      Struts框架是一个总控制器(ActionServlet)是一个Servlet,在web.xml中配置成自动启动的Servlet。 
   读取配置文件的配置信息,为不同的struts模块初始化相应的ModuleConfig对象(ActionConfig、 
   ControlConfig、FormBeanConfig、ForwardConfig、MessageResponseConfig)。 
   
   2.发送请求 
   3.填充Form(实例化、复位、填充数据、校验):请求时ActionServlet为我们填充。如果有对应的FormBean实例化并填充http的请求数据,并保存在Servlet Context中(request或session),这样就可以被其他Action或jsp调用。 
   4.派发请求:控制器根据配置信息ActionConfig将请求派发给具体的Action,相应的FormBean一并派发。 
   5.处理业务:Action的execute。 
   6.返回响应:完毕后返回一个ActionForward对象。 
   7.查找响应(翻译响应):总控制器根据Action返回的目标响应对象,查找对应的资源对象。 
   8.响应用户:目标响应对象将结果展现给用户 

工作流程: 
jsp请求,服务器servlet mapping(*.do),前端控制器(ActionServlet)响应,封装FormBean,派发请求,Action execute,完毕后返回一个ActionForward对象,查找响应,响应用户


自己用Struts 写一个登入项目

      类: LoginAction(继承action)

              LoginActionForm(继承ActionForm)

              manager(设计成单例 里面写具体的login方法)

       jsp:login (写个表单)

               success

               erro

 写完之后 配置struts-config.xml 和 web.xml 如下:

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans>
<form-bean
name="LoginActionForm"
type="com.LoginActionForm"/>

</form-beans>
<action-mappings>
<action
name="LoginActionForm" path="/login"
scope="request"
type="com.LoginAction"
validate="true" >
<forward name="success" path="/loginsuccess.jsp"/>
<forward name="erro" path="/loginerro.jsp"/>
</action>
</action-mappings>
</struts-config>
/* 令人蛋痛的 Struts配置 第一行 一定是<? xml ?> 。 还有<!DOCTYPE>,一些拼写错写 以及 ">","/>"的问题要小心 */


 接下来就是源码部分一个一个按照上面写的流程来看

/*

这个就是初始化

*/

ModuleConfig

实现代码:

public ModuleConfigImpl(String prefix) {

        super();

        this.prefix = prefix;

        this.actionConfigs = new HashMap();

        this.actionConfigList = new ArrayList();

        this.actionFormBeanClass = "org.apache.struts.action.ActionFormBean";

        this.actionMappingClass = "org.apache.struts.action.ActionMapping";

        this.actionForwardClass = "org.apache.struts.action.ActionForward";

        this.configured = false;

        this.controllerConfig = null;

        this.dataSources = new HashMap();

        this.exceptions = new HashMap();

        this.formBeans = new HashMap();

        this.forwards = new HashMap();

        this.messageResources = new HashMap();

        this.plugIns = new ArrayList();

    }

/*

用户发送请求

*/

http://127.0.0.1:8080/struts_login/login.do

/*

解析http的内容  将path 封装成对象 读取struts-config xml  

* /

1、 String path = processPath(request, response);

 实现代码:

 path = request.getServletPath();

 path =="/login.do"

  int slash = path.lastIndexOf("/");

    int period = path.lastIndexOf(".");

        if ((period >= 0) && (period > slash)) {

            path = path.substring(0, period);

        }

        return (path);

path="/login"

2、ActionMapping mapping = processMapping(request, response, path);

实现代码:

ActionMapping mapping = (ActionMapping)

     moduleConfig.findActionConfig(path);

从ActionConfigs的MAP中通过path取得对应的ActionMapping对象

<action-mappings>

<action path="/login"

       type="com.struts.LoginAction"

       name="loginForm"

       scope="request"

       validate="true"

<forward name="success" path="/login_success.jsp"/>

<forward name="error" path="/login_error.jsp"/>

</action>

</action-mappings>

在一个web 项目中,每个资源都必须用URL来引用,资源包括:jsp,html,和制定动作。为了给制定动作一个URL,Struts提供了一个ActionMapping对象

(Struts中,ActionMapping继承自ActionConfig,大部份的属性定义实际上都已经在ActionConfig中完成,不过ActionMapping仍旧存在)。

当请求的URL是:http://127.0.0.1:8080/struts_login/login.do,则ActionServlet会将path设定为/login,

然后会根据 /login, 找到xml里的配置信息并读取 ,找到Actionmapping  对象。ActionMapping对象告知ActionServlet要使用“com.struts.LoginAction”,

而后ActionServlet会将呼叫LoginActionexecute()方法,并将ActionMapping对象当作参数传递给它。 

并接下来会根据 name=“loginForm”执行如下

Ps:(ActionServlet实际上将工作交给Action对象,然而Action对象的运作必须提供一些参数来描述工作的细节,诸如使用哪一个ActionFormforward对象的查找、错误发生时的页面对象等等,Struts将这些信息包装在ActionMapping中,并作为参数传送给Action对象,以使得Action在需要相关的信息时可以从ActionMapping中取得。 

 

---------------------------------------------------------------------------

    

3、ActionForm form = processActionForm(request, response, mapping);

实现代码:

 ActionForm instance = RequestUtils.createActionForm()//创建ActionForm

 if ("request".equals(mapping.getScope())) {

            request.setAttribute(mapping.getAttribute(), instance);

        } else {

            HttpSession session = request.getSession();

            session.setAttribute(mapping.getAttribute(), instance);

        }

        return (instance);

     ------------------------------

       1)public static ActionForm createActionForm()  

       实现代码:

       String attribute = mapping.getAttribute();

        if (attribute == null) {

            return (null);

        }

        String name = mapping.getName();

      

     //从<formbeans>中通过name取得对应的FormBeanConfig对象

        FormBeanConfig config = moduleConfig.findFormBeanConfig(name);

        if (config == null) {

            return (null);

      

      // 从Scope中取得ActionForm

      2)ActionForm instance = lookupActionForm(request, attribute,           

        mapping.getScope());

     实现代码:

       {if ("request".equals(scope)) {

            instance = (ActionForm) request.getAttribute(attribute);

        } else {

            session = request.getSession();

            instance = (ActionForm) session.getAttribute(attribute);

        }

        return (instance);}

        if (instance != null && canReuseActionForm(instance, config)) {

                return (instance);

            }

        return createActionForm(config, servlet);//反射方式生成ActionForm对象

可以看出创建ActionForm是通过单例模式来实现的。通过name=“LoginForm”,创建表单 "com.LoginActionForm"

----------------------------------------------------------------------------

/*

填充表单

*/

4、 processPopulate(request, response, form, mapping);

 实现代码:

  if (form == null) {

            return;

        }

 form.reset(mapping, request);//ActionForm初始化

 //ActionForm对象自动收集请求参数

  RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix()

                              request);

    ---------------------

    public static void populate()//自动收集请求参数

    实现代码:

    HashMap properties = new HashMap();

    Enumeration names = null; 

    names = request.getParameterNames();

    while (names.hasMoreElements()) {

            String name = (String) names.nextElement();

            String stripped = name;

   Object parameterValue = null;

   parameterValue = request.getParameterValues(name);

   properties.put(stripped, parameterValue);

   BeanUtils.populate(bean, properties);

   ----------------

   public static void populate(Object bean, Map properties)

   实现代码:

    if ((bean == null) || (properties == null)) {

            return;

    Iterator names = properties.keySet().iterator();//取得参数名

    while (names.hasNext()) {

            String name = (String) names.next();

            Object value = properties.get(name);

            setProperty(bean, name, value);

        }

//对ActionForm信息进行验证

if (!processValidate(request, response, form, mapping)) {

            return;

        }

 调用 processPopulate(request, response, form, mapping),将request里面的表单数据自动收集。

-----------------------------------------------------------------------------

//创建action对象

 protected HashMap actions = new HashMap(); //

5、Action action = processActionCreate(request, response, mapping);

代码实现:

protected Action processActionCreate(HttpServletRequest request,

                                         HttpServletResponse response,

                                         ActionMapping mapping)

  {String className = mapping.getType();

 Action instance = null;

        synchronized (actions) {

            instance = (Action) actions.get(className);

            if (instance != null) {

               return (instance);

            }

     instance = (Action) RequestUtils.applicationInstance(className);

     actions.put(className, instance);

     return (instance);

   }

action是通过单例加同步创建,高效安全。

并且在一个xml里面一个action标签对应一个action,一般有多个action标签 

将这些action 存到hashmap  actions 如上 。

-----------------------------------------------------------------------------

//执行Action

6、ActionForward forward= 

processActionPerform(request, response,action, form, mapping);

----------------------

代码实现:

protected ActionForward

        processActionPerform(HttpServletRequest request,

                             HttpServletResponse response,

                             Action action,

                             ActionForm form,

                             ActionMapping mapping)

        throws IOException, ServletException {

        try {

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

        } catch (Exception e) {

            return (processException(request, response,

                                     e, form, mapping));

        }

    }

 执行action的   Actionforward execute(request,response,mapping,form) 返回一个  Actionforward

----------------------------------------------------------------------------

7、processForwardConfig(request, response, forward);

-------------------  

代码实现:

protected void processForwardConfig(HttpServletRequest request,

                                        HttpServletResponse response,

                                        ForwardConfig forward)

        throws IOException, ServletException {

        if (forward == null) {

            return;

        }

    String forwardPath = forward.getPath();

     uri = forwardPath;

   if (forward.getRedirect()) {

           

            response.sendRedirect(response.encodeRedirectURL(uri));

   else {

            doForward(uri, request, response);

        }

代码实现:

protected void doForward(

        String uri,

        HttpServletRequest request,

        HttpServletResponse response)

        throws IOException, ServletException

{RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);

rd.forward(request, response);

 根据在xml action 标签 里的  forward的标签将跳转 ,整个登入结束。 

ps:如果没有在xml配置mapping 则会返回一个null。

 -----------------------------

原文地址:https://www.cnblogs.com/publicmain/p/7338077.html