SSH框架之Struts(3)——Struts的执行流程之核心方法

  上篇讲了Tomcat实例化一个单例的ActionServlet。依据web.xml配置文件做好对应的初始化工作。

这时client产生一个.do结尾的request请求,採用get/post方式提交之后。不论哪种方式提交,都会进入到process核心方法中。

ActionServelt

 doGet()和doPost()方法

      public void <strong>doGet</strong>(HttpServletRequest request,	HttpServletResponse response)
	        throws IOException, ServletException {

	        <strong>process</strong>(request, response);

	    }

	    public void <strong>doPost</strong>(HttpServletRequest request,      HttpServletResponse response)
	        throws IOException, ServletException {

	        <strong>process</strong>(request, response);

	    }

 process方法

	    protected void process(HttpServletRequest request, HttpServletResponse response)
	        throws IOException, ServletException {

	        ModuleUtils.getInstance().selectModule(request, getServletContext());
	        ModuleConfig config = getModuleConfig(request);

	        RequestProcessor processor = getProcessorForModule(config);
	        if (processor == null) {
	           processor = getRequestProcessor(config);
	        }
	        processor.process(request, response);

	    }

  这种方法主要有两个作用:

  首先调用org.apache.struts.util.ModuleUtils类的selectModule()方法。这种方法依据请求对象和servletContext选择负责处理当前请求所属的模块。然后把与该模块相关的ModuleConfig和MessageResources对象存储倒request范围中,这使得框架的其余组件能够方便地从request范围中读取这些对象,从而获取应用配置信息和消息资源。

  其次, 实例化RequestProcessor类。然后调用RequestProcessor类的process()方法,来完毕十几的预处理请求操作。

RequestProcessor

 process()方法

public void process(HttpServletRequest request,                        HttpServletResponse response)
        throws IOException, ServletException {

        // Wrap multipart requests with a special wrapper
        request = processMultipart(request);

        // Identify the path component we will use to select a mapping
        String path = processPath(request, response);
        if (path == null) {
            return;
        }

        if (log.isDebugEnabled()) {
            log.debug("Processing a '" + request.getMethod() +
                      "' for path '" + path + "'");
        }

        // Select a Locale for the current user if requested
        processLocale(request, response);

        // Set the content type and no-caching headers if requested
        processContent(request, response);
        processNoCache(request, response);

        // General purpose preprocessing hook
        if (!processPreprocess(request, response)) {
            return;
        }

        this.processCachedMessages(request, response);

        // Identify the mapping for this request
        ActionMapping mapping = processMapping(request, response, path);
        if (mapping == null) {
            return;
        }

        // Check for any role required to perform this action
        if (!processRoles(request, response, mapping)) {
            return;
        }

        // Process any ActionForm bean related to this request
        ActionForm form = processActionForm(request, response, mapping);
        processPopulate(request, response, form, mapping);

        // Validate any fields of the ActionForm bean, if applicable
        try {
            if (!processValidate(request, response, form, mapping)) {
                return;
            }
        } catch (InvalidCancelException e) {
            ActionForward forward = processException(request, response, e, form, mapping);
            processForwardConfig(request, response, forward);
            return;
        } catch (IOException e) {
            throw e;
        } catch (ServletException e) {
            throw e;
        }

        // Process a forward or include specified by this mapping
        if (!processForward(request, response, mapping)) {
            return;
        }

        if (!processInclude(request, response, mapping)) {
            return;
        }

        // Create or acquire the Action instance to process this request
        Action action = processActionCreate(request, response, mapping);
        if (action == null) {
            return;
        }

        // Call the Action instance itself
        ActionForward forward =
            processActionPerform(request, response,
                                 action, form, mapping);

        // Process the returned ActionForward instance
        processForwardConfig(request, response, forward);

    }

依照process()方法的运行流程,

  一、processMultipart();

   1、首先推断是否为post方式。假设不是post方式,则肯定不是上传请求。则直接返回request对象

	if (!"POST".equalsIgnoreCase(request.getMethod())) {
		return (request);

        }

   2、获取request对象的ContentType,假设ContentType为multipart/form-datade 话则 new 一个 MultipartRequestWrapper 对象返回。

否则直接返回request。

 String contentType = request.getContentType();        if ((contentType != null)
            && contentType.startsWith("multipart/form-data")) {
            return (new MultipartRequestWrapper(request));
        } else {
            return (request);
        }

   这里简答的来说,是用来推断是否有上传功能的需求。假设有上传功能的需求。那么必须把form的contentType改为multipart/form-data。而这种方法就是来解析并打包成一个实现HttpServletRequest的包,为上传文件服务的。

  二、 processPath()

        String path = processPath(request, response);
        if (path == null) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("Processing a '" + request.getMethod() +
                      "' for path '" + path + "'");
        }

   通过调用processPath方法。获得訪问的详细action的名字

  三、processLocale()

