Struts2 submit form doesn't navigate to new view - struts2

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.

Related

Populating drop down in Struts2

I am using struts2 for implementing my application. In my application I have to implement two drop downs, value of the second drop down is dependent on first drop down. I got reference from an example and implemented my code accordingly, but still not getting the result. Please give your suggestion to make this code work.
SupporterAction.java
package action;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import entityBean.TicketDataBean;
import entityBean.UserBean;
import entityListener.SupporterListener;
import entityManager.Application;
#SuppressWarnings("serial")
public class SupporterAction extends ActionSupport{
private String application;
private String number;
private List<String> applicationNames;
List<String> ticketNumber;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public List<String> getApplicationNames() {
return applicationNames;
}
public void setApplicationNames(List<String> applicationNames) {
this.applicationNames = applicationNames;
}
public List<String> getTicketNumber() {
return ticketNumber;
}
public void setTicketNumber(List<String> ticketNumber) {
this.ticketNumber = ticketNumber;
}
public String getApplication() {
return application;
}
public void setApplication(String application) {
this.application = application;
}
public String getJSON() {
return execute();
}
#SuppressWarnings("unchecked")
public String execute()
{
#SuppressWarnings("rawtypes")
Map session = ActionContext.getContext().getSession();
System.out.println(session.get("currentSessionUser"));
applicationNames = new ArrayList<String>();
UserBean userBean = (UserBean)session.get("currentSessionUser");
List<Application> applicationObj = userBean.getApplication();
for (Application obj : applicationObj)
{
System.out.println(obj.getApplicationName());
applicationNames.add(obj.getApplicationName());
}
session.put("ApplicationNames",applicationNames);
System.out.println("Hello");
System.out.println(application);
if(application != null)
{
ticketNumber=new ArrayList<String>();
System.out.println("Hello 1");
SupporterListener sl = new SupporterListener();
List<TicketDataBean> tdbList = sl.getPendingTickets(application);
if(!tdbList.isEmpty())
{
for(TicketDataBean td : tdbList)
{
ticketNumber.add(td.getNumber());
}
session.put("logined","true");
session.put("TicketNumber",ticketNumber);
}
}
return "success";
}
}
Supporter.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix="s" uri="/struts-tags" %>
<%# taglib prefix="sj" uri="/struts-jquery-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<s:form id="formSelectReload" theme="simple" cssClass="yform" action="getApplicationList">
<fieldset>
<div class="type-text">
<label for="application">Application : </label>
<s:url var="remoteurl" action="getApplicationList" namespace="/"/>
<sj:select href="%{remoteurl}" id="application" name="application"
list="applicationNames" onChange="reloadsecondlist" emptyOption="false"
headerKey="-1" headerValue="Please Select a Application" />
</div>
<s:property value="#session.ApplicationNames"/>
<div class="type-text">
<label for="number">Ticket Number: </label>
<s:url var="remoteurl" action="getApplicationList" namespace="/"/>
<sj:select href="%{remoteurl}" id="ticketNumber" formIds="formSelectReload"
reloadTopics="reloadsecondlist" name="number"
list="ticketNumber"
emptyOption="false"
headerKey="-1" headerValue="Please Select a Ticket Number"/>
</div>
<div class="type-button">
<sj:submit
id="submitFormSelectReload"
/>
</div>
</fieldset>
</s:form>
</body>
</html>
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />
<constant name="struts.custom.i18n.resources" value="ApplicationResources" />
<package name="login" extends="struts-default">
<action name="login"
class="action.LoginAction"
method="execute">
<result name="success">/Home.jsp</result>
<result name="error">/InvalidLogin.jsp</result>
<result name="INVALID SESSION">/Home.jsp</result>
</action>
<action name="logout"
class="action.LoginAction"
method="logout">
<result name="success">/Login.jsp</result>
</action>
<action name="register">
<result>/Register.jsp</result></action>
<action name="importexcel">
<result>/ImportExcel.jsp</result></action>
<action name="supporter" class="action.SupporterAction"
method="execute">
<result name="success">/Supporter.jsp</result></action>
<action name="registeruser"
class="action.RegisterAction"
method="register">
<result name="success">/UserLogged.jsp</result>
<result name="error">/InvalidLogin.jsp</result>
<result name="INVALID SESSION">/Register.jsp</result>
</action>
<action name="importExcel"
class="action.ImportExcelAction"
method="importExcel">
<result name="success">/Home.jsp</result>
<result name="error">/InvalidLogin.jsp</result>
<result name="INVALID SESSION">/Home.jsp</result>
</action>
</package>
<package name="default" extends="struts-default,json-default" namespace="/">
<action name="getApplicationList"
class="action.SupporterAction" >
<result type="json" />
</action>
</package>
</struts>
jar files
Image of jar files
Result I am getting is
Image of result
As we can see in Image of result, list is being populated but I am not able to get it in drop down. Please suggest something.
Thank you in advance for your answers.
The prepare() interceptor is your friend.
https://struts.apache.org/docs/prepare-interceptor.html

