How to redirect struts action with dynamic parameter - redirect

I want to redirect action with parameter "id".
I used this code in struts.xml
<action name="register" class="com.framework.strust2.UserAffair">
<result name="success" type="redirectAction">
<param name="actionName">viewProfile</param>
<param name="id">${id}</param>
</result>
</action>
It works for action redirecting and parameter name id, but not parameter value ${id}. It only works with constant id, like;
<param name="id">1</param>
Though I searched the solution of my problem, there is nothing case that matches what I needed. Pls.

For passing the parameter with action you should have to define that variable in action and if you are using model driven approach then that parameter should be in pojo i.e
it is your struts.xml action configuration.
<action name="register" class="com.framework.strust2.UserAffair">
<result name="success" type="redirectAction">
<param name="actionName">viewProfile</param>
<param name="id">${id}</param>
</result>
</action>
so in you action class there should be variable sayaing id.
i.e
class UserAffair{
private int id;
//setter and getter
}
and if you are using model drivan then in your pojo there should be a variable saying id.
hope so this will help you a lot

Related

Struts 2 interceptor redirect JSP page

Using Struts 2, I have this interceptor:
public class AccessInterceptor extends AbstractInterceptor {
#Override
public String intercept(ActionInvocation ai) throws Exception {
ActionContext actionContext = ai.getInvocationContext();
Map<String, Object> session = actionContext.getSession();
Boolean logged = (Boolean) session.get("logged");
if(logged == null) {
session.put("logged", false);
logged = false;
}
if (!logged) {
// If exception is here, it IS thrown, so I am sure "login" is returned on /homepage
return "login";
}
return ai.invoke();
}
}
And this 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" />
<package name="loginInterceptor" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="access"
class="logininterceptor.interceptors.AccessInterceptor"/>
<interceptor-stack name="appDefault">
<interceptor-ref name="access" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="appDefault" />
<global-results>
<result name="login">/WEB-INF/content/login.jsp</result>
</global-results>
</package>
</struts>
I have also /WEB-INF/content/homepage.jsp JSP and /WEB-INF/content/login.jsp and mypackage.LoginAction.java class. There is not an acton class for homepage
The problem is, that when I go to the /homepage page, it is NOT redirected to login.jsp and I see the homepage.jsp content. What is wrong?
PS: I use struts2-convention-plugin
This is happening because the conventions plugin uses the "convention-default" package which does not know about your interceptor or interceptor stack.
If you could create a package which extends conventions-default doing just what your interceptor stack does (defines the interceptor, interceptor stack and defines the default result type) and then make the conventions plugin apply that stack as the default for all actions wouldn't that be great? You can.
After the <struts> tag define a constant like so:
<constant name="struts.convention.default.parent.package" value="loginInterceptor"/>
The other suggestion, was to use struts.xml to override the conventions, which is fine but a little verbose.
Another option is to use the parent package annotation, which is good when you need to override the default behavior but as you pointed out you want this to be the default behavior so you should reserve annotations for overriding this, not to implement it.
It may be worth browsing the following list of struts2 conventions plugin constants for the future: http://struts.apache.org/2.1.8/docs/convention-plugin.html#ConventionPlugin-Overwritingpluginclasses
PS: Just naming preference but I would call your package login-package rather than loginInterceptor... not a big deal.
If you want to force to execute the interceptor every time anyone is accessing to homepage.jsp, the correct way of doing this is to put an action that returns the jsp. For example:
<struts>
...
<package name="loginInterceptor" namespace="/" extends="struts-default">
<interceptors>
...
</interceptors>
<default-interceptor-ref name="appDefault" />
<global-results>
...
</global-results>
<action name="homepage">
<result>/WEB-INF/content/homepage.jsp</result>
</action>
</package>
</struts>
After that, when a user tries to access to http://.../homepage.action, the interceptor will be executed and will be redirected to the login page if the user is not logged in.

Struts 2 - Persist property value for redirect action