protected void processLocale(HttpServletRequest request,HttpServletResponse response) {

	        // Are we configured to select the Locale automatically?

if (!moduleConfig.getControllerConfig().getLocale()) {
	            return;
	        }
	        // Has a Locale already been selected?
	        HttpSession session = request.getSession();
	        if (session.getAttribute(Globals.LOCALE_KEY) != null) {
	            return;
	        }
	        // Use the Locale returned by the servlet container (if any)
	        Locale locale = request.getLocale();
	        if (locale != null) {
	            if (log.isDebugEnabled()) {
	                log.debug(" Setting user locale '" + locale + "'");
	            }
	            session.setAttribute(Globals.LOCALE_KEY, locale);
	        }
	    }

   

   是本地服务还是国际化服务,这是依据浏览器的设置的(确切的说是依据操作系统设置的)

  四、processContent();processNoCache();

   当中processContent用来确定内容类型和编码类型

   processNoCache依据配置文件里的配置属性来确定某些内容是否进行缓存

  五、 processMapping()

   依据request。response和action的名字去Struts.config.xml中获取相应的actionmapping,也就是将我们配置好的request要请求的action放入到ActionMapping对象中去。

  1、首先去配置文件中找对应的配置信息

// Is there a mapping for this path?

ActionMapping mapping = (ActionMapping) moduleConfig.findActionConfig(path);

  2、假设有配置则把它放入request。并返回。

        // If a mapping is found, put it in the request and return it
        if (mapping != null) {
            request.setAttribute(Globals.MAPPING_KEY, mapping);
            return (mapping);
        }

  3、找到“未知的映射路径(假设有的话)”。相同找到了就放到request里并返回他。

        // Locate the mapping for unknown paths (if any)
        ActionConfig[] configs = moduleConfig.findActionConfigs();
        for (int i = 0; i < configs.length; i++) {
            if (configs[i].getUnknown()) {
                mapping = (ActionMapping) configs[i];
                request.setAttribute(Globals.MAPPING_KEY, mapping);
                return (mapping);
            }

        }

  4、假设还是没有找到mapping信息则发送错误消息。并返回null

        // No mapping can be found to process this request
        String msg = getInternal().getMessage("processInvalid");
        log.error(msg + " " + path);
        response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);

        return null;

  此时。ActionMapping元素包括了如Action类的名称及在请求中用到的ActionForm的信息,另外还有配置在当前ActionMapping的里的ActionForwards信息。

  六、processActionForm()

	 protected ActionForm processActionForm(HttpServletRequest request,
	                                           HttpServletResponse response,
	                                           ActionMapping mapping) {

	        // Create (if necessary) a form bean to use
	        ActionForm instance = RequestUtils.createActionForm
	            (request, mapping, moduleConfig, servlet);
	        if (instance == null) {
	            return (null);
	        }

	        // Store the new instance in the appropriate scope
	        if (log.isDebugEnabled()) {
	            log.debug(" Storing ActionForm bean instance in scope '" +
	                mapping.getScope() + "' under attribute key '" +
	                mapping.getAttribute() + "'");
	        }
	        if ("request".equals(mapping.getScope())) {
	            request.setAttribute(mapping.getAttribute(), instance);
	        } else {
	            HttpSession session = request.getSession();
	            session.setAttribute(mapping.getAttribute(), instance);
	        }
	        return (instance);

	    }

   查看mapping里是否配置name属性或attribute属性来指定ActionForm,假设配置了ActionForm就到session或是Request中进行查找,查到后进行返回;假设没有找到。依据ActionForm的路径进行创建并放入到scope域中。

  七、processPopulate()

 protected void processPopulate(HttpServletRequest request,
                                   HttpServletResponse response,
                                   ActionForm form,
                                   ActionMapping mapping)
        throws ServletException {

        if (form == null) {
            return;
        }
        // Populate the bean properties of this ActionForm instance
        if (log.isDebugEnabled()) {
            log.debug(" Populating bean properties from this request");
        }
        form.setServlet(this.servlet);
        form.reset(mapping, request);

        if (mapping.getMultipartClass() != null) {
            request.setAttribute(Globals.MULTIPART_KEY,
                                 mapping.getMultipartClass());
        }
        RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(),
                              request);

        // Set the cancellation request attribute if appropriate
        if ((request.getParameter(Constants.CANCEL_PROPERTY) != null) ||
            (request.getParameter(Constants.CANCEL_PROPERTY_X) != null)) {
            request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
        }
    }

   这种方法主要是用来为ActionForm 填充数据,运行ActionForm的reset重置方法,之后获取到表单全部输入域的名称。依据request.getParameter获取输入域名称所相应的值,然后将输入域名称和值以键值对形式放入到map中,之后调用一个比較重要的第三方组件BeanUtils来实现属性的转换和拷贝到详细的ActionForm中

  八、processValidate()

   验证表单数据合法性,这个可用可不用的。假设使用了Struts的验证,这里会自己主动的运行该方法进行验证。

  九、processForward()

   处理mapping指定的forward 和 include,Struts检查<action>元素的forward和include属性的值。假如有配置。则把forward和include 请求放在配置的页面内,之后转发到详细的ActionServlet中进行详细业务逻辑的处理。

