You are on page 1of 37

Interceptors

Edit Page Browse Space Add Page Add News


Added by victorsosa, last edited by Ted Husted on Mar 17, 2007 (view change)
The default Interceptor stack is designed to serve the needs of most
applications. Most applications will not need to add Interceptors or
change the Interceptor stack.

Many Actions share common concerns. Some Actions need input validated. Other
Actions may need a file upload to be pre-processed. Another Action might need
protection from a double submit. Many Actions need drop-down lists and other controls
pre-populated before the page displays.

The framework makes it easy to share solutions to these concerns using an "Interceptor"
strategy. When you request a resource that maps to an "action", the framework invokes
the Action object. But, before the Action is executed, the invocation can be intercepted
by another object. After the Action executes, the invocation could be intercepted again.
Unsurprisingly, we call these objects "Interceptors."

Understanding Interceptors
Interceptors can execute code before and after an Action is invoked. Most of the
framework's core functionality is implemented as Interceptors. Features like double-
submit guards, type conversion, object population, validation, file upload, page
preparation, and more, are all implemented with the help of Interceptors. Each and every
Interceptor is pluggable, so you can decide exactly which features an Action needs to
support.

Interceptors can be configured on a per-action basis. Your own custom Interceptors can
be mixed-and-matched with the Interceptors bundled with the framework. Interceptors
"set the stage" for the Action classes, doing much of the "heavy lifting" before the Action
executes.

Action Lifecyle
In some cases, an Interceptor might keep an Action from firing, because of a double-
submit or because validation failed. Interceptors can also change the state of an Action
before it executes.

The Interceptors are defined in a stack that specifies the execution order. In some cases,
the order of the Interceptors on the stack can be very important.

Configuring Interceptors
struts.xml
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="timer" class=".."/>
<interceptor name="logger" class=".."/>
</interceptors>

<action name="login"
class="tutorial.Login">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<result name="input">login.jsp</result>
<result name="success"
type="redirect-action">/secure/home</result>
</action>
</package>

Stacking Interceptors
With most web applications, we find ourselves wanting to apply the same set of
Interceptors over and over again. Rather than reiterate the same list of Interceptors, we
can bundle these Interceptors together using an Interceptor Stack.

struts.xml
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="timer" class=".."/>
<interceptor name="logger" class=".."/>
<interceptor-stack name="myStack">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
</interceptor-stack>
</interceptors>

<action name="login"
class="tutuorial.Login">
<interceptor-ref name="myStack"/>
<result name="input">login.jsp</result>
<result name="success"
type="redirect-action">/secure/home</result>
</action>
</package>

Looking inside struts-default.xml, we can see how it's done.

The Default Configuration


<?xml version="1.0" encoding="UTF-8" ?>
<!--
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
-->

<!DOCTYPE struts PUBLIC


"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" />
<bean type="com.opensymphony.xwork2.ObjectFactory" name="struts"
class="org.apache.struts2.impl.StrutsObjectFactory" />

<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="xwork"


class="com.opensymphony.xwork2.DefaultActionProxyFactory"/>
<bean type="com.opensymphony.xwork2.ActionProxyFactory"
name="struts" class="org.apache.struts2.impl.StrutsActionProxyFactory"/>

<bean type="com.opensymphony.xwork2.util.ObjectTypeDeterminer"
name="tiger"
class="com.opensymphony.xwork2.util.GenericsObjectTypeDeterminer"/>
<bean type="com.opensymphony.xwork2.util.ObjectTypeDeterminer"
name="notiger"
class="com.opensymphony.xwork2.util.DefaultObjectTypeDeterminer"/>
<bean type="com.opensymphony.xwork2.util.ObjectTypeDeterminer"
name="struts"
class="com.opensymphony.xwork2.util.DefaultObjectTypeDeterminer"/>

<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
name="struts"
class="org.apache.struts2.dispatcher.mapper.DefaultActionMapper" />
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
name="composite"
class="org.apache.struts2.dispatcher.mapper.CompositeActionMapper" />
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
name="restful"
class="org.apache.struts2.dispatcher.mapper.RestfulActionMapper" />
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
name="restful2"
class="org.apache.struts2.dispatcher.mapper.Restful2ActionMapper" />

<bean
type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
name="struts"
class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest"
scope="default" optional="true"/>
<bean
type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
name="jakarta"
class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest"
scope="default" optional="true" />

<bean type="org.apache.struts2.views.TagLibrary" name="s"


class="org.apache.struts2.views.DefaultTagLibrary" />

<bean class="org.apache.struts2.views.freemarker.FreemarkerManager"
name="struts" optional="true"/>
<bean class="org.apache.struts2.views.velocity.VelocityManager"
name="struts" optional="true" />

<bean
class="org.apache.struts2.components.template.TemplateEngineManager" />
<bean type="org.apache.struts2.components.template.TemplateEngine"
name="ftl"
class="org.apache.struts2.components.template.FreemarkerTemplateEngine"
/>
<bean type="org.apache.struts2.components.template.TemplateEngine"
name="vm"
class="org.apache.struts2.components.template.VelocityTemplateEngine" />
<bean type="org.apache.struts2.components.template.TemplateEngine"
name="jsp"
class="org.apache.struts2.components.template.JspTemplateEngine" />

<bean type="com.opensymphony.xwork2.util.XWorkConverter"
name="xwork1" class="com.opensymphony.xwork2.util.XWorkConverter" />
<bean type="com.opensymphony.xwork2.util.XWorkConverter"
name="struts"
class="com.opensymphony.xwork2.util.AnnotationXWorkConverter" />

<bean type="com.opensymphony.xwork2.TextProvider" name="xwork1"


class="com.opensymphony.xwork2.TextProviderSupport" />
<bean type="com.opensymphony.xwork2.TextProvider" name="struts"
class="com.opensymphony.xwork2.TextProviderSupport" />

<bean type="org.apache.struts2.components.UrlRenderer"
name="struts" class="org.apache.struts2.components.ServletUrlRenderer"/>

<!-- Only have static injections -->