I want to retain a property value after redirecting to a different action. I know that the value will go away since we are navigating to different action (request). But I need to some how that how can I achieve this ?
Here is my code :
<action name="save" class="saveAction" method="saveData">
<result name="success" type="redirectAction">redirectedPageAction</result>
<result name="successView" >successView.jsp</result>
<result name="error" >error.jsp</result>
</action>
<action name="redirectedPageAction" class="month" method="">
<result name="success">employeesList.jsp</result>
</action>
In save action class I am using addActionMessage(String msg) method to set a value. Also I have getter/setter for the same.
I tried this but didn't get success :
<action name="redirectedPageAction" class="month" method="">
<result name="success">employeesList.jsp>
<param name="msg">${msg}</param>
</result>
</action>
I want value which was set by adActionMessage(msg) in my employeelist.jsp page. I am getting null pointer struts exception.
Please help..
Actions are created per-request. If you don't actually pass anything from the first action to the second, there won't be anything for the second action to retrieve. Getters don't change HTTP mechanics.
If you're interested specifically in messages/etc., use the MessageStoreInterceptor, or do it manually.
Since you already mentioned that and you know that it will create a new request cycle and Actions and created per request since they work as Data object also ,which means your request/response parameters will be lost.
Now you have few option
Try using the Struts2 build in support for this message-store-interceptor.
This interceptor has been created to store a ValidationAware action's messages / errors and field errors into HTTP Session and is very useful in your use-case.
If you want wider scope either you can store data in the session and retrieve that at later stage or can pass values as query parameters.
I've faced this problem before, sometimes you need to show a whole new view after an action and the redirect result does not take into consideration any previous data (http request stuff).
We wanted to create a custom interceptor, but before doing it I found this
http://www.mail-archive.com/user#struts.apache.org/msg77854.html
It really helped us a lot.
Having said that, what version of Struts 2 are you using? We use Struts 2.2.3 and the parameters passed to the redirectAtion works fine.
Do you have setter and getters in both actions?
You can pass your property variable with redirectAction as a parameter like this
<action name="save" class="saveAction" method="saveData">
<result name="success" type="redirectAction">
<param name="actionName">redirectedPageAction</param>
<param name="msg">${msg}</param>
</result>
<result name="successView" >successView.jsp</result>
<result name="error" >error.jsp</result>
</action>
Also, dont miss to add getter/setter for msg variable in your redirectedPageAction action

Populate fields after redirect in struts 2

I'm trying to understand if there is an easiest and shorter way to populate the fields of a form, after it fails validation and it's redirected (following the pattern described here).
I have a form that is called from addPerson.action action, and submit action is savePerson.action.
If it fails validation, I redirect passing all parameters, so that the redirected page will populate the fields with the data inserted by the user, avoiding the user the hassle to start from scratch.
The problem of this solution is that I have to list every single parameter of the form in the struts.xml, like in the example below:
<action name="savePerson" class="personAction" method="savePerson">
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
<interceptor-ref name="myStack" />
<result name="success" type="redirectAction">
<param name="actionName">listPeople</param>
</result>
<result name="input" type="redirectAction">
<param name="actionName">addPerson</param>
<param name="parse">true</param>
<param name="person.name">${person.name}</param>
<param name="person.surname">${person.surname}</param>
<param name="person.gender">${person.gender}</param>
<param name="person.email">${person.email}</param>
<param name="person.mobile">${person.mobile}</param>
</result>
</action>
<action name="addPerson" class="personAction" method="addPerson">
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<interceptor-ref name="myStack" />
<result name="success">/person/add.jsp</result>
<result name="input">/person/add.jsp</result>
</action>
I had to use the MessageStoreInterceptor in order to save and retrieve the validation error messages from a redirect.
I'm already using the ajax validation, but I wish to make my pages work in non javascript mode as well. With the code above everything works as expected, but looks weird that I have to list all my parameters inside the result tag.
Is there a better and shorter way of doing it?
thanks
With a redirect you start over, you throw out the value stack except for the parameters you explicitly pass in. What you probably want is chain, which snowballs the value stack.
See here for a list of result types, the link to Chain has some examples: http://struts.apache.org/2.2.1.1/docs/result-types.html
You can then just use the basic result tag and probably will not need a body.
See nmc's comment. This is what I do too, it isn't a good idea to use chain or redirectAction... creates spaghetti actions.

uuid custom typehandler mybatis

