I am trying to understand the path data takes within Struts2, how is data placed on the ValueStack? How can I find out which object is currently present in the ValueStack? What other data can I access from different scopes application, session, request, page? How to decide the scopes my variables should have?
问题:
回答1:
That's a lot of questions.
The value stack is just a data structure, sort of a combination of a map and stack. Named objects (accessed via the #
tag in OGNL) are in the map (like the request scope, say), objects to search through for properties/methods are on the stack.
The <s:debug>
tag is the easiest way to find out what's in the value stack. You can also access arbitrary objects on the stack using "bare" array notation in JSP, like "[0]"
is the top-most object, "[1]"
is the next, etc. This is almost never a good idea in real life.
You can access whatever is in each of the scopes.
Your own objects should almost always be placed on the value stack via the action itself, or if you're implementing ModelDriven
, via the model. Other than that it's the same as any other Java EE application--objects needed for the duration of the client's session should be in session scope, objects shared across the application should be in the application scope, etc.
The value stack itself is in the request scope.
回答2:
I will specifically address the "How does data travel" element, and the stackness of the ValueStack. As for the bit about what data is available, that can change with the context;the whole point of having a "stack" is to support contextual changes in the data that is in scope. Furthermore, the specific data on the stack is better covered by reference materials, such as found on the struts website.
Struts 2 has a very clean architecture. It does a great job of separating concerns of the software into distinct components. One of the main halmarks of this is the fact that the Action is a POJO. As a pojo, the action's main duty is the carrying of data. It is the primary data transfer object; it's properties recieve the incoming request data, provided that the naming all lines up. The task of moving data, and thinking about when to move data, is captured in another component: the interceptor.
The movement of data onto the ValueStack is done almost exclusively with interceptors. One of the first things the framework does when processing a request is to place the newly created action object onto the top of the valuestack. This supports the OGNL access to your action's properties. Then, interceptors move data onto the valuestack, and since your action is there, it's properties will receive data on matching setters. Other interceptors will also move stuff onto the valuestack in a similar fashion, such as the validation interceptors; if they find an error, that error message goes onto the stack as well.
In addition to being the centralized data container, the ValueStack is, of course, a stack. This stackness, which allows properties on the top of the stack to hide properties lower down in the stack, comes into play when you consider such things as the iterator tag. If you iterate over a collection of users, for instance, each user goes onto the top of the stack and remains there during the body of the iteration. This allows your OGNL property references to hit the properties of each individual user in turn. More importantly, if something else with a similarly named property was found further down in the stack, it will be hidden by the user object on the top. Note, in consideration of this, the push tag, which allows you to push whatever object you like onto the stack, providing nice flexibility when you need to force your own context.