<bean class="com.opensymphony.xwork2.ObjectFactory" static="true" />
<bean class="com.opensymphony.xwork2.util.XWorkConverter"
static="true" />
<bean class="com.opensymphony.xwork2.util.OgnlValueStack"
static="true" />
<bean class="org.apache.struts2.dispatcher.Dispatcher" static="true"
/>
<bean class="org.apache.struts2.components.Include" static="true" />
<bean class="org.apache.struts2.dispatcher.FilterDispatcher"
static="true" />
<bean class="org.apache.struts2.views.util.ContextUtil"
static="true" />
<bean class="org.apache.struts2.views.util.UrlHelper" static="true"
/>

<package name="struts-default" abstract="true">


<result-types>
<result-type name="chain"
class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="dispatcher"
class="org.apache.struts2.dispatcher.ServletDispatcherResult"
default="true"/>
<result-type name="freemarker"
class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader"
class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-type name="redirect"
class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-type name="redirectAction"
class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-type name="stream"
class="org.apache.struts2.dispatcher.StreamResult"/>
<result-type name="velocity"
class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-type name="xslt"
class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText"
class="org.apache.struts2.dispatcher.PlainTextResult" />
</result-types>

<interceptors>
<interceptor name="alias"
class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring"
class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInter
ceptor"/>
<interceptor name="chain"
class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError"
class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"
/>
<interceptor name="createSession"
class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging"
class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef"
class="com.opensymphony.xwork2.interceptor.ExternalReferencesIntercepto
r"/>
<interceptor name="execAndWait"
class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception"
class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"
/>
<interceptor name="fileUpload"
class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n"
class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger"
class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven"
class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven"
class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"
/>
<interceptor name="params"
class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="prepare"
class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams"
class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"
/>
<interceptor name="scope"
class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig"
class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring"
class="org.apache.struts2.spring.interceptor.SessionContextAutowiringIn
terceptor"/>
<interceptor name="timer"
class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token"
class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession"
class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation"
class="org.apache.struts2.interceptor.validation.AnnotationValidationIn
terceptor"/>
<interceptor name="workflow"
class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store"
class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox"
class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling"
class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles"
class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation"
class="org.apache.struts2.interceptor.validation.JSONValidationIntercep
tor" />
<interceptor name="annotationWorkflow"
class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkfl
owInterceptor" />

<!-- Basic stack -->


<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>

<!-- Sample validation and workflow stack -->


<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>

<!-- Sample JSON validation stack -->


<interceptor-stack name="jsonValidationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation">
<param
name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="jsonValidation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
<!-- Sample file upload stack -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- Sample model-driven stack -->


<interceptor-stack name="modelDrivenStack">
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- Sample action chaining stack -->


<interceptor-stack name="chainStack">
<interceptor-ref name="chain"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- Sample i18n stack -->


<interceptor-stack name="i18nStack">
<interceptor-ref name="i18n"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>

<!-- An example of the params-prepare-params trick. This


stack
is exactly the same as the defaultStack, except that it
includes one extra interceptor before the prepare
interceptor:
the params interceptor.

This is useful for when you wish to apply parameters


directly
to an object that you wish to load externally (such as
a DAO
or database or service layer), but can't load that
object
until at least the ID parameter has been loaded. By
loading
the parameters twice, you can retrieve the object in
the
prepare() method, allowing the second params
interceptor to
apply the values on the object. -->
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param
name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param
name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>

<!-- A complete stack with all the common interceptors in


