Struts2 keep same action url if validation fail using struts2-bean-validation-plugin - struts2

I am using Struts 2 and I have two action one will show the register form and second will be register user.
I want to achieve is while submitting form if any validation fail then user will be redirect to previous page with errors details.
I have use struts2-bean-validation-plugin for validating user bean.
My configuration files are as below
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.objectFactory" value="spring" />
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="beanValidation" class="org.apache.struts.beanvalidation.validation.interceptor.BeanValidationInterceptor" />
<interceptor-stack name="appDefaultStack">
<interceptor-ref name="beanValidation"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<action name="userRegisterForm" method="userRegisterForm" class="com.pc.collabtest.actions.UserRegisterAction">
<result name="success">/userRegisterForm.jsp</result>
</action>
<action name="userRegister" method="userRegister" class="com.pc.collabtest.actions.UserRegisterAction" >
<interceptor-ref name="appDefaultStack"/>
<result name="userList" type="redirectAction">userList</result>
<result name="userRegisterForm" type="redirectAction">userRegisterForm</result>
<result name="input" type="redirectAction">userRegisterForm</result>
</action>
</package>
</struts>
And Action class is
package com.pc.collabtest.actions;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionSupport;
import com.pc.collabtest.model.User;
import com.pc.collabtest.service.UserService;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Component
public class UserRegisterAction extends ActionSupport {
private static final long serialVersionUID = 1L;
#Valid
public User user;
#Autowired
private UserService userService;
public String userRegisterForm() throws Exception {
return "success";
}
public String userRegister() throws Exception {
if (user != null) {
if(userService.saveUser(user) != null) {
return "userList";
}
}
return "userRegisterForm";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

Actually I need some configuration changes in struts.xml file you can see I have create two package as I don't need validation in every action i.e showing registration form doesn't need any validation where submit registration form needed. so I put u userRegister action in struts-bean-validation package. and whenever userRegister(submit) action return input result because of validation fail we will redirect userRegisterForm to show registration form but at this point struts will create new request object so we will loose error result so for that we use struts default interceptor store with operation mode STORE which will store error result in session and in userRegisterForm action again we use store interceptor but with operation mode RETRIEVE so that struts will fetch error result from session.
Note here you can see I use beanValidationDefaultStack interceptor which is mention in struts2-bean-validation-plugin.jar struts-plugin.xml file. because what I assume if we use interceptor then struts will now use default interceptor.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.objectFactory" value="spring" />
<package name="default" extends="struts-default">
<action name="userRegisterForm" method="userRegisterForm" class="com.pc.collabtest.actions.UserRegisterAction">
<interceptor-ref name="store"><param name="operationMode">RETRIEVE</param></interceptor-ref>
<result name="success">/userRegisterForm.jsp</result>
</action>
</package>
<package name="my-bean-validation" extends="struts-bean-validation">
<action name="userRegister" method="userRegister" class="com.pc.collabtest.actions.UserRegisterAction">
<interceptor-ref name="store"><param name="operationMode">STORE</param></interceptor-ref>
<interceptor-ref name="beanValidationDefaultStack"></interceptor-ref>
<result name="userList" type="redirectAction">userList</result>
<result name="userRegisterForm" type="redirectAction">userRegisterForm</result>
<result name="input" type="redirectAction">userRegisterForm</result>
</action>
</package>
</struts> ```

Related

Struts 2 interceptor firing when it shouldn't

I have different areas in my webapp, basically:
Login actions. No special interceptor needs.
Secure zone. Only for authenticated users. AuthenticationInterceptor redirects non authenticated users to logout action.
Admin zone. Only for admin users. AdministrationInterceptor redirects non admin users to logout action.
Hence, I have divided my actions in packages.
numeritos-default is a package with no actions, just to define the
interceptors and a couple stacks, in order to inherit from it.
numeritos-login is a package that inherits directly from
struts-default and, hence, uses the defaultStack from struts.
numeritos-secure inherits from numeritos-default and SHOULD (afaik)
use the numeritos-default default stack.
numeritos-admin inherits
from numeritos-default but defines a different default stack, in
order to add the administrationInterceptor to the default stack.
The thing is, the actions in numeritos-secure are executing the administrationInterceptor when they shouldn't, since their default stack, inherited from numeritos-default doesn't include that interceptor (I can't figure out the reason), hence only admin users can access the application. The rest of users are kicked out of the whole secure zone, when they should be only kicked out of the admin zone.
I have the following struts.xml configuration file. Sorry to post the whole of it, but I think it could help. All classes references are really Spring beans names, since all dependencies are managed by Spring.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="global-messages" />
<constant name="struts.devMode" value="true" />
<constant name="struts.ui.theme" value="simple" />
<package name="numeritos-default" extends="struts-default">
<interceptors>
<!-- Session authentication interceptor -->
<interceptor name="authenticationInterceptor" class="authenticationInterceptor"/>
<!-- Administration privileges interceptor -->
<interceptor name="administrationInterceptor" class="administrationInterceptor"/>
<!-- Caching headers interceptor -->
<interceptor name="cachingHeadersInterceptor" class="cachingHeadersInterceptor"/>
<!-- Default interceptor stack for this package (default + authentication) -->
<interceptor-stack name="numeritosDefaultStack">
<interceptor-ref name="authenticationInterceptor"/>
<interceptor-ref name="cachingHeadersInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
<!-- Default interceptor stack for administration packages (default + administration) -->
<interceptor-stack name="numeritosAdminStack">
<interceptor-ref name="administrationInterceptor"/>
<interceptor-ref name="numeritosDefaultStack"/>
</interceptor-stack>
</interceptors>
<!-- Secure interceptor stack as default -->
<default-interceptor-ref name="numeritosDefaultStack"/>
</package>
<package name="numeritos-login" extends="struts-default">
<action name="welcome" class="welcomeAction">
<result name="success" type="freemarker">ftl/login.ftl</result>
</action>
<action name="login" class="loginAction">
<result name="success" type="redirectAction">exerciseLoad</result>
<result name="input" type="freemarker">ftl/login.ftl</result>
</action>
</package>
<package name="numeritos-secure" extends="numeritos-default">
<!-- Common login result -->
<global-results>
<result name="login" type="redirectAction">logout</result>
</global-results>
<action name="exerciseLoad" class="exerciseLoadAction">
<result name="simple_op" type="freemarker">ftl/simple_operation_view.ftl</result>
<result name="equation" type="freemarker">ftl/equation_view.ftl</result>
</action>
<action name="exerciseCheck" class="exerciseCheckAction">
<result name="success" type="freemarker">ftl/show_exercise_result.ftl</result>
<result name="input" type="freemarker">ftl/answer_format_error.ftl</result>
</action>
<action name="stats" class="statsAction">
<result name="success" type="freemarker">ftl/stats.ftl</result>
</action>
<action name="modulesList" class="modulesListAction">
<result name="success" type="freemarker">ftl/modules_list.ftl</result>
</action>
<action name="selectModule" class="selectModuleAction">
<result name="input" type="freemarker">ftl/modules_list.ftl</result>
<result name="success" type="redirectAction">exerciseLoad</result>
</action>
<action name="userSettings" class="userSettingsAction">
<result name="success" type="freemarker">ftl/user_settings.ftl</result>
</action>
<action name="changePassword" class="changePasswordAction">
<result name="success" type="freemarker">ftl/user_settings.ftl</result>
<result name="input" type="freemarker">ftl/user_settings.ftl</result>
</action>
<action name="logout" class="logoutAction">
<result name="success" type="freemarker">ftl/login.ftl</result>
</action>
</package>
<package name="numeritos-admin" extends="numeritos-secure">
<!-- Admin interceptor stack as default -->
<default-interceptor-ref name="numeritosAdminStack"/>
<!-- Common login result -->
<global-results>
<result name="login" type="redirectAction">logout</result>
</global-results>
<action name="adminConsole" class="adminConsoleAction">
<result name="success" type="freemarker">ftl/admin_console_results.ftl</result>
</action>
<action name="adminConsoleGroups" class="adminConsoleGroupsAction">
<result name="success" type="freemarker">ftl/admin_console_groups.ftl</result>
</action>
<action name="adminCreateGroup" class="adminConsoleGroupsAction" method="create">
<result name="success" type="redirectAction">adminConsoleGroups</result>
</action>
<action name="adminDeleteGroup" class="adminConsoleGroupsAction" method="delete">
<result name="success" type="redirectAction">adminConsoleGroups</result>
</action>
</package>
<package name="json-admin" extends="numeritos-default, json-default">
<interceptors>
<!-- Default interceptor stack for this package (default + administration + json) -->
<interceptor-stack name="numeritosJsonAdminStack">
<interceptor-ref name="administrationInterceptor"/>
<interceptor-ref name="json"/>
<interceptor-ref name="numeritosDefaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="numeritosJsonAdminStack"/>
<action name="jsonTest" class="jsonTestAction">
<result name="success" type="json">
<param name="root">users</param>
</result>
</action>
</package>
</struts>
Defining package configuration elements are only for adding additional configuration to packages that extend it. The packages can contain interceptors, interceptor stacks, actions that can be extended.
The package element has one required attribute name, which acts as the key for later reference to the package. The extends attribute is optional and allows one package to inherit the configuration of one or more previous packages
including all interceptor, interceptor-stack, and action configurations.
Usually packages are separated by namespace attribute which is essential for configuring actions. You can define the abstract package which doesn't contain the action configurations.
The optional abstract attribute creates a base package that can omit the action configuration.
The thing is, you are not using namespace, nor abstract packages and default-intercepto-ref is not inherited to the packages that extends it.

Struts2: can't call action before rendering index.jsp

I've searched for this all over SO, but didn't find a similar situation with the same symptoms. I'm using Sruts2 and trying to invoke an action before rendering the main page of my application (index.jsp). I truly believe that this action is not being called, because I have a System.out.println() (for debugging purposes) in the beginning of the execute() method of the action that is not being printed. Indeed index.jsp is being presented (because it is the default page), but the part that is related to the action is not being run. In conclusion, I think that the problem may reside in the struts.xml file. Below are both the struts.xml and the action file:
Struts.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- The core configuration file for the framework is the default (struts.xml) file
and should reside on the classpath of the webapp (generally /WEB-INF/classes). -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- devMode equals debug information and reload everything for every request -->
<constant name="struts.devMode" value="true" />
<constant name="struts.ui.theme" value="simple" />
<package name="faultinjector" extends="struts-default">
<default-action-ref name="loadexperiments" />
<action name="loadexperiments" class="faultinjector.action.LoadExperimentsAction" method="execute">
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
LoadExperimentsAction.java:
public class LoadExperimentsAction extends ActionSupport
{
private static final long serialVersionUID = 4L;
private ExperimentService service;
private List <Experiment> experiments;
#Override
public String execute()
{
System.out.println("Hello!");
return SUCCESS;
}
public ExperimentService getService()
{
return service;
}
public void setService(ExperimentService service)
{
this.service = service;
}
public List<Experiment> getExperiments()
{
return experiments;
}
public void setExperiments(List<Experiment> experiments)
{
this.experiments = experiments;
}
}
I finally managed to achieve what I was looking for, without the need of redirecting pages. Basically the solution is to keep my original configuration, but changing the JSP page name from "index.jsp" to another one (in my case, it is now called "user_main".jsp). This way, it oddly works, I guess it has some hidden default configuration parameter when using the default name "index.jsp". Content of my configuration files:
web.xml:
<web-app id="faultinjector" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
struts.xml:
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.ui.theme" value="simple" />
<package name="faultinjector" extends="struts-default">
<default-action-ref name="loadexperiments" />
<action name="loadexperiments" class="faultinjector.action.LoadExperimentsAction" method="execute">
<result name="success">/user_main.jsp</result>
</action>
</package>
</struts>

http status 404 in struts 2 result

im in learning struts 2.
i create a simple project that can add and list the PRODUCT that user add. list is my first page and show all product that added. it is my struts.xml file:
<struts>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="listProduct" />
<action name="listProduct" class="control.ProductHandler" method="list">
<result name="success">/list.jsp</result>
</action>
<action name="addProduct" class="control.ProductHandler" method="add">
<result name="success">/listProduct</result>
</action>
<action name="*Form">
<result>{1}.jsp</result>
</action>
</package>
</struts>
when i enter localhost:8080/product in then browser it show me list.jsp file. in this file i have a link that with it i can goto add.jsp file. href of this link is addForm.
in add.jsp file i have 3 text field and a submit button. when entered data added action class return "success" and i most goto localhost:8080/product (default page) but it show me :
HTTP Status 404 - /product/listProduct
this is my action file:
public String list(){
products=Database.get();
return "success";
}
public String add(){
if (add!=null){
Product product=new Product(name, producer, price);
Database.add(product);
}
return "success";
}
where is my mistake?
thanks.
In order to redirect to another action use redirectAction result type.
<action name="addProduct" class="control.ProductHandler" method="add">
<result name="success" type="redirectAction">listProduct</result>
</action>

Struts2: interceptor and parameters

i have done some pages with Struts 2.(J2EE project)
All was ok until i try to add an interceptor.
It seems that the Interceptor delete all properties of my Class Action and Parameters send by the jsp with url like: action?param=xxx
here is the interceptor:
public class SessionInterceptor extends AbstractInterceptor{
#Override
public String intercept(ActionInvocation invocation) throws Exception {
return invocation.invoke();
}
here is the struts.xml:
<action name="movefc_ShowFjt" class="struts2.ShowFjtAction" method="movefc">
<interceptor-ref name="sessionInterceptor"></interceptor-ref>
<result name="input" type="dispatcher">jsp/showFjt.jsp</result>
<result name="success" type="dispatcher">jsp/showFjt.jsp</result>
</action>
in the class action,
public class ShowFjtAction extends ActionSupport {
private String param;
private Personne p;
param property never receive value from the jsp (it is ok when interceptor is off). Worse, other properties in Class action seems to be erased.
Is that an normal effect of the return invocation.invoke(); of the interceptor ?
Is there anything i can do to fix that ?
y defining your own interceptor are you causing all of the default interceptors to be discarded?
Should you perhaps be defining an interceptor stack which includes your interceptor and the default stack?
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="sessionInterceptor" class="SessionInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="sessionInterceptor"/>
</interceptor-stack>
</interceptors>
<action name="movefc_ShowFjt"
class="struts2.ShowFjtAction">
<interceptor-ref name="myStack"/>
<result name="input" type="dispatcher">jsp/showFjt.jsp</result>
<result name="success" type="dispatcher">jsp/showFjt.jsp</result>
</action>
The entire concept is explained as follows
1] First when user does not writes any interceptors, then interceptors defined in struts-default.xml will be used. It is defined in struts-core.jar, it is accomplished by extending the "struts-default" extended in our package xml tag.
2] When user writes his own interceptor if you add one mode code block after sessionInterceptor ref name i.e interceptor-ref name="defaultStack" will solve your problem.
Befor trying this try to unzip the struts-core.jar and move forward with your implementation.

struts2 action not calling properly

On default I want my struts2 app to forward to an action:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />
<package name="myApp" namespace="/myApp" extends="struts-default">
<action name="Login_*" method="{1}" class="myApp.SessionManager">
<result name="input">/myApp/Login.jsp</result>
<result type="redirectAction">Menu</result>
</action>
</package>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Login_input.action</param>
<param name="namespace">/myApp</param>
</result>
</action>
</package>
</struts>
I'm looking for the application to call SessionManager.input(), but instead it calls SessionManager.execute().
You don't want typically a public input() method. The most basic and typical scenario for an Action is:
The Action is intended to "do something" (one thing), and this action needs some user input.
The Action does than something in the method execute()
If the Action did succesfully that something, it returs SUCCESS. This triggers a result informative JSP page.
If the Action didn't get the user input (because there wasn't any, or because it was insufficient or wrong) it returns INPUT. This triggers a "input form" JSP so that the user can fill the data and (re)try the action.
Now, this basic scenario can be coded in several ways, among them:
1) Two different mappings, one for the input form, other for the execution
<!-- default action class: execute does nothing, returns SUCCES -->
<action name="ActionXXXShowForm">
<result>/myApp/XXXForm.jsp</result>
</action>
<action name="ActionXXX" class="myApp.XXXAction">
<result name="input">/myApp/XXXForm.jsp</result>
<result>/myApp/XXXDone.jsp</result>
</action>
2) Just one mapping
<action name="ActionXXX" class="myApp.XXXAction">
<result name="input">/myApp/XXXForm.jsp</result>
<result>/myApp/XXXDone.jsp</result>
</action>
Both are very similar (specially if your are doing programmatic validation).
In both cases, we have only a "struts" method in the action (execute), which is good practice as our action only "does one thing".
But in the second case, we need to deal with the case in which no data is post, and dont emit an error message for that case.
Example: In case 1:
public class XXXAction extends ActionSupport {
...
public String execute() throws Exception {
if(! inputOk()) return INPUT;
// .. do your stuff
return SUCCESS;
}
private boolean inputOk() {
// ... check your inputs - sort of programatic validation
if( surname == null ) addActionError("no surname");
// .... more checks
return ! hasActionErrors());
}
}
In case 2 you modify it slightly:
public class XXXAction extends ActionSupport {
....
public String execute() throws Exception {
if( emptyInput() ) return INPUT; // no error messages in this case
if(! inputOk()) return INPUT;
// .. do your stuff
return SUCCESS;
}
private boolean inputOk() {
// same as before
}
private boolean emptyInput() {
// detect no input was sent. do not emit errors herer
}
}
When you call an actions from jsp, the default method is execute(). If you want to call another method, you can spec by the attribute method="".
<s:url action="SessionManager" method="input"/>
The attribute method is common on other tags.
If you are using a <s:a... tag, then you will not be able to call the intended method apart from the default execute() method. Instead of <s:a... tag, you need to define the action using an <s:url... tag with an id and call the same using normal html anchor tag ie.,
<a href=${<<id>>} but you may need to specify the method in your struts.xml or any other xml configuration file, which you have included in your struts.xml file with the method attribute in your <action... method="..." clause.

Resources