小结

  至此,RequestProcessor的核心方法process运行完成。之后会到详细的Action中运行业务相关的操作。

纵观整个运行流程,其基本的方法无外乎两个,一个是AcionServlet中的process方法,还有一个是RequestProcessor的process()方法,至于其它的截取请求路径,填充actionForm。国际化等方法也都被用于外观模式封装在了process方法中。

时间: 2024-10-17 10:43:01

SSH框架之Struts(3)——Struts的执行流程之核心方法的相关文章

SSH 框架打开项目自动执行action的一种方法

web.xml不配置任何东西 <welcome-file-list> <welcome-file></welcome-file> </welcome-file-list></span> 如上,为什么不把<welcome-file></welcome-file>也出掉,因为出掉之后会提示标签不完整. struts.xml如下 <action name="" class="index&quo

SSH 框架打开项目自动执行action的第二种方法

web.xml还是什么不配置 <welcome-file-list> <welcome-file></welcome-file> </welcome-file-list> struts.xml加上这个 <default-action-ref name="index" /> 同时原来的修改为这样 <action name="index" class="index"> <r

利用SSH框架开发时遇到的各种Bug及解决方法

1.hibernate自动生成的配置文件 hibernate.cfg.xml 有时候是有问题的,会出现 org.hibernate.HibernateException: Could not parse configuration: /hibernate.cfg.xml 原因是自动生成的hibernate.cfg.xml第二个标签引号内容的最末尾有一个空格,删掉即可 <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hiberna

SSH框架与Action/Service/Dao功能划分介绍

1. Action/Service/Dao简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. DAO只完成增删改查,虽然可以1-n,n-n,1-1关联,模糊.动态.子查询都可以.但是无论多么复杂的查询,dao只是封装增删改查.至于增删查改如何去实现一个功能,dao是不管的. 现在最基本的分层方式,结合了SSH架构: Model层就是对应的数据库表的实体类. Dao层是使用了Hibernate连接数据库.操作数据库(增删改查). Service层

SSH框架分模块开发

------------------siwuxie095 SSH 框架分模块开发 1.在 Spring 核心配置文件中配置多个内容,容易造成 配置混乱,不利于维护 「分模块开发主要针对 Spring 核心配置文件」 2.把 Spring 核心配置文件中的一部分配置放到单独的 配置文件中,再在 Spring 核心配置文件中引入单独的配 置文件即可 3.一般情况下,建议把 Action 对象的配置放到单独的 配置文件中 「因为其它的配置基本不变,只有 Action 对象的配置在 不断重复」 如: u

SSH框架--struts深入详解(一)

学习了struts,但是对于它的由来,以及为什么使用action和struts.xml的方式而不采用以前的servlet方式,有些疑问,到底之前的方式有什么弊端,struts又给我们带来了什么便利? 下面一一为大家解答! struts的由来: 随着JSP与Servlet 技术大量应用于以Web为基础的应用程序,为了提升Web 应用程序可维护性与重复使用性,Java开发人员提出了一些较佳的开发模式.比较常见的两种JSP应用架构分别为Model1 与Model 2.详情参见(JAVA学习篇--JAV

Eclipse下面的Maven管理的SSH框架整合(Struts,Spring,Hibernate)

搭建的环境:eclispe下面的maven web项目 Struts:    2.5.10 Spring:    4.3.8 Hibernate:   5.1.7 .Final MySQL:   5.1.30 先来详细的讲解一下SSH框架的整合,在这里是将struts2.0的Action的创建工作由Spring进行统一管理,主要是利用了Spring 控制反转和依赖注入的功能. 而将hibernate.cfg.xml整合Spring的配置文件中.而且利用Spring的面向切向功能对Hibernat

spring+springMvc+struts的SSH框架整合

1.建立一个web项目 2.导入SSH框架所需jar包 3.配置web.xml文件 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation=&

SSH框架之Struts(1)——Struts的运行流程

对于采用Struts框架的Web应用,我们通过实例来介绍一下其基本流程. 一.实例 Login.jsp,进行系统登录的页面 <form action="login.do" method="post"> 用户:<input type="text" name="username"><br> 密码:<input type="password" name="pas