• 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方法中。



  • 相关阅读:
    C# Winform 运行异常 CefSharp.core.dll 找不到指定的模块
    WCF TCP通信方式 通过IIS承载调试
    [译]Modern Core Graphics with Swift系列
    博客搬家
    [ios] 定位报错Error Domain=kCLErrorDomain Code=0 "The operation couldn’t be completed. (kCLErrorDomain error 0.)"
    [IOS] 'Double' is not convertible to 'CGFloat'
    [IOS]swift 使用AVOS的API
    [IOS]使用了cocoapods 抱错Pods was rejected as an implicit dependency for ‘libPods.a’ because its architectures ......
    [IOS]cocoapos 两个ruby源的对比
    [IOS]Swift 遍历预制的本地资源文件
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7130344.html
Copyright © 2020-2023  润新知