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

  上篇讲了Tomcat实例化一个单例的ActionServlet,根据web.xml配置文件做好相应的初始化工作。这时客户端产生一个.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方法中。



评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值