How to show a result message using Struts2

I have a search box on my index page, it is supposed to return a message if no result was found or redirect to result page if it succeeded.
Currently, if results were found it redirects to the new page, and if not will stay on the same page (index) but it does not show the message, just add the mymessage parameter to the page address as following
www.address.com/index.jsp?mymessage=Sorry,No+results+were+found.
Index
.......
<s:property value="mymessage"/>
SearchBox
public String search(){
....
if(found)
return "success";
else
return "failed;
}
struts.xml
<package name="Search" extends="default" namespace="/Search">
<action name="*" method="{1}" class="com.myproject.myclasses.Search">
<result name="success" type="tiles">search</result>
<result name="failed" type="redirectAction">
<param name="actionName">index</param>
<param name="namespace">/</param>
<param name="mymessage">${mymessage}</param>
</result>
</action>
</package>
I think <s:property> expects a getter getMyMessage() on your action class to populate
values can you try <s:property value="#request.mymessage" />
OR
Why can't you use action errors?
public String search(){
....
if(found) {
return "success";
}
else {
addActionError("No results found");
return "failed;
}
}
Now in the index.jsp add the following,
<s:if test="hasActionErrors()">
<s:iterator value="actionErrors">
<s:property escape="false"/>
</s:iterator>
</s:if>

Struts 2 server side validation using XML not working for struts action

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.

struts2 global result not redirecting to action

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.

Struts 2 using tokenSession Interceptor unable to get form values after submit

I have following simple code for login & secured login. For secured login I am using tokenSession interceptor at the time of form submit . In success.jsp I am unable to get the userId value if I submit secureLogin but fine with Login . Can anyone pls help me what is the reason behind it.
<%# taglib prefix="s" uri="/struts-tags" %>
<html>
<body><LOGIN.JSP>
<s:form action="login" >
<s:textfield name="userId" label="Login Id"/><br>
<s:password name="password" label="Password"/><br>
<s:submit value="Login" align="center"/>
</s:form>
<s:form action="secureLogin" >
<s:textfield name="userId" label="Login Id"/><br>
<s:password name="password" label="Password"/><br>
<s:token />
<s:submit value="secureLogin" align="center"/>
</s:form>
</body>
</html>
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="tokenSession" class = "org.apache.struts2.interceptor.TokenSessionStoreInterceptor" />
</interceptors>
<global-results>
<result name="invalid.token">/error.jsp</result>
</global-results>
<action name="secureLogin" class="com.actions.HelloAction" method="secureLogin">
<result name="success">/success.jsp</result>
<result name="failure">/login.jsp</result>
<interceptor-ref name="tokenSession" />
</action>
<action name="login" class="com.actions.HelloAction" method="login">
<result name="success">/success.jsp</result>
<result name="failure">/login.jsp</result>
</action>
</package>
</struts>
package com.actions;
public class HelloAction {
private String userId;
private String password;
public String execute() {
return "success";
}
public String login(){
return "success";
}
public String secureLogin(){
return "success";
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
<%# taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>SUCCESS.JSP</title>
</head>
<body>
Welcome <b><s:property value="userId"/></b> , you have loged in. <br />
</body>
</html>
you need a interceptor-stack
<struts>
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="tokenSession" class = "org.apache.struts2.interceptor.TokenSessionStoreInterceptor" />
<interceptor-stack name="yourStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="tokenSession"></interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="yourStack"/>
<global-results>
<result name="invalid.token">/error.jsp</result>
</global-results>
</package>
</struts>
Here is a link: Interceptors

Resources