ActionContext
ActionContext is the context of Action, where Struts2 automatically saves some objects required during Action execution, such as session, parameters, locale, etc. Struts2 will create the corresponding ActionContext based on each thread that executes the HTTP request, that is, a thread has a unique ActionContext. Therefore, users can use the static method ActionContext.getContext() to obtain the ActionContext of the current thread. It is precisely for this reason that users do not have to worry about making Action thread-safe.
In any case, ActionContext is used to store data. Struts2 itself will put a lot of data in it, and users can also put the data they want. The data structure of ActionContext itself is a mapping structure, that is, a map, which uses a key to map value. So users can use it like using Map, or directly use the Action.getContextMap() method to operate on the Map.
The data placed in Struts2 itself include ActionInvocation, application (i.e. ServletContext), conversionErrors, Locale, action name, request parameters, HTTP Session and value stack, etc. For a complete list, please refer to its Javadoc (the appendix of this article discusses what it contains).
Due to the characteristics that can be obtained by thread-only and static methods of ActionContext, it can be obtained directly in non-Action classes without waiting for Action to be passed or injected. It should be noted that it is only valid in threads created due to request (because the corresponding ActionContext is created when requesting), but is invalid in threads started by the server (such as fliter's init method). Due to the convenience of accessing it in non-Action classes, ActionContext can also be used to pass data to JSP in non-Action classes (because JSP can also easily access it).
The connection and difference between ValueStack and ActionContext:
Similarities: They are all used within the scope of an HTTP request, i.e. their lifetime is one request.
Differences: The value stack is the structure of the stack, and ActionContext is the structure of the map (Map).
Contact: The Map obtained by the ValueStack.getContext() method is actually the Map of ActionContext. Looking at the source code of Struts2, we can see (line 79 of org.apache.struts2.dispatcher.ng.PrepareOperations in Struts2.3.1.2, createActionContext method). When creating ActionContext, ValueStack.getContext() is used as a parameter of the constructor of ActionContext. So, ValueStack and ActionContext can essentially be obtained from each other.
Note: In some documents, the word "stack's context" will appear, which is actually the value being saved into ActionContext. So when reading these documents, you must see clearly whether the stack structure (i.e. value stack) is placed or the mapping structure (the context of the value stack, that is, ActionContext).
How to get ActionContext:
In a custom interceptor: use ActionInvocation.getInvocationContext() or use ActionContext.getContext().
In Action class: let the interceptor inject or use ActionContext.getContext().
In non-Action classes: let the Action class pass parameters, inject using the injection mechanism, or use ActionContext.getContext(). Note: ActionContext.getContext() can only be called by code running in the request thread, otherwise null is returned.
In JSP: Generally, there is no need to obtain the ActionContext itself.
How to save a value into an ActionContext:
In Java classes such as interceptor, Action class, non-Action class, etc.: Use ActionContext.put(Object key, Object value) method.
In JSP: the tag <s:set value="..."/> will store the value in ActionContext by default (of course, the <s:set> tag can also store the value in other places). In addition, many tags have var attributes (the id attribute was used before, but now the id attribute has been deprecated). This attribute can store a value into the ActionContext, the key is the value of the var attribute, and the value is the value of the tag's value attribute. (Some documents write about storing values into the context of ValueStack, which is actually the same)
How to read a value from an ActionContext:
In Java classes such as interceptor, Action class, non-Action class, etc.: Use the ActionContext.get(Object key) method.
In JSP: Use an Ognl expression starting with #, for example, the ActionContext.get("name") method will be called. Note: If the attributes of a certain tag are not parsed as Ognl expressions by default, you need to use %{} to enclose the expression, and an expression similar to "%{#name}" will appear. (See more for "#" here)
In short, using ActionContext in JSP is because it is a mapping structure, and on the other hand, it can read some configurations of Action. When you need to provide common values for many Actions, you can have each Action provide the getXXX() method, but a better way is to store these common values in the ActionContext in the interceptor or JSP template (because interceptor or JSP template is often used for multiple Actions).
Some examples:
Java code
// This class will demonstrate the operation on ActionContext in the interceptor publicclass MyInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { // Get ActionContext ActionContext actionContext = invocation.getInvocationContext(); // Save the value Person person = new Person(); actionContext.put("person", person); // Get the value Object value = actionContext.get("person"); // Get HttpServletRequest HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); // Get the Map of the request, that is, the value operated by HttpServletRequest.getAttribute(...) and HttpServletRequest.setAttribute(...) Map requestMap = (Map) actionContext.get("request"); // Other codes// ...... return invocation.invoke(); } } Java code
// This class will demonstrate the operation of ActionContext in Action publicclass MyAction extends ActionSupport { @Override public String execute() throws Exception { // Get the value stack ActionContext actionContext = ActionContext.getContext(); // Save the value Person person = new Person();// This is the class defined in the previous example actionContext.put("person", person); // Get the value Object object = actionContext.get("person"); // Other codes// ...... return SUCCESS; } } Html code
<!DOCTYPE html> <html> <head> <metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <!-- This JSP will demonstrate the use of ActionContext in JSP --> <!-- This JSP is the JSP corresponding to MyAction --> <!-- Since the value of the ActionContext has been stored in the ActionContext, you can use "#person" to get it, as follows --> <s:propertyvalue="#person"/> <!-- Get the name attribute of the person, as follows --> <s:propertyvalue="#person.name"/> <!-- Get the value stored by Struts2 in ActionContext, such as the Map of request, as follows --> <s:propertyvalue="#request"/> <!-- Get the value stored by Struts2 in ActionContext, such as the Map of session, as follows --> <s:propertyvalue="#session"/> <!-- Get the value stored by Struts2 in ActionContext, request the map of the passed GET parameter or POST parameter, as follows --> <s:propertyvalue="#parameters"/> <!-- The following demonstrates saving the value in ActionContext in JSP--> <!-- Save a string "myName", the key is "myKey", as follows --> <s:setvalue="%{'myName'}"var="myKey"/> <!-- Use the s:bean tag to create an object and save it in ActionContext, the key is myObject, as follows --> <s:beanname="com.example.Person"var="myObject"/> <!-- After that, you can use "#" to read them, as follows --> <s:propertyvalue="#myKey"/> <s:propertyvalue="#myObject"/> </body> </html> 3. HttpServletRequest class or request Map
Struts2 provides two operations on request: one is the HttpServletRequest class provided by the web server, which is the same as the operation of requests in traditional Java Web projects; the other is a "request Map", which is a mapping class that encapsulates the attributes of HttpServletRequest. Operating the map is equivalent to operating the attributes of HttpServletRequest. The reason why Map is provided is that it is convenient to operate, and the other is that it can use Ognl to read requests in JSP tags. In any case, these two requests are interoperable. As for the concepts such as the life cycle of request, it is no different from other Java Web projects, and this article will not be described in detail.
Use HttpServletRequest class or request Map
Although the two are interoperable, in terms of reading request attributes, using request maps is much more convenient and does not expose unnecessary interfaces. Of course, HttpServletRequest has some methods that the request Map does not have. Of course, the former should be used when using these methods.
Using request's Map or ActionContext:
Both are Map, and both life cycles are a request.
In traditional Java Web projects, the value is often passed to JSP through the attributes of the request: first setAttribute() in the Servlet, and then getAttribute() in the JSP. Of course, in the Struts2 project, you can still use this method, but abandoning the delivery function provided by Struts2 is not worth the effort. Although the author did not find the official document saying that you must replace the request's map with ActionContext, and did not find that there is a map in the program that can obtain ActionContext but cannot obtain the request, under the Struts2 framework, operating ActionContext is more convenient than operating the request's map. Therefore, the author recommends: try to use ActionContext instead of request's Map to pass the value.
The request's Map sometimes contains values set by other frameworks, such as Spring frameworks. When getting these values, you need to use the request Map because there is no in the ActionContext.
Through ActionContext, you can get the HttpServletRequest class: "HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);".
You can also get the Map of the request through ActionContext: "Map requestMap = (Map) actionContext.get("request");". Therefore, in the JSP tag, you can get the data of the Map of the request using the expression "#request".
How to get HttpServletRequest:
If there is already an ActionContext, use "actionContext.get(StrutsStatics.HTTP_REQUEST)" to obtain the HttpServletRequest.
In a custom interceptor, first obtain the ActionContext, and then obtain it through the ActionContext.
In Action, first obtain the ActionContext, and then obtain it through the ActionContext. Or let Action implement the ServletRequestAware interface and use the ServletConfigInterceptor interceptor, so that the interceptor will inject HttpServletRequest.
In JSP, you generally do not need to obtain HttpServletRequest.
How to get the Map of request:
If there is already an ActionContext, use "actionContext.get("request")" to obtain.
In a custom interceptor, first obtain the ActionContext, and then obtain it through the ActionContext.
In Action, first obtain the ActionContext, and then obtain it through the ActionContext. Or let Action implement the RequestAware interface and use the ServletConfigInterceptor interceptor, so that the interceptor will inject Map request.
In JSP, use "#request" to obtain the request's map, and use "#request.key" or "#request['key']" to read the value in the map.
In short, request still conforms to the general rules of Java Web sites. However, the author recommends that users should try to avoid using request to pass values.
Some examples:
// This class will demonstrate the operation of the Map of HttpServletRequest and request in the interceptor publicclass MyInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { // Get ActionContext ActionContext actionContext = invocation.getInvocationContext(); // Get HttpServletRequest HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST); // Get the Map Map requestMap = (Map) actionContext.get("request"); // Create a class as an instance Person person = new Person(); // The following two lines of statements have the same function httpServletRequest.setAttribute("person", person); requestMap.put("person", person); // Other codes// ...... return invocation.invoke(); } } // This class will demonstrate the operation of the map of HttpServletRequest and request in Action (the static method obtains ActionContext) publicclass MyAction extends ActionSupport { @Override public String execute() throws Exception { // Obtain ActionContext ActionContext actionContext = ActionContext.getContext(); // Obtain HttpServletRequest HttpServletRequest httpServletRequest=(HttpServletRequest)actionContext.get(StrutsStatics.HTTP_REQUEST); // Get the Map Map requestMap = (Map) actionContext.get("request"); // Create a class as an instance Person person = new Person(); // The following two lines of statements have the same function httpServletRequest.setAttribute("person", person); requestMap.put("person", person); // Other codes// ...... return SUCCESS; } } // This class will demonstrate using ServletRequestAware in Action to obtain HttpServletRequest (Note: you need to use ServletConfigInterceptor interceptor) publicclass MyAction extends ActionSupport implements ServletRequestAware { private HttpServletRequest request; //This method is a method of the interface ServletRequestAware publicvoid setServletRequest(HttpServletRequest request) { this.request = request; } @Override public String execute() throws Exception { // HttpServletRequest is ready in the field of this class, and can be used directly // ...... return SUCCESS; } } // This class will demonstrate using ServletRequestAware in Action to obtain the Map of the request (Note: you want to use ServletConfigInterceptor interceptor) publicclass MyAction extends ActionSupport implements RequestAware { Map<String, Object> request; // This method is a method of the interface RequestAware publicvoid setRequest(Map<String, Object> request) { this.request = request; } @Override public String execute() throws Exception { // The Map of the request is ready in the field of the class and can be used directly // ...... return SUCCESS; } }<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <!-- This JSP will demonstrate the use of request maps in JSP --> <!-- This JSP is the JSP corresponding to MyAction --> <!-- The Map of request is the value automatically stored in the ActionContext by Struts2 (the key is request), so use "#" to access the ActionContext and read the request from it --> <s:property value="#request"/> <!-- The following two lines are the value of the key "name" in the Map that accesses the request --> <s:property value="#request.name"/> <s:property value="#request['name']"/> </body> </html>
3. Parameters, that is, parameters of GET request or POST request
Parameters are parameters passed by the browser to the server when requesting GET or POST. In traditional Java Web projects, use methods such as HttpServletRequest.getParameter() to obtain parameters, and you can directly use HttpServletRequest.getParameterMap() to obtain a map with encapsulated parameters. In Struts2, Struts2 directly stores the above map in ActionContext, with the key "parameters". In addition, ActionContext also directly provides the ActionContext.getParameters() method to obtain this map. Therefore, the method of operating parameters in each component of Struts2 is very similar to the method of operating the Map of request, and this paragraph will not be described in detail.
4. Map of HttpServletSession class and session
The session in traditional Java Web projects is all familiar with, and we use it to record the session status of a user. Struts2 encapsulates the HttpServletSession into a Map, that is, the "session Map", which is similar to the processing of request. However, in order to save system resources, we will not create sessions when we do not need sessions. It may be because of this that the HttpServletSession is not put into the ActionContext in Struts2. If your program needs to use HttpServletSession, you should first get the HttpServletRequest, and then use getSession() or getSession(boolean b) to get it, and decide whether you need to create a session. For the session map, Struts2 still puts it in the ActionContext (key is "session"), but don't worry, the mechanism of this map makes sessions only when put new values are created. In short, the operation of HttpServletSession in Struts2 must first obtain it through HttpServletRequest, and the operation of the session Map is exactly the same as the operation of the request Map, which will not be described in detail in this paragraph.
5. Map of ServletContext and application
In traditional Java Web projects, ServletContext is used to store global variables, and each Java virtual machine has only one ServletContext per Web project. This ServletContext is created by a web server to ensure its uniqueness. ServletContext has some methods that can operate its attributes, and these operations are similar to operating a Map. So, Struts2 encapsulates again: it encapsulates the attributes of ServletContext into a map, that is, "application Map", and also puts it in the ActionContext (key is application). Therefore, if the operation of the application map is to the Map of the request, this paragraph will not be described in detail.
As for the operation on ServletContext, it is similar to the operation on HttpServletRequest: Struts2 puts the ServletContext into the ActionContext, and ServletConfigInterceptor provides the injection interface ServletContextAware for ServletContext. Therefore, this paragraph will not be described in detail.
Note: Using "#application" in Ognl expressions can get the application's Map, not the ServletContext. However, in the Java code embedded in JSP (such as "<% application.getAttribute(""); %>"), the application is a ServletContext, not a Map.