I have a custom interceptor (TransferInterceptor) that checks for a function change within my application. When it changes, the interceptor returns a post-processing string (the result) containing the global results name of the action that I want to redirect to. I have the results defined in the global results of my struts.xml file, but they do not redirect to the specified action. I have a 'Login' global result that works fine, but it is being called from a JSP with:
<s:a action="Login.action">Login</s:a>
The struts.xml file:
<package name="default" extends="struts-default" namespace="/">
<interceptors>
<interceptor name="AuthenticationInterceptor" class="com.purchasing.utils.AuthenticationInterceptor" />
<interceptor name="TransferInterceptor" class="com.purchasing.utils.TransferInterceptor" />
<interceptor-stack name="secureStack">
<interceptor-ref name="TransferInterceptor" />
<interceptor-ref name="AuthenticationInterceptor" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="secureStack" />
<global-results>
<result name="Login">login.jsp</result>
<result name="RESULTA" type="redirect">ACTIONA</result>
<result name="RESULTB" type="redirect">ACTIONB</result>
</global-results>
<action name="Login" class="com.purchasing.actions.Login">
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">welcome.jsp</result>
<result name="error">login.jsp</result>
<result name="input">login.jsp</result>
</action>
<action name="ACTIONA" class="com.purchasing.actions.ACTIONA">
<result name="success">ACTIONA.jsp</result>
<result name="error">ACTIONA.jsp</result>
<result name="input">ACTIONA.jsp</result>
</action>
<action name="ACTIONB" class="com.purchasing.actions.ACTIONB">
<result name="success">ACTIONB.jsp</result>
<result name="error">ACTIONB.jsp</result>
<result name="input">ACTIONB.jsp</result>
</action>
</package>
The TransferInterceptor:
public String intercept(ActionInvocation ai) throws Exception
{
String result = ai.invoke();
session = ai.getInvocationContext().getSession();
fl = (FunctionLine) session.get(Constants.FUNCTION_LINE);
function = fl.getFl_function();
last_function = (Integer) session.get(Constants.LAST_FUNCTION);
if (function != last_function) {
session.put(Constants.LAST_FUNCTION, new Integer(function));
switch (function) {
case 61: return "RESULTA";
case 62: return "RESULTB";
}
return "error";
}
else {
return result;
}
}
Any help would be greatly appreciated!
As per #Lukasz comment :
If you want to redirect to an action use redirectAction result type instead of redirect which is used to redirect to static resources
It still won't work, because the ACTIONB & ACTIONA never executes since they go through the same interceptor stack, which returned redirectAction result & hence, it's kinda stuck in an infinite loop.
Related
I'm using Struts2 (version 2.5.14.1) with the Spring and Tiles plug-ins.
This is my (relevant) struts.xml configuration:
<package name="enrollment" namespace="/enrollment" extends="struts-bean-validation">
<result-types>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
<action name="start" class="io.shido.struts.action.enrollment.StartAction">
<result name="success" type="tiles">enrollment.start.tiles</result>
</action>
<action name="personal-info" class="io.shido.struts.action.enrollment.PersonalInfoAction">
<result name="input" type="tiles">enrollment.personal-info.tiles</result>
<result name="success" type="tiles">enrollment.billing-info.tiles</result>
</action>
<action name="billing-info" class="io.shido.struts.action.enrollment.BillingInfoAction">
<result name="input" type="tiles">enrollment.billing-info.tiles</result>
<result name="success" type="tiles">enrollment.finish.tiles</result>
</action>
<action name="finish" class="io.shido.struts.action.enrollment.FinishAction">
<result name="success" type="tiles">enrollment.finish.tiles</result>
</action>
</package>
...the JSP file that holds one of the forms:
<%# taglib prefix="s" uri="/struts-tags" %>
<link rel="stylesheet" href="<s:url value='/resources/styles/enrollment.styles.css' />">
<s:form cssClass="form-input-info" action="personal-info" method="post">
<legend><s:text name="legend.text" /></legend>
<hr>
<s:textfield cssClass="form-control" key="textfield.first-name" name="personalInfo.firstName" />
<s:textfield cssClass="form-control" key="textfield.last-name" name="personalInfo.lastName" />
<s:textfield cssClass="form-control" key="textfield.email" name="personalInfo.email" />
<s:textfield cssClass="form-control" key="textfield.phone-number" name="personalInfo.phoneNumber" />
<s:textfield cssClass="form-control" key="textfield.age" name="personalInfo.age" />
<s:submit class="btn btn-primary btn-lg btn-block" key="submit.continue" />
</s:form>
...and finally the (super simple) Action class:
package io.shido.struts.action.enrollment;
// imports
public final class PersonalInfoAction extends ActionSupport {
private static final long serialVersionUID = 3560814234131884357L;
private final Logger logger = LogManager.getLogger(this.getClass());
private PersonalInfoHandler handler;
#Valid
private PersonalInfo personalInfo;
#Override
public String execute() {
// If personalInfo is not null is guaranteed to be valid due to Bean Validation contraints
if (null != personalInfo) {
logger.debug("Processing personal info...");
handler.save(personalInfo);
return Action.SUCCESS;
}
logger.info("Collecting personal info...");
return Action.INPUT;
}
public PersonalInfoHandler getHandler() { return handler; }
public void setHandler(final PersonalInfoHandler handler) { this.handler = handler; }
public PersonalInfo getPersonalInfo() { return personalInfo; }
public void setPersonalInfo(final PersonalInfo personalInfo) {
this.personalInfo = personalInfo;
this.personalInfo.normalize();
}
}
The issue is, whenever I submit that form, I'm expecting the Bean Validation to kick out and check all the annotated fields (check, this is happening) and when everything is fine, send the flow to /WEB-INF/content/enrollment/billing-info.jsp (defined in Tiles by enrollment.billing-info.tiles)...but all I see is (almost) the "billing info" form with the wrong labels. See the below picture:
The URL should have changed, as well as the labels. To put the cherry on top, if I click the Continue button again, the form is displayed then correctly.
Any clues?
I have no direct answer but you could try to use a redirect action instead of using the tiles several times.
So you could try this here:
<action name="personal-info" class="io.shido.struts.action.enrollment.PersonalInfoAction">
<result name="input" type="tiles">enrollment.personal-info.tiles</result>
<result name="success" type="redirectAction">
<param name="actionName">billing-info</param>
</result>
</action>
And if you need to transfer some kind of id to show the data you can use additional params in the struts.xml like this:
<!-- rest as above -->
<result>
<param name="param1">${value1}</param>
</result>
The param1 must have valid getter/setter-methods in both actions to transfer the information.
I am getting following exception
SEVERE: Exception occurred during processing request: No result defined for action iland.login.LoginAction and result AddBill
No result defined for action iland.login.LoginAction and result AddBill
Here AddBill amd dashboard are two actions based on role value I would like to redirect it to appropriate action
In action:
if (role > 3) {
return "dashboard";
} else if (role <= 3) {
return "AddBill";
}
In struts.xml
<action name="login" class="iland.login.LoginAction" method="doLogin">
<result name="success" type="redirect">${url}</result>
<result name="input">/pages/login.jsp</result>
</action>
<action name="dashboard" class="iland.login.DashBoardAction" method="fetch">
<result name="success">/pages/dashboadr.jsp</result>
<result name="input">/pages/dashboadr.jsp</result>
<result name="login">/pages/login.jsp</result>
</action>
<action name="AddBill" class="iland.login.LoginForPage">
<result name="success">/pages/billing/AddBill.jsp</result>
<result name="input">/pages/billing/AddBill.jsp</result>
<result name="login">/pages/login.jsp</result>
</action>
You must always return a RESULT.
A RESULT may be mapped to another Action with the RedirectAction result type. You can't call an action by returning its name.
You need this:
<action name="login" class="iland.login.LoginAction" method="doLogin">
<result name="success" type="redirect">${url}</result>
<result name="input">/pages/login.jsp</result>
<result name="AddBill" type="redirectAction">
<param name="actionName">AddBill</param>
</result>
</action>
<action name="AddBill" class="iland.login.LoginForPage">
<result name="success">/pages/billing/AddBill.jsp</result>
<result name="input">/pages/billing/AddBill.jsp</result>
<result name="login">/pages/login.jsp</result>
</action>
Edit
Otherwise, as suggested by #LukaszLenart 's comment, you can return an instance of the Result interface directly from the action:
return new ServletActionRedirectResult("AddBill");
I have created my own Interceptor, MyInterceptor, as follows:
public class MyInterceptor extends MethodFilterInterceptor
{
String inv=null;
#Override
protected String doIntercept(ActionInvocation invocation)
{
System.out.println("MyInterceptor fired");
try
{
inv=invocation.invoke();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return inv;
}
}
My action class is this:
public class MyStruts2Class extends ActionSupport implements Preparable
{
#Override
public void prepare()
{
System.out.println("HI Prepare");
}
public String execute()
{
System.out.println("Hi Execute");
return "success";
}
}
... and my struts.xml is this:
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="myIntercept" class="org.sagar.intercetors.MyInterceptor"/> </interceptors>
<action name="defaultStrutsAction" class="org.sagar.struts.MyStruts2Class" method="execute">
<interceptor-ref name="myIntercept"/> <result name="success">success.jsp</result>
</action>
</struts>
My problem is when I fire my defaultStrutsAction class, MyInterceptor runs fine but the prepare method in the Action class is not invoked which it should, as I have implemented the Preparable interface.
If I omit this line:
<interceptor-ref name="myIntercept"/>
... in struts.xml, the prepare method in the Action class runs fine.
I am new in Struts2, but can't figure out what is wrong here.
You have to add the prepare interceptor to the interceptor stack for the prepare method to get called in the action. You can do this in a few ways, one is to define the action itself to have the prepare interceptor. Like so. The order matters.
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="myIntercept" class="org.sagar.intercetors.MyInterceptor"/> </interceptors>
<action name="defaultStrutsAction" class="org.sagar.struts.MyStruts2Class" method="execute">
<interceptor-ref name="myIntercept"/>
<interceptor-ref name="prepare"/>
<result name="success">success.jsp</result>
</action>
</struts>
You can also define the interceptor stack in the interceptors tag and use the default-interceptor-ref tag
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="myIntercept" class="org.sagar.intercetors.MyInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="myIntercept"/>
<interceptor-ref name="prepare"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
<action name="defaultStrutsAction" class="org.sagar.struts.MyStruts2Class" method="execute">
<result name="success">success.jsp</result>
</action>
</struts>
And finally, what I think your interceptor stack should look like,
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="myIntercept" class="org.sagar.intercetors.MyInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="myIntercept"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
<action name="defaultStrutsAction" class="org.sagar.struts.MyStruts2Class" method="execute">
<result name="success">success.jsp</result>
</action>
</struts>
In this example, I ref defaultStack instead of just prepare, because defaultStack already has prepare defined along with other common interceptors that you may want to use.
in your example when you omit this line
<interceptor-ref name="myIntercept"/>
the prepare interceptor gets called because it is in the defaultStack already defined by struts2.
Take a look at the stacks defined in link provided by Steven Benitez.
Under default configuration.
http://struts.apache.org/release/2.3.x/docs/interceptors.html
Hope that helps.
here is an example of my reply to your comment.
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="myIntercept" class="org.sagar.intercetors.MyInterceptor"/> </interceptors>
<action name="defaultStrutsAction" class="org.sagar.struts.MyStruts2Class" method="execute">
<interceptor-ref name="myIntercept"/>
<interceptor-ref name="defaultStack"/>
<result name="success">success.jsp</result>
</action>
</struts>
I am using Struts 2 Validator framework with XML. But the server side validations are not working. Following is the code snippet.
Struts.xml
<interceptor-stack name="MyStack">
<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\..*,^struts\..*,.*\\.*,.*\(.*,.*\).*,.*#.*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse,reset</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse,reset</param>
</interceptor-ref>
</interceptor-stack>
<action name="process" method="process" class="org.web.action.MyAction">
<interceptor-ref name="MyStack" />
<result name="success">success.jsp</result>
<result name="error">error.jsp</result>
<result name="wait">wait.jsp</result>
<result name="input">Index.jsp</result>
</action>
MyAction.java
public class MyAction extends ActionSupport {
private String amount;
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String process() throws Exception {
//some processing done here
}
}
MyAction-process-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator Config 1.0//EN"
"##xwork.validator.dtd##">
<validators>
<field name="amount">
<field-validator type="requiredstring" short-circuit="true">
<message key="order.amount.required"/>
</field-validator>
<field-validator type="amountValidator" short-circuit="true">
<message key="order.amount.invalid" />
</field-validator>
</field>
</validators>
AmountValidator.java
public class AmountValidator extends FieldValidatorSupport {
public Struts2DonationAmountValidator() {
super();
}
public void validate(Object object) throws ValidationException {
//some validation check here
}
}
validators.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator Config 1.0//EN"
"https://s3.amazonaws.com/static/xwork-validator-config-1.0.dtd">
<validators>
<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator" />
<validator name="amountValidator" class="org.web.validator.AmountValidator"/>
</validators>
Index.jsp
<input type="text" id="amountTemp" name="amount">
I have put sysouts at the first line of validator as well as in action method. The sysout in AmountValidator.java is not called. Even while debugging, the validation doesn't get called and the control jumps to action method. There is no hint of any exception in console. The action method flow works fine.
Thanks in advance!!!
I found a other solution on http://struts.apache.org/release/2.1.x/docs/validation.html. I changed the name of my MyAction-process-validation.xml to MyAction-processAction-validation.xml and named my action as processAction instead of process. That means instead of method I used action name.
Thanks for your support.
i'm trying to implement jasper report with struts2,for now i can't get my report.i do realy nead help,here is my struts.xml
<struts>
<package extends="jasperreports-default" name="default" namespace="/">
<result-types>
<result-type class="org.apache.struts2.views.jasperreports.JasperReportsResult" name="jasper"/>
</result-types>
<action class="action.JasperAction" name="StrutsJasperAction" method="execute">
<result name="success" type="jasper">
<param name="location">/jasper/sample.jasper</param>
<param name="dataSource">stList</param>
<param name="format">PDF</param>
</result>
</action>
</package>
</struts>
and i want to know in what location should i do.here is my structure of my app.
and in my action JasperAction what should i do at JasperCompileReportToFile.compileReportToFile(....??????) .
try {
JasperCompileManager.compileReportToFile(
"D:/Test/workspace/testJasper/WebContent/jasper/sample.jrxml",
"D:/Test/workspace/testJasper/WebContent/jasper/sample.jasper");
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
if you need more details just ask.