上篇讲了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方法中。

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

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

    .hibernate自动生成的配置文件 hibernate.cfg.xml 有时候是有问题的,会出现 org.hibernate.HibernateException: Could not parse ...

  2. SSH框架之Struts(4)——Struts查漏补缺BeanUtils在Struts1中

    在上篇博客SSH框架之Struts(3)--Struts的执行流程之核心方法,我们提到RequestProcessor中的processPopulate()是用来为为ActionForm 填充数据.它 ...

  3. SSH 框架学习之初识Java中的Action、Dao、Service、Model-收藏

    SSH 框架学习之初识Java中的Action.Dao.Service.Model-----------------------------学到就要查,自己动手动脑!!!   基础知识目前不够,有感性 ...

  4. 用一天的时间学习Java EE中的SSH框架

    首先说明一下,本人目前主要从事.NET领域的工作,但对于C++.Java.OC等语言也略知一二,周末闲来无事,特花费一天的时间学习了一下Java中的SSH框架,希望把学习过程中的心得体会与园友们进行分 ...

  5. 说说你对用SSH框架进行开发的理解

    SSH框架指的是Struts,Spring,Hibernate.其中,Struts主要用于流程控制:Spring的控制反转能祈祷解耦合的作用:Hibernate主要用于数据持久化.

  6. SSM框架和SSH框架的区别

    SSH和SSM定义 SSH 通常指的是 Struts2 做控制器(controller),spring 管理各层的组件,hibernate 负责持久化层. SSM 则指的是 SpringMVC 做控制 ...

  7. 基于SSH框架开发的《高校大学生选课系统》的质量属性的实现

    基于SSH框架开发的<高校大学生选课系统>的质量属性的实现 对于可用性采取的是错误预防战术,即阻止错误演变为故障:在本系统主要体现在以下两个方面:(1)对于学生登录模块,由于初次登陆,学生 ...

  8. SSH框架分模块开发

    ------------------siwuxie095 SSH 框架分模块开发 1.在 Spring 核心配置文件中配置多个内容,容易造成 配置混乱,不利于维护 「分模块开发主要针对 Spring ...

  9. javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之一 基础Struts框架搭建篇

    即将开始着手写这个项目,所以希望通过这篇博客来记录自己学习的过程 今天开学第一天,就上了软件工程实践课,自己也开始着手做这个大作业了.首先我的项目名称叫做智能班车管理系统. 项目的概况: 该软件产品是 ...

随机推荐

  1. Vue 页面回退参数被当作字符串处理

    当时情景是这样的,我从A页面跳到B页面时会传一个Boolean类型的参数,当B跳到C,再从C返回B的时候,控制台打印发现参数还在,可是判断怎么都不起作用,后来发现,当页面返回的时候,默认将参数变成了字 ...

  2. skiing 暴力搜索 + 动态规划

    我的代码上去就是 直接纯粹的  暴力  .   居然没有超时   200ms  可能数据比较小   一会在优化 #include<stdio.h> #include<string.h ...

  3. 【转】DOS与linux的断行字符

    转自:http://www.2cto.com/os/201109/104833.html 今天配置linux的dns服务器,在配置的时候,在linux下修改配置文件感觉很麻烦,于是想到把配置文件拿到w ...

  4. 一键生成Spring MVC + MyBatis + maven项目

    首先创建一个新的maven项目,在src/main/java创建一个类Test 然后在Test复制以下代码: import java.io.*; import java.sql.Connection; ...

  5. ios9-NSLayoutAnchor和UILayoutGuide实现自动布局

    @interface ViewController () { NSLayoutConstraint *yellowViewTopConstraint; NSLayoutConstraint *blue ...

  6. Redux 基础概念

    Redux is a predictable state container for JavaScript apps.,亦即 Redux 希望能提供一个可以预测的 state 管理容器,让开发者可以可 ...

  7. DeltaFish 校园物资共享平台 第七次小组会议

    DeltaFish 校园物资共享平台 第七次小组会议 一.上周进度报告 前端 娄:和李一起建立前后端交互参数文档,和数据库文档,完成前端页面跳转和图片加载的 bug,Git 上去. 刘:优化前端 ab ...

  8. .net 大数据量,查找Where优化(List的Contains与Dictionary的ContainsKey的比较)

    最近优化一个where查询条件,查询时间很慢,改为用Dictionary就很快了.  一.样例 假设:listPicsTemp 有100w条数据,pictures有1000w条数据. 使用第1段代码执 ...

  9. Centos7搭建lamp环境

    首先安装apache Centos7默认已经安装httpd服务,只是没有启动. 如果需要重新安装,输入 yum install -y httpd 启动服务: systemctl start httpd ...

  10. python函数参数的区别

    在运用python的过程中,发现当函数参数为list的时候,在函数内部调用list.append()会改变形参,与C/C++的不太一样,查阅相关资料,在这里记录一下. python中id可以获取对象的 ...