place.
Generally, this stack should be the one you use,
though it
may do more than you need. Also, the ordering can be
switched around (ex: if you wish to have your servlet-
related
objects applied before prepare() is called, you'd need
to move
servlet-config interceptor up.

This stack also excludes from the normal validation


and workflow
the method names input, back, and cancel. These
typically are
associated with requests that should not be validated.
-->
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="profiling"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param
name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param
name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
<!-- The completeStack is here for backwards compatibility
for
applications that still refer to the defaultStack by
the
old name -->
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack"/>
</interceptor-stack>

<!-- Sample execute and wait stack.


Note: execAndWait should always be the *last*
interceptor. -->
<interceptor-stack name="executeAndWaitStack">
<interceptor-ref name="execAndWait">
<param
name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="execAndWait">
<param
name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>

</interceptors>

<default-interceptor-ref name="defaultStack"/>
</package>

</struts>

Since the struts-default.xml is included in the application's configuration by default,


all of the predefined interceptors and stacks are available "out of the box".

Framework Interceptors
Interceptor classes are also defined using a key-value pair specified in the Struts
configuration file. The names specified below come specified in struts-default.xml. If you
extend the struts-default package, then you can use the names below. Otherwise, they
must be defined in your package with a name-class pair specified in the <interceptors>
tag.

Interceptor Name Description


Converts similar parameters that may be named
Alias Interceptor alias
differently between requests.
Makes the previous Action's properties available
to the current Action. Commonly used together
Chaining Interceptor chain
with <result type="chain"> (in the previous
Action).
Checkbox Interceptor checkbox Adds automatic checkbox handling code that
detect an unchecked checkbox and add it as a
parameter with a default (usually 'false') value.
Uses a specially named hidden field to detect
unsubmitted checkboxes. The default unchecked
value is overridable for non-boolean value'd
checkboxes.
Inject cookie with a certain configurable name /
Cookie Interceptor cookie
value into action. (Since 2.0.7.)
Conversion Error Adds conversion errors from the ActionContext
conversionError
Interceptor to the Action's field errors
Create an HttpSession automatically, useful with
Create Session
createSession certain Interceptors that require a HttpSession to
Interceptor
work properly (like the TokenInterceptor)
Provides several different debugging screens to
DebuggingInterceptor debugging
provide insight into the data behind the page.
Executes the Action in the background and then
Execute and Wait
execAndWait sends the user off to an intermediate waiting
Interceptor
page.
Exception Interceptor exception Maps exceptions to a result.
An Interceptor that adds easy access to file
File Upload Interceptor fileUpload
upload support.
Remembers the locale selected for a user's
I18n Interceptor i18n
session.
Logger Interceptor logger Outputs the name of the Action.
Store and retrieve action messages / errors / field
Message Store
store errors for action that implements
Interceptor
ValidationAware interface into session.
Model Driven If the Action implements ModelDriven, pushes
model-driven
Interceptor the getModel Result onto the Value Stack.
If the Action implements ScopedModelDriven,
Scoped Model Driven scoped-model- the interceptor retrieves and stores the model
Interceptor driven from a scope and sets it on the action calling
setModel.
Parameters Interceptor params Sets the request parameters onto the Action.
If the Action implements Preparable, calls its
Prepare Interceptor prepare
prepare method.
Simple mechanism for storing Action state in the
Scope Interceptor scope
session or application scope.
Servlet Config Provide access to Maps representing
servletConfig
Interceptor HttpServletRequest and HttpServletResponse.
Sets the struts.xml defined parameters onto
Static Parameters
staticParams the action. These are the <param> tags that are
Interceptor
direct children of the <action> tag.
Action will only be executed if the user has the
Roles Interceptor roles
correct JAAS role.
Outputs how long the Action takes to execute
Timer Interceptor timer
(including nested Interceptors and View)
Checks for valid token presence in Action,
Token Interceptor token
prevents duplicate form submission.
Same as Token Interceptor, but stores the
Token Session
tokenSession submitted data in session when handed an
Interceptor
invalid token
Performs validation using the validators defined
Validation Interceptor validation
in action-validation.xml
Calls the validate method in your Action class.
Workflow Interceptor workflow If Action errors are created then it returns the
INPUT view.
Parameter Filter Removes parameters from the list of those
N/A
Interceptor available to Actions
Profiling Interceptor profiling Activate profiling through parameter
Since 2.0.7, Interceptors and Results with hyphenated names were
converted to camelCase. (The former model-driven is now
modelDriven.) The original hyphenated names are retained as "aliases"
until Struts 2.1.0. For clarity, the hyphenated versions are not listed
here, but might be referenced in prior versions of the documentation.

Method Filtering

An abstract Interceptor that is applied to filter method names according to specified


included/excluded method lists.

Setable parameters are as follows:

• excludeMethods - methods name to be excluded


• includeMethods - methods name to be included

NOTE: If method name are available in both includeMethods and excludeMethods, it


will still be considered as an included method. In short includeMethods takes precedence
over excludeMethods.

Interceptors that extends this capability would be :-

• TokenInterceptor
• TokenSessionStoreInterceptor
• DefaultWorkflowInterceptor
• ValidationInterceptor

Interceptor Parameter Overriding

Interceptor's parameter could be overriden through the following ways :-


Method 1:

<action name="myAction" class="myActionClass">


<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="model-driven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">myValidationExcudeMethod</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>
</action>

Method 2:

<action name="myAction" class="myActionClass">


<interceptor-ref name="defaultStack">
<param
name="validation.excludeMethods">myValidationExcludeMethod</param>
<param
name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
</interceptor-ref>
</action>

In the first method, the whole default stack is copied and the parameter then changed
accordingly.

In the second method, the refer to an existing interceptor-stack, namely default-stack in


this example, and override the validator and workflow interceptor excludeMethods
typically in this case. Note that in the

tag, the name attribute contains a dot (.) the word before the dot(.) specifies the
interceptor name whose parameter is to be overriden and the word after the dot (.)
specifies the parameter itself. Essetially it is as follows :-
<interceptor-name>.<parameter-name>

Note also that in this case the name attribute is used to indicate an interceptor stack which
makes sense as if it is refering to the interceptor itself it would be just using Method 1
describe above.

Order of Interceptor Execution


Interceptors provide an excellent means to wrap before/after processing. The concept
reduces code duplication (think AOP).

<interceptor-stack name="xaStack">
<interceptor-ref name="thisWillRunFirstInterceptor"/>
<interceptor-ref name="thisWillRunNextInterceptor"/>
<interceptor-ref name="followedByThisInterceptor"/>
<interceptor-ref name="thisWillRunLastInterceptor"/>
</interceptor-stack>

Note that some Interceptors will interrupt the stack/chain/flow ... so the order is very
important.

Interceptors implementing
com.opensymphony.xwork2.interceptor.PreResultListener will run after the
Action executes but before the Result executes.

thisWillRunFirstInterceptor
thisWillRunNextInterceptor
followedByThisInterceptor
thisWillRunLastInterceptor
MyAction1
MyAction2 (chain)
MyPreResultListener
MyResult (result)
thisWillRunLastInterceptor
followedByThisInterceptor
thisWillRunNextInterceptor
thisWillRunFirstInterceptor

FAQ
• How do we configure an Interceptor to be used with every Action?
• How do we get access to the session?
• How can we access the HttpServletRequest?
• How can we access the HttpServletResponse?
• How can we access request parameters passed into an Action?
• How do we access static parameters from an Action?
• Can we access an Action's Result?
• How do I obtain security details (JAAS)?
• Why isn't our Prepare interceptor being executed?
• How do we upload files?

Next: Writing Interceptors


How do we configure an Interceptor to be used with every Action
Edit Page Browse Space Add Page Add News
Added by Ted Husted, last edited by Ted Husted on Nov 08, 2006
Any given action mapping can create an "ad-hoc" interceptor stack

<action name="login" class="tutorial.Login">

<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<interceptor-ref name="default-stack"/>

<result name="input">login.jsp</result>
<result type="redirect-action">/secure/home</result>
</action>

Or, we can create our own named stacks and even declare a new default interceptor stack
for a package

<package name="default" extends="struts-default" >


<interceptors>
<interceptor-stack name="myStack">
<interceptor-ref name="timer"/>
<interceptor-ref name="logger"/>
<interceptor-ref name="default-stack"/>
</interceptor-stack>
</interceptors>

<default-interceptor-ref name="myStack"/>

<action name="login" class="tutorial.Login">


<result name="input">login.jsp</result>
<result type="redirect-action">/secure/home</result>
</action>

</package>

Packages can extend other packages. If all the other packages in your application extend
"default", then they will all inherit the new default interceptor.

How do we get access to the session


Edit Page Browse Space Add Page Add News
Added by digi9ten, last edited by Ted Husted on Jul 22, 2006 (view change)

You can obtain the session attributes by asking the ActionContext or implementing
SessionAware. Implementing SessionAware is preferred.

Ask the ActionContext


The session attributes are available on the ActionContext instance, which is made
available via ThreadLocal.

Map attibutes = ActionContext.getContext().getSession();


Implement SessionAware
_Preferred_

• Ensure that servlet-config Interceptor is included in the Action's stack.


o The default stack already includes servlet-config.
• Edit the Action so that it implements the SessionAware interface.
o The SessionAware interface expects a setSession method. You may
wish to include a companion getSession method.
• At runtime, call getSession to obtain a Map representing the session attributes.
• Any changes made to the session Map are reflected in the actual
HttpSessionRequest. You may insert and remove session attributes as needed.

Map parameters = this.getSession();


When the servlet-config Interceptor sees that an Action implements
ParameterAware, it passes a Map of the session attributes to the
Action's setParameters method. Changes made to the Map are
reflected in the runtime HttpSessionRequest.
To unit test a SessionAware Action, create your own Map with the
pertinent session attributes and call setSession as part of the test's
setUp method.
How can we access the HttpServletRequest
Edit Page Browse Space Add Page Add News
Added by digi9ten, last edited by Ted Husted on Jul 22, 2006 (view change)

You can obtain the request by asking the ActionContext or implementing


ServletRequestAware. Implementing ServletRequestAwareis preferred.

Ask the ActionContext


The request is available on the ActionContext instance, which is made available via
ThreadLocal.

HttpServletRequest request = ServletActionContext.getRequest();

Implement ServletRequestAware
Preferred

• Ensure that servlet-config Interceptor is included in the Action's stack.


o The default stack already includes servlet-config.
• Edit the Action so that it implements the ServletRequestAware interface.
o The ServletRequestAware interface expects a setServletRequest
method. You may wish to include a companion getServletRequest
method.
• At runtime, call getServletRequest to obtain a reference to the request object.
When the servlet-config Interceptor sees that an Action implements
ServletRequestAware, it passes a reference to the request the Action's
setServletRequest method.

It is more difficult to test Actions with runtime dependencies on


HttpServletRequest. Only implement ServletRequestAware as a last
resort. If the use case cannot be solved by one of the other servet-
config interfaces (ApplicationAware, SessionAware,
ParameterAware), consider whether an custom Interceptor could be
used instead of Action code. (Review how servlet-config works for
examples of what can be done.)
How can we access the HttpServletResponse
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Jul 22, 2006 (view change)

You can obtain the request by asking the ActionContext or implementing


ServletResponseAware. Implementing ServletResponseAware is preferred.

Ask the ActionContext


The response is available on the ActionContext instance, which is made available via
ThreadLocal.

HttpServletResponse response = ServletActionContext.getResponse();

Implement ServletResponseAware
Preferred

• Ensure that servlet-config Interceptor is included in the Action's stack.


o The default stack already includes servlet-config.
• Edit the Action so that it implements the ServletResponseAware interface.
o The ServletResponseAware interface expects a setServletResponse
method. You may wish to include a companion getServletResponse
method.
• At runtime, call getServletResponse to obtain a reference to the response
object.
When the servlet-config Interceptor sees that an Action implements
ServletResponseAware, it passes a reference to the request the Action's
setServletResponse method.
It is more difficult to test Actions with runtime dependencies on
HttpServletReponse. Only implement ServletResponseAware as a last
resort. A better approach to solving a use case involving the response
may be with a custom Result Type.
How can we access request parameters passed into an Action
Edit Page Browse Space Add Page Add News
Added by digi9ten, last edited by Ted Husted on Jul 22, 2006 (view change)

You can obtain the request parameters by asking the ActionContext or implementing
ParameterAware. Implementing ParameterAware is preferred.

Ask the ActionContext


The request parameters are available on the ActionContext instance, which is made
available via ThreadLocal.

Map parameters = ActionContext.getContext().getParameters();

Implement ParameterAware
Preferred

• Ensure that servlet-config Interceptor is included in the Action's stack.


o The default stack already includes servlet-config.
• Edit the Action so that it implements the ParameterAware interface.
o The ParameterAware interface expects a setParameters method. You
may wish to include a companion getParameters method.
• At runtime, call getParameters to obtain a Map representing the request
parameters.

Map parameters = this.getParameters();


When the servlet-config Interceptor sees that an Action implements
ParameterAware, it passes a Map of the request parameters to the
Action's setParameters method.
To unit test a ParameterAware Action, create your own Map with the
pertinent request parameters and call setParameters as part of the
test's setUp method.
How do we access static parameters from an Action
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Jul 22, 2006 (view change) show
comment

Static (or pre-defined) parameters can be set to a Map property or to individual JavaBean
properties.
• Define the parameters to be set by adding the name(s) and value(s) to the action
mapping element (in the application's struts.xml.

<action name="myAction" class=" MyAction">


<param name="myStaticParam1">myStaticValue1</param>
<param name="myStaticParam2">myStaticValue2</param>
<param name="myStaticParam3">myStaticValue3</param>
</action>

• Ensure that static-params Interceptor is included in the Action's stack.


o The default stack already includes static-params.
• Edit the Action so that it implements the Parameterizable interface.

Map property
• Ensure the Action defines a setParams(Map) method.

• The static-params Interceptor will set the defined values to the Map, using the
name as the entry key.

key value
myStaticParam1 myStaticValue1
myStaticParam2 myStaticValue2
myStaticParam3 myStaticValue3

JavaBean properties
• Ensure that the Action defines JavaBean properties corresponding to the param
elements in the action mapping.

• The static-params|| Interceptor will set the defined values to


each JavaBean property that corresponds to a {{param element.

public String getMyStaticParam1()


public void setMyStaticParam1(String myStaticParam1)

public String getMyStaticParam2()


public void setMyStaticParam2(String myStaticParam2)

public String getMyStaticParam3()


public void setMyStaticParam3(String myStaticParam3)
Can we access an Action's Result
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Jul 22, 2006 (view change)

Yes, you can access the ResultConfig objects before the Action executes, and you can
access the final Result object using a PreResultListener.
Accessing the ResultConfig Objects
If you need to work with the set of ResultConfigs before the Action executes, you can use
an Interceptor to process the Map returned by getResults.

public class MyInterceptor implements Interceptor {


// ...
public String intercept(ActionInvocation invocation) throws Exception
{
Map resultsMap = invocation.getProxy().getConfig().getResults();

// do something with ResultConfig in map

return invocation.invoke();
}
// ...
}

If you are writing against Java 5, you could use a generic when obtain the map.

Map<String, ResultConfig> resultsMap =


invocation.getProxy().getConfig().getResults();

Adding a PreResultListener
If you need to work with the final Result object before it is executed, you can use an
Interceptor to register a PreResultListener. The code example creates a PreResultListener
as an anonymous inner class.

public class MyInterceptor implements Interceptor {


// ...
public String intercept(ActionInvocation invocation) throws Exception
{

invocation.addPreResultListener(new PreResultListener() {

public void beforeResult(ActionInvocation invocation, String


resultCode) {
Map resultsMap = invocation.getProxy().getConfig().getResults();
ResultConfig finalResultConfig = resultsMap.get(resultCode);

// do something interesting with the 'to-be' executed result

});

return invocation.invoke();
}
// ...
}
If you are writing against Java 5, you could use a generic when obtain the map.

Map<String, ResultConfig> resultsMap =


invocation.getProxy().getConfig().getResults();
How do I obtain security details (JAAS)
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Jul 22, 2006 (view change) show
comment

You can obtain the UserPrincipal and other security details by going through the request
or implementing PrincipalAware. Implementing PrincipalAware is preferred.

Go Through the Request


First obtain the HttpServletRequest and then obtain the security Principal.

HttpServletRequest request = ServletActionContext.getRequest();


String authType = request.getAuthType(); // http or https
String user = request.getRemoteUser(); // the user principal
(in string)
Principalprincipal = request.getUserPrincipal(); // get a Principal
object
bool isAuth = request.isUserInRole("patrick");

Implement PrincipalAware
Preferred

• Ensure that servlet-config Interceptor is included in the Action's stack.


o The default stack already includes servlet-config.
• Edit the Action so that it implements the PrincipalAware interface.
o The PrincipalAware interface expects a
setPrincipalProxy(PrincipalProxy) method. You may wish to
include a companion getPrincipalProxy method.
• At runtime, use the PrincipalProxy reference to invoke methods such as
isUserInRole, getUserPrincipal(), getRemoteUser(), isRequestSecure(),
and so forth.

Why isn't our Prepare interceptor being executed


Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Jul 22, 2006 (view change)

Sometimes the order of the Interceptors makes a difference. In the case of the prepare
Interceptor, ensure that it comes before validation on the interceptor-stack.

<interceptor-stack name="myInterceptorStack">
...
<interceptor-ref name="prepare" />
...
<interceptor-ref name="validation" />
...
</interceptor-stack>
The default stack does place the prepare Interceptor before the
validation Inteceptor.
How do we upload files
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Jan 28, 2007 (view change)

You can obtain the MultipartRequestWrapper from the ServletActionContext or by


utilizing the fileUpload interceptor. The fileUpload interceptor is preferred.

Ask the ServletActionContext


MultipartRequestWrapper multipartRequest =
((MultipartRequestWrapper)ServletActionContext.getRequest())

The MultipartRequestWrapper provideds access methods such as getFiles, getFile,


getContentType, hasErrors, getErrors, and so forth, so that you can process the file
uploaded.

Utilize the fileUpload Interceptor


_Preferred_

• Ensure that {{fileUpload }} Interceptor is included in the Action's stack.


o The default stack already includes {{fileUpload }}.
• Ensure that the HTML form sets the enctype and specifies on or more file type
inputs.

<form name="myForm" enctype="multipart/form-data">


<input type="file" name="myDoc" value="Browse ..." />
<input type="submit" />
</form>

• Ensure that the Action provides one or more fileUpload mutator methods, with
names that correspond to name of the file type input.

public void setMyDoc(File myDoc)


public void setMyDocContentType(String contentType)
public void setMyDocFileName(String filename)

• The Action may also provide the corresponding accessor methods.

public File getMyDoc()


public ContentType getMyDocContentType()
public String getMyDocFileName()

Handling multiple files

When multiple files are uploaded by a form, the files are represented by an array.

Given:

<form name="myForm" enctype="multipart/form-data">


<input type="file" name="myDoc" value="Browse File A ..." />
<input type="file" name="myDoc" value="Browse File B ..." />
<input type="file" name="myDoc" value="Browse File C ..." />
<input type="submit" />
</form>

The Action class can define file handling methods that accept an array.

public void setMyDoc(File[] myDocs)


public void setMyDocContentType(String[] contentTypes)
public void setMyDocFileName(String[] fileNames)

The uploaded files can be handled by iterating through the appropriate array.

Extra Information

Property Default
struts.multipart.parser Commons FileUpload
struts.multipart.saveDir javax.servlet.context.tempdir as defined by container
struts.multipart.maxSize Approximately 2M
Writing Interceptors
Edit Page Browse Space Add Page Add News
Added by Musachy Barroso, last edited by Musachy Barroso on Jul 09, 2007 (view
change)

See the Interceptors page for an overview of how interceptors work.

Interceptor interface

Interceptors must implement the com.opensymphony.xwork2.interceptor.Interceptor


interface.

Interceptor.java
public interface Interceptor extends Serializable {

void destroy();

void init();
String intercept(ActionInvocation invocation) throws Exception;
}

The init method is called the after interceptor is instantiated and before calling intercept.
This is the place to allocate any resources used by the interceptor.

The intercept method is where the interceptor code is written. Just like an action method,
intercept returns a result used by Struts to forward the request to another web resource.
Calling invoke on the parameter of type ActionInvocation will execute the action (if this
is the last interceptor on the stack) or another interceptor.

Keep in mind that invoke will return after the result has been called (eg.
after you JSP has been rendered), making it perfect for things like open-
session-in-view patterns. If you want to do something before the result
gets called, you should implement a PreResultListener.

Overwrite destroy to release resources on application shutdown.

Thread Safety

Interceptors must be thread-safe!

A Struts 2 Action instance is created for every request and do not need
to be thread-safe. Conversely, Interceptors are shared between requests
and must be thread-safe .

AbstractInterceptor

The AbstractInterceptor class provides an empty implementation of init and destroy, and
can be used if these methods are not going to be implemented.

Mapping

Interceptors are declared using the interceptor element, nested inside the interceptors
element. Example from struts-default.xml:

<struts>
...

<package name="struts-default">
<interceptors>
<interceptor name="alias"
class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring"
class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInter
ceptor"/>
...
</interceptors>
</package>

...
</struts>

Example

Assuming there is an action of type "MyAction", with a setDate(Date) method, this


simple interceptor will set the date of the action to the current date:

Interceptor Example
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class SimpleInterceptor extends AbstractInterceptor {

public String intercept(ActionInvocation invocation) throws


Exception {
MyAction action = (MyAction)invocation.getAction();
action.setDate(new Date());
return invocation.invoke();
}
}
Action Chaining
Edit Page Browse Space Add Page Add News
Added by jcarreira, last edited by Ted Husted on Feb 12, 2007 (view change)

The framework provides the ability to chain multiple actions into a defined sequence or
workflow. This feature works by applying a Chain Result to a given Action, and
intercepting its target Action's invocation with a ChainingInterceptor .

Don't Try This at Home

As a rule, Action Chaining is not recommended. First explore other


options, such as the Redirect After Post technique.

Chain Result
The Chain Result is a result type that invokes an Action with its own Interceptor Stack
and Result. This Interceptor allows an Action to forward requests to a target Action,
while propagating the state of the source Action. Below is an example of how to define
this sequence.

<package name="public" extends="struts-default">


<!-- Chain creatAccount to login, using the default parameter -->
<action name="createAccount" class="...">
<result type="chain">login</result>
</action>

<action name="login" class="...">


<!-- Chain to another namespace -->
<result type="chain">
<param name="actionName">dashboard</param>
<param name="namespace">/secure</param>
</result>
</action>
</package>

<package name="secure" extends="struts-default" namespace="/secure">


<action name="dashboard" class="...">
<result>dashboard.jsp</result>
</action>
</package>

Another action mapping in the same namespace (or the default "" namespace) can be
executed after this action mapping (see Configuration Files). An optional "namespace"
parameter may also be added to specify an action in a different namespace.

Chaining Interceptor
If you need to copy the properties from your previous Actions in the chain to the current
action, you should apply the ChainingInterceptor . The Interceptor will copy the original
parameters from the request, and the ValueStack is passed in to the target Action. The
source Action is remembered by the ValueStack, allowing the target Action to access the
properties of the preceding Action(s) using the ValueStack, and also makes these
properties available to the final result of the chain, such as the JSP or Velocity page.

One common use of Action chaining is to provide lookup lists (like for a dropdown list of
states). Since these Actions get put on the ValueStack, their properties will be available in
the view. This functionality can also be done using the ActionTag to execute an Action
from the display page. You may also use the Redirect Action Result to accomplish this.

Result Types
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Philip Luppens on Mar 13, 2007 (view change) show
comment

Most use cases can be divided into two phases. First, we need to change or query the
application's state, and then we need to present an updated view of the application. The
Action class manages the application's state, and the Result Type manages the view.

Predefined Result Types


The framework provides several implementations of the
com.opensymphony.xwork2.Result interface, ready to use in your own applications.
Chain Result Used for Action Chaining
Dispatcher Result Used for web resource integration, including JSP integration
FreeMarker Result Used for FreeMarker integration
HttpHeader Result Used to control special HTTP behaviors
Redirect Result Used to redirect to another URL (web resource)
Redirect Action Result Used to redirect to another action mapping
Used to stream an InputStream back to the browser (usually for
Stream Result
file downloads)
Velocity Result Used for Velocity integration
XSL Result Used for XML/XSLT integration
Used to display the raw content of a particular page (i.e jsp,
PlainText Result
HTML)
S2PLUGINS:Tiles
Used to provide Tiles integration
Result

Optional

Used for JasperReports Tutorial Optional, third-party


JasperReports Plugin
integration plugin

Additional Result Types can be created and plugged into an application by implementing
the com.opensymphony.xwork2.Result interface. Custom Result Types might include
generating an email or JMS message, generating images, and so forth.

Registering Result Types


All Result Types are plugged in via the Result Configuration.

Chain Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Philip Luppens on Feb 10, 2007 (view change) show
comment

This result invokes an entire other action, complete with it's own interceptor stack and
result.

Parameters
• actionName (default) - the name of the action that will be chained to
• namespace - used to determine which namespace the Action is in that we're
chaining. If namespace is null, this defaults to the current namespace
• method - used to specify another method on target action to be invoked. If null,
this defaults to execute method
• skipActions - (optional) the list of comma separated action names for the actions
that could be chained to

Examples
<package name="public" extends="struts-default">
<!-- Chain creatAccount to login, using the default parameter -->
<action name="createAccount" class="...">
<result type="chain">login</result>
</action>

<action name="login" class="...">


<!-- Chain to another namespace -->
<result type="chain">
<param name="actionName">dashboard</param>
<param name="namespace">/secure</param>
</result>
</action>
</package>

<package name="secure" extends="struts-default" namespace="/secure">


<action name="dashboard" class="...">
<result>dashboard.jsp</result>
</action>
</package>
Dispatcher Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Ted Husted on Sep 10, 2006 (view change)

Includes or forwards to a view (usually a jsp). Behind the scenes Struts will use a
RequestDispatcher, where the target servlet/JSP receives the same request/response
objects as the original servlet/JSP. Therefore, you can pass data between them using
request.setAttribute() - the Struts action is available.

There are three possible ways the result can be executed:

• If we are in the scope of a JSP (a PageContext is available), PageContext's {@link


PageContext#include(String) include} method is called.
• If there is no PageContext and we're not in any sort of include (there is no
"javax.servlet.include.servlet_path" in the request attributes), then a call to
{@link RequestDispatcher#forward(javax.servlet.ServletRequest,
javax.servlet.ServletResponse) forward} is made.
• Otherwise, {@link RequestDispatcher#include(javax.servlet.ServletRequest,
javax.servlet.ServletResponse) include} is called.

Parameters
• location (default) - the location to go to after execution (ex. jsp).
• parse - true by default. If set to false, the location param will not be parsed for
Ognl expressions.
Examples
<result name="success" type="dispatcher">
<param name="location">foo.jsp</param>
</result>
FreeMarker Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Ted Husted on Sep 10, 2006 (view change)

Renders a view using the Freemarker template engine.

The FreemarkarManager class configures the template loaders so that the template
location can be either

• relative to the web root folder. eg /WEB-INF/views/home.ftl


• a classpath resuorce. eg com/company/web/views/home.ftl

Also see Freemarker Support.

Parameters
• location (default) - the location of the template to process.
• parse - true by default. If set to false, the location param will not be parsed for
Ognl expressions.
• contentType - defaults to "text/html" unless specified.
• writeIfCompleted - false by default, write to stream only if there isn't any error
processing the template. Setting template_exception_handler=rethrow in
freemarker.properties will have the same effect.

Examples
<result name="success" type="freemarker">foo.ftl</result>
HttpHeader Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Ted Husted on Sep 10, 2006 (view change)

A custom Result type for setting HTTP headers and status by optionally evaluating
against the ValueStack. This result can also be used to send and error to the client.

Parameters
• status - the http servlet response status code that should be set on a response.
• parse - true by default. If set to false, the headers param will not be parsed for
Ognl expressions.
• headers - header values.
• error - the http servlet response error code that should be set on a response.
• errorMessage - error message to be set on response if 'error' is set.

Examples
<result name="success" type="httpheader">
<param name="status">204</param>
<param name="headers.a">a custom header value</param>
<param name="headers.b">another custom header value</param>
</result>

<result name="proxyRequired" type="httpheader">


<param name="error">305</param>
<param name="errorMessage">this action must be accessed through a
prozy</param>
</result>
Redirect Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by David H. DeWolf on Dec 01, 2006 (view change)

Calls the {@link HttpServletResponse#sendRedirect(String) sendRedirect} method to the


location specified. The response is told to redirect the browser to the specified location (a
new request from the client). The consequence of doing this means that the action (action
instance, action errors, field errors, etc) that was just executed is lost and no longer
available. This is because actions are built on a single-thread model. The only way to
pass data is through the session or with web parameters (url?name=value) which can be
OGNL expressions.

Parameters
• location (default) - the location to go to after execution.
• parse - true by default. If set to false, the location param will not be parsed for
Ognl expressions.

This result follows the same rules from StrutsResultSupport.

Examples
<result name="success" type="redirect">
<param name="location">foo.jsp</param>
<param name="parse">false</param>
</result>
Redirect Action Result
Edit Page Browse Space Add Page Add News
Added by Patrick Lightbody, last edited by Ted Husted on Sep 04, 2006 (view change)

This result uses the ActionMapper provided by the ActionMapperFactory to redirect the
browser to a URL that invokes the specified action and (optional) namespace. This is
better than the ServletRedirectResult because it does not require you to encode the URL
patterns processed by the ActionMapper in to your struts.xml configuration files. This
means you can change your URL patterns at any point and your application will still
work. It is strongly recommended that if you are redirecting to another action, you use
this result rather than the standard redirect result.

See examples below for an example of how request parameters could be passed in.

See ActionMapper for more details

Parameters
• actionName (default) - the name of the action that will be redirect to
• namespace - used to determine which namespace the action is in that we're
redirecting to . If namespace is null, this defaults to the current namespace

Examples
<package name="public" extends="struts-default">
<action name="login" class="...">
<!-- Redirect to another namespace -->
<result type="redirect-action">
<param name="actionName">dashboard</param>
<param name="namespace">/secure</param>
</result>
</action>
</package>

<package name="secure" extends="struts-default" namespace="/secure">


<-- Redirect to an action in the same namespace -->
<action name="dashboard" class="...">
<result>dashboard.jsp</result>
<result name="error" type="redirect-action">error</result>
</action>

<action name="error" class="...">


<result>error.jsp</result>
</action>
</package>

<package name="passingRequestParameters" extends="struts-default"


namespace="/passingRequestParameters">
<-- Pass parameters (reportType, width and height) -->
<!--
The redirect-action url generated will be :
/genReport/generateReport.action?reportType=pie&width=100&height=100
-->
<action name="gatherReportInfo" class="...">
<result name="showReportResult" type="redirect-action">
<param name="actionName">generateReport</param>
<param name="namespace">/genReport</param>
<param name="reportType">pie</param>
<param name="width">100</param>
<param name="height">100</param>
</result>
</action>
</package>
Stream Result
Edit Page Browse Space Add Page Add News
Added by Patrick Lightbody, last edited by Musachy Barroso on Jan 02, 2007 (view
change) show comment

A custom Result type for send raw data (via an InputStream) directly to the
HttpServletResponse. Very useful for allowing users to download content.

If you are running your app server under HTTPS and having issues with
PDF's or other file streams you should take a look at HTTPS and IE
Issues

Parameters
• contentType - the stream mime-type as sent to the web browser (default =
text/plain).
• contentLength - the stream length in bytes (the browser displays a progress bar).
• contentDispostion - the content disposition header value for specifing the file
name (default = inline, values are typically filename="document.pdf".
• inputName - the name of the InputStream property from the chained action
(default = inputStream).
• bufferSize - the size of the buffer to copy from input to output (default = 1024).

Examples
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">filename="document.pdf"</param>
<param name="bufferSize">1024</param>
</result>
Apache Struts 2 Documentation
Velocity Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Ted Husted on Sep 10, 2006 (view change)

Using the Servlet container's JspFactory, this result mocks a JSP execution environment
and then displays a Velocity template that will be streamed directly to the servlet output.

Parameters
• location (default) - the location of the template to process.
• parse - true by default. If set to false, the location param will not be parsed for
Ognl expressions.

This result follows the same rules from StrutsResultSupport.

Examples
<result name="success" type="velocity">
<param name="location">foo.vm</param>
</result>
XSL Result
Edit Page Browse Space Add Page Add News
Added by casey, last edited by Ted Husted on Sep 10, 2006 (view change)

XSLTResult uses XSLT to transform an action object to XML. The recent version has
been specifically modified to deal with Xalan flaws. When using Xalan you may notice
that even though you have a very minimal stylesheet like this one

<xsl:template match="/result">
<result/>
</xsl:template>

Xalan would still iterate through every property of your action and all its descendants.

If you had double-linked objects, Xalan would work forever analysing an infinite object
tree. Even if your stylesheet was not constructed to process them all. It's because the
current Xalan eagerly and extensively converts everything to its internal DTM model
before further processing.

That's why there's a loop eliminator added that works by indexing every object-property
combination during processing. If it notices that some object's property was already
walked through, it doesn't go any deeper. Say you have two objects, x and y, with the
following properties set (pseudocode):

x.y = y;
and
y.x = x;
action.x=x;

Due to that modification, the resulting XML document based on x would be:

<result>
<x>
<y/>
</x>
</result>

Without it there would be endless x/y/x/y/x/y/... elements.


The XSLTResult code tries also to deal with the fact that DTM model is built in a manner
that children are processed before siblings. The result is that if there is object x that is
both set in action's x property, and very deeply under action's a property then it would
only appear under a, not under x. That's not what we expect, and that's why XSLTResult
allows objects to repeat in various places to some extent.

Sometimes the object mesh is still very dense and you may notice that even though you
have a relatively simple stylesheet, execution takes a tremendous amount of time. To help
you to deal with that obstacle of Xalan, you may attach regexp filters to elements paths
(xpath).

Note: In your .xsl file the root match must be named result.
This example will output the username by using getUsername on your action class:

<xsl:template match="result">
<html>
<body>
Hello <xsl:value-of select="username"/> how are you?
</body>
</html>
<xsl:template/>

In the following example the XSLT result would only walk through action's properties
without their childs. It would also skip every property that has "hugeCollection" in their
name. Element's path is first compared to excludingPattern - if it matches it's no longer
processed. Then it is compared to matchingPattern and processed only if there's a match.

<result name="success" type="xslt">


<param name="location">foo.xslt</param>
<param name="matchingPattern">^/result/[^/*]$</param>
<param name="excludingPattern">.*(hugeCollection).*</param>
</result>

Parameters
• location (default) - the location to go to after execution.
• parse - true by default. If set to false, the location param will not be parsed for
Ognl expressions.
• matchingPattern - Pattern that matches only desired elements, by default it
matches everything.
• excludingPattern - Pattern that eliminates unwanted elements, by default it
matches none.

struts.properties related configuration:

• struts.xslt.nocache - Defaults to false. If set to true, disables stylesheet caching.


Good for development, bad for production.
Examples
<result name="success" type="xslt">
<param name="location">foo.xslt</param>
<param name="matchingPattern">^/result/[^/*]$</param>
<param name="excludingPattern">.*(hugeCollection).*</param>
</result>
PlainText Result
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Sep 03, 2006 (view change)

A result that send the content out as plain text. Usefull typically when needed to display
the raw content of a JSP or Html file for example.

Parameters
• location (default) = location of the file (jsp/html) to be displayed as plain text.
• charSet (optional) = character set to be used. This character set will be used to set
the response type (eg. Content-Type=text/plain; charset=UTF-8) and when
reading using a Reader. Some example of charSet would be UTF-8, ISO-8859-1
etc.

Examples
<action name="displayJspRawContent" >
<result type="plaintext">/myJspFile.jsp</result>
</action>

<action name="displayJspRawContent" >


<result type="plaintext">
<param name="location">/myJspFile.jsp</param>
<param name="charSet">UTF-8</param>
</result>
</action>
DispatcherListener
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Oct 17, 2006 (view change)

Use a DispatcherListener object to execute code when a Dispatcher is initalized or


destroyed. A DispatcherListener is an easy way to associate customizable components
like a ConfigurationManager with a Dispatcher.

Example
static {
Dispatcher.addDispatcherListener(new DispatcherListener() {
public void dispatcherInitialized(Dispatcher du) {
// do something to Dispatcher after it is initialized eg.
du.setConfigurationManager(....);
}

public void dispatcherDestroyed(Dispatcher du) {


// do some cleanup after Dispatcher is destroyed.
}
});
}
PreResultListener
Edit Page Browse Space Add Page Add News
Added by tm_jee, last edited by Ted Husted on Feb 12, 2007 (view change)

A PreResultListener can affect an action invocation between the interceptor/action phase


and the result phase. Typical uses include switching to a different Result or somehow
modifying the Result or Action objects before the Result executes.

Examples
A PreResultListener can be added by an Action or an Interceptor.

By an Action
public class MyAction extends ActionSupport {
...
public String execute() throws Exception {
ActionInvocation invocation =
ActionContext.getActionInvocation();
invocation.addPreResultListener(new PreResultListener() {
public void beforeResult(ActionInvocation invocation,
String resultCode) {
// perform operation necessary before Result execution
}
});
}
...
}

By an Interceptor
public class MyInterceptor extends AbstractInterceptor {
...
public String intercept(ActionInvocation invocation) throws
Exception {
invocation.addPreResultListener(new PreResultListener() {
public void beforeResult(ActionInvocation invocation,
String resultCode) {
// perform operation necessary before Result execution
}
});
}
...
}

You might also like