When accessing a menu link in struts2, we only need to combine the corresponding package namespace with the name of the action, and with the corresponding suffix, we can directly access the corresponding action, then how this process is done, multiple identical namespaces How the package satisfies non-conflicting, it requires a detailed understanding of how the path information is parsed in STRUTS2 and the corresponding action configuration based on the access path.
The whole process can be dealt with in the following steps
- Parse the XML to save all the path information that can be accessed
- Depending on the access request information, take the path that is available in it
- Search by path and finally find the action we need
Parsing xml
First we know that a package and action are configured as follows:
1 2 3 4 5 |
<package name= "PackageName" extends= "Struts-default" namespace= "/" > <action name= "logic" class= "detailaction" method= "init" > <result name= "Success" >/jsp/success.jsp</result> </action> </package> |
This includes the package name, namespace, and the name of the action. Then we can organize this series of information through a similar Packageconfig object. This is the packageconfig used inside the struts2. Let's look at its simple definition:
1 2 3 4 |
Protected map<string, actionconfig> actionconfigs; ...... protected String name; Protected String namespace = ""; |
This includes the package name we know, the namespace, and a map with the action name and each action configuration. So, the whole project has a lot of package,struts how to deal with it, it will need to use the name space in this area.
We can take the namespace as a key and then save all the action configurations in each package as value, then use key to represent the namespace, and the action configuration as value, where the configuration of the action is once again map, Use the following data structures to define the store.
1 |
Map<string, map<string, actionconfig>> namespaceactionconfigs = new linkedhashmap<string, Map< String, actionconfig>> (); |
Double-map, the first key represents the namespace, the second key represents the name of the action, the path, and the final value is the corresponding information for each action, which is for one of the following paths:
1 |
/contextpath/Module name/function name/action name/action. Action |
We only need to remove the context and the subsequent. Action, the remaining/module name/function name/action/action, which is actually a combination of a namespace and an action path. We only need to follow the/delimiter to find in the map. If there is a package information with the module name namespace, we can directly define to the second map and then directly match to the corresponding action using the key function name/action name/operation.
Then the whole construction of the data structure is in the method Buildruntimeconfiguration of Class Defaultconfiguration, as follows:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 |
Map<string, map<string, actionconfig>> namespaceactionconfigs = new linkedhashmap<string, Map< String, actionconfig>> (); map<string, string> namespaceconfigs = new linkedhashmap<string, string> (); This is done by looping through each package, and then into the map For (Packageconfig packageConfig:packageContexts.values ()) { String namespace = Packageconfig.getnamespace (); map<string, actionconfig> configs = Namespaceactionconfigs.get (namespace); map<string, actionconfig> actionconfigs = Packageconfig.getallactionconfigs (); For (Object O:actionconfigs.keyset ()) { String actionname = (string) o; Here we first get the set information that was originally placed in the big map. Actionconfig baseconfig = Actionconfigs.get (ActionName); This is where the action configuration in the current package is then merged into the larger map based on the namespace Configs.put (ActionName, Buildfullactionconfig (Packageconfig, baseconfig)); } Namespaceactionconfigs.put (namespace, configs); } } return new Runtimeconfigurationimpl (Namespaceactionconfigs, namespaceconfigs); |
Parse Action Information
The next step is to find the action, and when a request arrives, Struts2 first to know which action is capable of handling the request, and if there are no requests to process, an error or other hint. First, we know that this lookup process must first remove all the information before the context, followed by removing the suffix, leaving only the middle of the string with the namespace and the action name, and then looking. The description of the process is performed in the method GetMapping of the class Defaultactionmapper, as follows:
" " , , , , , , |
Actionmapping mapping = new actionmapping (); //This step goes to header and context string uri = geturi (request); //This step to the semicolon and all subsequent information int indexofsemicolon = uri.indexof (";"); uri = (indexofsemicolon > -1) ? uri.substring (0, indexofsemicolon) : uri; //This step goes to all subsequent and later information, such as. Action uri = dropextension (uri, mapping); //This step is a true discovery process parsenameandnamespace (Uri, mapping, configmanager ); |
The exact process of finding is related to the organization of the entire path, and the entire implementation can be determined by the following steps.
- by/In reverse lookup, if not, the namespace is considered "" and the entire path is the action name
- If in the 1th position, that is, the/start, the namespace is considered/, followed by the action name
- Otherwise, full namespace search is configured, that is, greedy search, that is, all/previous is the namespace, followed by the action name
- Otherwise, all of the first steps in the map to make the longest match, that is, the longest match to the namespace is what we want, followed by the action name
- Finally, if there is no/in the configured action path, the entire action path is removed, and the last not included/is the action name
In the above steps, 1,2,3,4 is the lookup process, and the last 5th step is the process. The entire implementation logic is consistent with the above, as shown below:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
String namespace, name; int lastslash = Uri.lastindexof ("/"); This is the 1th step, that is, when there is no context, the entire path does not/ if (Lastslash = =-1) { namespace = ""; name = URI; The 2nd step, that is, when there is a namespace of/, or "", then/that is, the 1th bit } else if (Lastslash = = 0) { ww-1046, assume it is the root namespace, it'll fallback to Default Namespace anyway if not found in root namespace. namespace = "/"; Name = uri.substring (Lastslash + 1); 3rd step, if greedy search, then the longest path is the namespace } else if (alwaysselectfullnamespace) { Simply Select the namespace as everything before the last slash namespace = uri.substring (0, Lastslash); Name = uri.substring (Lastslash + 1); 4th step, longest match search } else { Try to find the namespace in those defined, defaulting to "" Configuration config = configmanager.getconfiguration (); String prefix = uri.substring (0, Lastslash); namespace = ""; Find the longest matching namespace, defaulting to the default For (Object cfg:config.getPackageConfigs (). values ()) { String ns = ((packageconfig) cfg). GetNamespace (); if (ns! = NULL && prefix.startswith (NS) && (prefix.length () = = Ns.length () | | Prefix.charat (ns.length ()) = = '/')) { This is to determine whether the longest, otherwise the lookup will be replaced with a longer if (Ns.length () > Namespace.length ()) { namespace = ns; } } } Name = Uri.substring (namespace.length () + 1); } This is the 5th step, for the action name processing if (!allowslashesinactionnames && name! = null) { int pos = Name.lastindexof ('/'); if (pos >-1 && pos < Name.length ()-1) { Name = name.substring (pos + 1); } } |
This completes the lookup process, but here is only a lookup, not a final match, because there is also the process of mapping to the final action object based on how the found match results are mapped to actionconfig.
Map Actionconfig
The entire mapping process can be divided into the following steps
- First, the lookup is based on the default match, and if it can be found, it is considered the final actionconfig, where the action name is also pattern-matched
- Otherwise, the namespace is matched with an * number, and a pattern match is attempted
- Finally, try to find using the default empty namespace
1 is the first to find the corresponding sub-map according to the namespace, that is, the collection of ActionName and Actionconfig, and then find in the sub-map, if not found in the child map, then use pattern matching. If you can't find it, go to step 2.
2 at Step 2 o'clock, you will first use pattern matching to find the corresponding namespace, and if you have a matching namespace, repeat the first step again with that namespace
3 not found yet, use the default namespace as "" to find
The entire implementation is in the Getactionconfig method of the class Defaultactionmapper, as follows:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21st 22 23 24 25 26 |
Use the first step to match Actionconfig config = findactionconfiginnamespace (namespace, name); Pattern matching for namespaces using the second step Try Wildcarded namespaces if (config = = null) { Namespacematch match = Namespacematcher.match (namespace); if (match! = null) { Config = Findactionconfiginnamespace (Match.getpattern (), name); If Config found, place all the matches found in the namespace processing in the action ' s parameters if (config! = null) { Config = new Actionconfig.builder (config) . Addparams (Match.getvariables ()) . build (); } } } Use the default match for step 3rd Fail over to empty namespace if (config = = null) && (Namespace! = null) && (! "". Equals (Namespace.trim ()))) { Config = Findactionconfiginnamespace ("", name); } return config; |
At this point, the entire positioning process is complete. If the Actionconfig object is still not found here, then the corresponding exception is thrown directly, that is, the common
There is no Action mapped for namespace {0} and action name {1}.
There is no action mapped for action name {0}.
Reprint please indicate source: I Flym
This address: http://www.iflym.com/index.php/code/201302270001.html
How to navigate to the detailed access action based on the request path in STRUTS2