I want to manage a table with a VARCHAR primary key, that in the
mapped java object should be a UUID.
i have my sql-map-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="database.properties"/>
<typeHandlers>
<typeHandler
handler="[...].persistence.typehandlers.UuidTypeHandler"
javaType="java.util.UUID"
jdbcType="VARCHAR"/>
</typeHandlers>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="user.xml" />
</mappers>
</configuration>
and the user.xml is like that:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="[...].persistence.mappers.UserMapper">
<select id="selectUserByUUID" parameterType="java.util.UUID"
resultMap="userResultMap">
SELECT * FROM user WHERE uuid = #{uuid, jdbcType=VARCHAR,
typeHandler=[...].persistence.typehandlers.UuidTypeHandler}
</select>
<resultMap id="userResultMap" type="[...].model.User">
<id property="uuid" column="uuid" jdbcType="OTHER"
typeHandler="[...].persistence.typehandlers.UuidTypeHandler"/>
...
</resultMap>
</mapper>
anyway, i got this exception:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause:
org.apache.ibatis.reflection.ReflectionException: There is no getter
for property named 'uuid' in 'class java.util.UUID'
### The error may involve
[...].persistence.mappers.UserMapper.selectUserByUUID-Inline
### The error occurred while setting parameters
### Cause: org.apache.ibatis.reflection.ReflectionException: There is
no getter for property named 'uuid' in 'class java.util.UUID'
it seems that my typehandler never gets called (i have it logging a
bit, but never prints anything).
Is there something wrong? Thanks.
Your problem is right there in your exception....
There is no getter for property named 'uuid' in 'class java.util.UUID'
Use a parameter type of String, and pass in unique id as an argument. You don't need a type handler.
Seems kinda odd answering my own question, but i got some help on the mybatis-users list, so i'd like to share some hints here:
Mybatis was trying to "get" a non-existing field:
Luckily, one of mybatis developers helped me a while ago, suggesting that the easiest way to get it to work was to add a #Param annotation in the UserMapper to do this thing:
public User selectUserByUUID(#Param("uuid") UUID uuid);
<select id="selectUserByUUID" parameterType="uuid" resultMap="userResultMap">
SELECT * FROM user WHERE uuid = #{uuid, typeHandler=com.collective.persistence.typehandlers.UuidTypeHandler, javaType=uuid, jdbcType=VARCHAR}
</select>
I was stuck in watching the typehandler configuration, but,
if I understood it right, this has not much to do with typehandlers,
since they are used to "transport and translate" data between the sql
table and the java objects (through setter and getters), while my
issue was in the handling of methods' parameters. Hope this helps someone.
Also such error could be fixed by adding in mapper file new method with corresponding queue
Smth like this:
#Select("SELECT * FROM Users u WHERE u.userUUID = '${uuid}'")
User selectByUserUuid(#Param("uuid") UUID uuid);

Redirect to default action in Struts 2

I have an action with an empty string for name defined in the root namespace, and I want to redirect to that action from another action if a certain result is found, but it doesn't seem to work.
Here's the default action
<action name="" class="com.example.actions.HomeAction">
<result name="success" type="freemarker">freemarker/home.ftl</result>
</action>
And I'm defining the redirect in the global-results for the package:
<global-results>
<result name="sendToRouting" type="redirectAction">
<param name="actionName"></param>
<param name="namespace">/</param>
</result>
</global-results>
I've tried taking out the actionName parameter, but that doesn't work. If I put a name in for the HomeAction and reference it by name in the global-results it works, so I'm assuming the problem is lack of action name for the redirect.
Any thoughts?
I think that what you want to do is use <default-action-ref />:
<package name="home" namespace="/" extends="struts-default">
<default-action-ref name="home" />
<action name="home" class="com.example.actions.HomeAction">
<result name="success" type="freemarker">freemarker/home.ftl</result>
</action>
</package>
Sorry...misread the question:
Try changing type="redirectAction" to type="redirect", I'm fairly sure that redirectAction is now redirect.
Were you getting a NullPointerException because the actionName parameter is blank? I hacked around this by providing a string which evaluates to an empty string:
<param name="actionName">${}</param>
Still looking for a more "correct" solution though...