首先斷點走出了processpath方法,
這個方法是用來截取字符串的,今天我們來看怎樣獲得actionmapping的方法---processmapping。
在此之前簡單說一下actionmapping,它的源代碼中可以看出,其中最重要的屬性和我們的mvc小實例中的actionmapping類似,都是有path、type還有forwardmap,主要是對應的struts-config配置文件而來,這個就是保存這個配置文件的信息到內存中。
具體的mvc小實例的actionmapping代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
package com.cjq.servlet; import java.util.map; public class actionmapping { private string path; private object type; private map forwardmap; public string getpath() { return path; } public void setpath(string path) { this .path = path; } public object gettype() { return type; } public void settype(object type) { this .type = type; } public map getforwardmap() { return forwardmap; } public void setforwardmap(map forwardmap) { this .forwardmap = forwardmap; } } |
而struts中的actionconfig(因為actionmapping是繼承這個actionconfig的,所以我們來看actionconfig更加直接)的代碼如下:
從這兩部分代碼來看,更加印證了我在開篇寫的mvc小實例是一個struts框架的雛形。
講完actionmapping的一些內容后,相信對actionmapping有所了解,那么系統是如何生成actionmapping和如何找到actionmapping的呢?這就是今天要說的整體:
我們看下web.xml中有一個<load-on-startup>2</load-on-startup> 配置信息,這個信息就是說明了但服務器已啟動就動態讀取struts-config配置文件把配置文件的信息put到actionmapping中。所以當我們運行服務器的時候,我們在內存中已經存在對應struts-config配置文件信息對應的actionmapping。今天就是要通過processmapping讀取這個actionmapping類。
進入斷點調試,首先在processmapping方法上設置斷點。
進入源代碼中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
/** * <p>select the mapping used to process theselection path for this request * if no mapping can be identified, createan error response and return * <code>null</code>.</p> * * @param request the servlet request weare processing * @param response the servlet response weare creating * @param path the portion of the requesturi for selecting a mapping * * @exception ioexception if an input/outputerror occurs */ protectedactionmapping processmapping(httpservletrequestrequest, httpservletresponse response, string path) throws ioexception { // is there a mapping for this path? actionmapping mapping = (actionmapping) moduleconfig.findactionconfig(path); // if a mapping is found, put it in the request and return it if (mapping != null ) { request.setattribute(globals.mapping_key, mapping); return (mapping); } // 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); } } // 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 ; } |
首先我們傳入我們在上一步截取的路徑,通過moduleconfig的findaction方法來查找actionconfig,并且返回actionmapping。具體代碼是:
1
2
|
actionmapping mapping =(actionmapping) moduleconfig.findactionconfig(path); |
如果找到,那么就講actionmapping存放到request的context中。代碼:
1
2
3
4
|
if (mapping != null ) { request.setattribute(globals.mapping_key, mapping); return (mapping); } |
如果沒有通過path找到mapping,則在actionconfig中遍歷為未知路徑尋找mapping,如果找到則存放到request中,如果沒有找到,則返回錯誤信息,具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// locate the mapping for unknownpaths (if any) actionconfig configs[] = moduleconfigfindactionconfigs(); for ( int i = 0 ; i < configslength; i++) { if (configs[i].getunknown()) { mapping = (actionmapping)configs[i]; request.setattribute(globals.mapping_key, mapping); return (mapping); } } // 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 ; |
來看下actionservlet中的一個方法processactionform,當我們在截取字符串,再根據字符串取得actionmapping(這是前兩篇文章中介紹的)之后,我們就要用利用actionmapping來創建actionform了,并且把actionform放到request或session中管理。
先來看具體struts中processactionform方法的具體實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
/** * <p>retrieve and return the <code>actionform</code> associatedwith * this mapping, creating and retaining oneif necessary. if there is no * <code>actionform</code> associated with this mapping,return * <code>null</code>.</p> * * @param request the servlet request weare processing * @param response the servlet response weare creating * @param mapping the mapping we are using */ protectedactionform processactionform(httpservletrequestrequest, httpservletresponse response, actionmapping mapping) { // create (if necessary) a form bean to use actionform instance = requestutilscreateactionform (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 =requestgetsession(); session.setattribute(mapping.getattribute(), instance); } return (instance); } |
這個方法的大體流程是:根據actionmapping中的name名稱查找actionform,如果配置了actionform,那么就到request或session中查找,如果在request或session中存在已經創建的actionform,那么將返回。如果不存在那么會根據actionform的完成路徑采用反射進行創建,再將創建好的actionform放到request或session中,之后返回actionform。
具體我們可以跟隨斷點調試來看看這個方法是如何運行的。
先設置斷點,之后進入processactionform方法。
第一個步驟就是創建actionform:
1
2
3
4
5
6
7
8
9
10
11
|
// create (if necessary) a formbean to use actionform instance = requestutils.createactionform (request, mapping, moduleconfig, servlet); if (instance == null ) { return ( null ); } |
通過調用requestutils.createactionform的方法把actionmapping中的actionform字符串生成對象,并且返回。進入這段代碼中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
publicstaticactionform createactionform( httpservletrequest request, actionmapping mapping, moduleconfig moduleconfig, actionservlet servlet) { // is there a form bean associated with this mapping? string attribute = mappinggetattribute(); if (attribute == null ) { return ( null ); } // look up the form bean configuration information to use string name = mapping.getname(); formbeanconfig config =moduleconfigfindformbeanconfig(name); if (config == null ) { log.warn( "no formbeanconfig found under '" + name + "'" ); return ( null ); } actionform instance = lookupactionform(request,attribute, mappinggetscope()); // can we recycle the existing form bean instance (if there is one)? try { if (instance != null && canreuseactionform(instance,config)) { return (instance); } } catch (classnotfoundexception e) { log.error(servlet.getinternal().getmessage( "formbean" ,config.gettype()), e); return ( null ); } return createactionform(config,servlet); } |
方法首先定義變量name,并且從mapping中獲取值,string name = mapping.getname();也就是我們實例中的loginform字符串。之后通過調用formbeanconfig config =moduleconfig.findformbeanconfig(name);這句話把相應的loginform字符串生成相應的對象。
這里要說明的是我們在struts-config配置文件中,配置過這樣一個標簽信息:
1
2
3
4
5
|
<form-beans> <form-bean name= "loginform" type= ".struts.loginactionform" /> </form-beans> |
這個標簽在服務器一啟動的時候就會利用digester讀取這里的配置信息,并且放在formbeanconfig類中,這樣我們可以通過上面那一句話就可以把loginform字符串生成相應的對象。
之后調用了actionform instance = lookupactionform(request,attribute, mapping.getscope());這個方法,這個方法主要是查找scope屬性中有沒有存在actionform。具體實現:
1
2
3
4
5
6
7
8
9
10
11
|
if ( "request" .equals(scope)){ instance = (actionform)request.getattribute(attribute); } else { session = request.getsession(); instance = (actionform)session.getattribute(attribute); } |
這里判斷scope屬性值是否為request,如果是則從request中讀出actionform,如果不是則從session中讀出。程序如果是第一次執行,那么actionform會是為空的。因為這里的actionform為空,所以就進入了if判斷語句中,最后通過調用return createactionform(config, servlet);創建actionform并且返回。
之后processactionform就會把返回來的actionform放入request或者session中。具體實現就是:
1
2
3
4
5
6
7
8
9
10
11
|
if ( "request" .equals(mapping.getscope())){ request.setattribute(mapping.getattribute(), instance); } else { httpsession session =request.getsession(); session.setattribute(mapping.getattribute(), instance); } |
到此為止,actionform就創建完成,當actionform創建完成之后,就要用其他的方法來往actionform中賦值了