一次请求的流程
一:接受请求
1.以.do结尾的URL被ActionServlet拦截,执行service方法
2.根据请求传递的方法GET/POST选择执行doGet()或doPost()方法
3.在doGet()/doPost()方法中,调用process()方法
二:process()方法
1. 选择模块
ModuleUtils.getInstance().selectModule(request, getServletContext())
根据request里的信息从servletContext里找到相应的子模块ModuleConfig,和它下面的MessageResources,并放到request里,使其他组件可以方便的供request里取得应用配置信息和消息资源.
根据请求URL和应用的所有模块名(这个模块名的集合在ActionServlet的初始化时放到ServletContext里),分析出请求对应的模块名。
根据这个模块名,从ServletContext里拿到对应的模块(ModuleConfig对象),放到request作用域里。
根据这个模块里的MessageResources配置信息,从ServletContext里拿到对应的MessageResources对象,放到request作用域里。
2、ModuleConfig config = getModuleConfig(request);
取出MoudleConfig实例config
3、获得模块对应的RequestProcessor ----RequestProcessor processor = getProcessorForModule(config);
根据config里这个子模块的信息,从servletcontext里,取出这个子模块的RequestProcessor实例 。
4、如果processor实例为空,就新建一个.同时放到servletcontext里
5、 调用RequestProcessor的process方法处理---- pro cessor.process(request, response)
5.1、 处理multipart请求------- request = processMultipart(request);
如果请求是POST的,并且其contentType属性值为multipart/form-data,将请求包装成MultipartRequestWrapper。
5.2、 处理请求路径-------processPath
将请求的URI掐头去尾,也就是将URI中的模块名和后缀名两部分去掉。如果路径为null,处理请求结束。
这里首先查询request.getattribute(include_path_info)中是否有这样的一个值,如果为空就调用
request.getpathinfo()方法获取path。如果这样还是获取不了,就从request.getattribute(include_servlet _path)
方法中获取path,找不到就使用request.getservlet path()得到的path进行分析。
分析过程如下:
然后如果这个path不是属于当前的moduleconfig的话,直接返回null。截取prefix后面的字符串,
如果这个字符串以.xx结尾,那么就截取"."前面的字符,比如
http://localhost:8080/servlet /where/go.do。where为module的名称(prefix),那么我们获取的 path值为/go。
5.3、 处理Locale------processLocale
如果Struts配置文件里controller元素的locale属性没有指定为false(默认为true),并且session里没有Locale的话,就从request里拿到Locale,放到session里。
它查找的顺序是:
moduleconfig.getcontrollerconfig().getlocale(),session.getattribute(globals.locale_key),request.getlocale()。
5.4、 处 理内容类型-------processContent
获得Struts配置文件里controller元素的contentType属性值(默认为text/html),将response的内容类型设置为该值。
这个contenttype是从moduleconfig.getcontrollerconfig().getcontenttype()获取的。
5.5、 处理no-cache headers-----processNoCache
如果Struts配置文件里controller元素的nocache属性指定为true(默认为false),设置response的相关header属性。
5.6、 预处理------processPreprocess
预处理request,这个方法是预留的,用户可以根据自己的需要加一些预处理的程序。
这里processPreprocess方法只有一句话:return(true);其实是为了可以扩展,如果要对请求预处理,可以继承这个类,然后重写这个
protected boolean processPreprocess(HttpServletRequest request,HttpServletResponse response) {
return (true);
}
5.7、 处 理缓存信息----processCachedMessages
在session里找名字为Globals.MESSAGE_KEY和Globals.ERROR_KEY的ActionMessages,如果有并且已经被访问过,就从session里删除它们。
5.8、 处理ActionMapping-------processMapping
请求的路径path为key从moduleconfig中查找actionmapping 对象。如果找到了,那么保存这个mapping到request中,key值为globals.mapping_key。如果不存在,那么遍历moduleconfig中所有的actionmapping,查找哪一个是缺省的actionmapping。然后把它保存到request中,key值为globals.mapping_key。
5.9、 处理角色权限--------processRoles
检查当前用户是否有权限执行这个请求。如果request.isuserinrole(roles[i])返回true,则代表有。
5.10、 处理ActionForm---------processActionForm
针对上面拿到的ActionMapping,根据它的name属性,查找对应的form-bean元素。
根据它的attribute和scope属性,在request或session里查找ActionForm,如果找到,还要对照刚才找到的form-bean元素,检查它们的类型是否匹配。如果没找到ActionForm或检查类型不匹配,就根据form-bean元素创建新的ActionForm。
根据scope属性,把ActionForm放到request或session里。
5.11、 填充ActionForm---------processPopulate
用请求参数填充对应的ActionForm属性。
5.12、 验证ActionForm--------processValidate
实际上就是调用ActionForm的validate()方法,如果validate()方法返回的ActionErrors不为空,表示没有通过验证,请求将转向到ActionMapping的input属性指定的路径。如果出现下面的情况之一将跳过这一步:
ActionForm为null;ActionMapping的validate属性指定为false;当前请求由点击“取消”按钮(即<html:cancel>)产生。
5.13、 处理Forward-----processForward
如果ActionMapping设置了forward属性值,请求将转向该属性指定的路径。
5.14、 处理include-------processInclude
如果ActionMapping设置了include属性值,请求将包含该属性指定的路径。
5.15、 获得Action对象-------processActionCreate
Action对象是ActionMapping的type属性指定类的实例。如果Action对象以前被访问过,可以直接获得该对象;如果没有被访问过,则创建新的Action对象。
5.16、 执行Action的execute()方法--------processActionPerform
这个execute()方法就是使用Struts的程序员最熟悉的那个方法。
5.17、 处理ActionForward------processForwardConfig
上面的execute()方法返回一个ActionForward对象,将请求转发或重定向到ActionForward的path属性指定的路径。
Come from:http://gemini.javaeye.com/category/8491?show_full=true