Redirecting URL using struts2 - struts2

How can i redirect www.mysite.com/12345 to www.mysite.com/action?id=12345 using struts2?

I use URL rewriting to get these kind of flexible mappings working (though you could probably do it in struts proper, possibly with your own interceptor or something). There's a great little project, urlrewritefilter that gets the job done. In your URL rewriting configuration you'd have a rule like:
<rule>
<from>^/(\d+)$</from>
<to>/action?id=$1</to>
</rule>
Have a look at the manual to see if it is what you are looking for.

<action name="12345">
<result type="redirect-action">
<param name="actionName">action</param>
<param name="id">12345</param>
</result>
</action>
UPDATE
Ok. Based on the comment below.
I have managed something like this in this way in the past. Create a package in struts with a catch all action.
<package name="numbers">
<action name="*" class="my.package.ActionClass" method="urlrewrite">
<result type="redirect-action">
<param name="actionName">${nextpage}</param>
<param name="id">${id}</param>
</result>
</action>
</package>
Then in the urlrewrite method of the action class:
public String urlrewrite(){
//parse the url and determine the ID and the next page
nextpage = "action";
id = "12345";
return SUCCESS;
}
So in calling the action you will have to do like this:
http://www.mysite.com/numbers/12345.action
If you do not want a new package then you can do this in the default package.

Related

How can i use multiple parameters in restful struts?

i'm trying the struts restful plugin .. but i didn't find any solution to pass more than one parameter to my controll class ..
I put the parameters into struts.xml and but every time i can't use more than one
<package name="rest" namespace="/rest" extends="rest-default">
<action name="doctor/*" class="hospital.services.rest.DoctorController">
<param name="id">{1}</param>
<param name="name">{2}</param>
</action>
</package>
i can't rich the second parameter .. any suggestion?

Attribute parameter from <action> element - equivalent in Struts 2

In Struts1 you can use the attribute parameter from element(struts-config.xml) and access it's value within the action class via the actionMapping.getParameter() method. For actions requiring multiple steps, the parameter is often used to indicate which step the mapping is associated
with.
Ex:
<action path="\something\Step1"
type="actions.SomethingAction"
parameter="step1"> ...
<action path="\something\Step2"
type="actions.SomethingAction"
parameter="step2"> ...
Which is the alternative solution for Struts2?
Parameters in the action configuration could be used instead
<package name="something" namespace="/something" extends="struts-default">
<action name="Step1" class="actions.SomethingAction">
<param name="step1" ...
</action>
<action name="Step2" class="actions.SomethingAction">
<param name="step2" ...
</action>
</package>

Variable at start of namespace (or equivalent)

I am trying to create URLs that look like http://localhost:8080/app/client/shared-namespaces-and-actions:
“/app” would be the context root.
“client” would actually be a variable, replaced by the actual client version/interface of the application, such as
“john” (i.e.:
http://localhost:8080/app/john/namespaces-and-actions).
“/shared-namespaces-and-actions” would be packages/actions
accessible under one or more clients (such as “/about/contact”, or
“/products/73/edit”).
Ideally, a URL could entirely omit the “client” component, and so that for actions where it makes sense some sort of combined view could be displayed. For example “/app/” would display links to the client versions, whereas the client’s “/app/client/” would have what that client wants on their homepage.
This variable “client” component is what I have a question about.
Thus far, I have been using a query string parameter to handle the client selection, rather than part of the URL path. However, this has some obvious issues for things like bookmarks, as I always have to pass the client parameter in the query string (not attractive), else bookmarks will fail.
Is there an easy way to make this change? It seems like what I want is a wildcard in the namespace, as I do with actions, but the documentation doesn't seem to support that as a possibility, nor did experimentation. I already use packages to set namespaces, interceptor stacks, and to group related actions in the struts.xml file, so it would not be trivial to change all actions to be under the "/" namespace package with an additional wildcard for the client.
An option I was looking at was to extend the class DefaultActionMapper, and override the method parseNameAndNamespace(String, ActionMapping, ConfigurationManager), removing the client component of the URI (if it exists), and then passing that modified URI to the parent implementation. However this has a number of issues, such as breaking all links, form targets, and redirects. I expect fixing the links/forms would be annoying to fix, but not impossible, but I'm not sure if the same would be true of redirects.
I am using 2.3.16.3.
struts.xml:
<struts>
<constant name="struts.enable.SlashesInActionNames" value="true" />
<constant name="struts.mapper.alwaysSelectFullNamespace" value="false" />
<constant name="struts.patternMatcher" value="namedVariable"/>
<constant name="struts.action.extension" value="" />
<package
name="poc-default"
extends="struts-default"
strict-method-invocation="true">
<default-interceptor-ref name="defaultStack" />
<default-action-ref name="http404" />
<action
name="http404"
class="poc.DefaultAction">
<result name="success">/WEB-INF/http404.jsp</result>
</action>
</package>
<package
name="root"
namespace="/"
extends="poc-default"
strict-method-invocation="true">
<action
name=""
class="poc.DefaultAction">
<result name="success">/WEB-INF/home.jsp</result>
</action>
<action
name="clients"
class="poc.DefaultAction">
<result name="success">/WEB-INF/client-select.jsp</result>
</action>
</package>
</struts>
Using the struts.xml above, "http://localhost:8080/poc/" goes to the home page, and "http://localhost:8080/poc/clients" goes to the client selection page.
I then replace the package "root" with the following (added named wildcard to namespace):
<package
name="root"
namespace="/{uriClientString}/"
extends="poc-default"
strict-method-invocation="true">
<action
name=""
class="poc.DefaultAction">
<result name="success">/WEB-INF/home.jsp</result>
</action>
<action
name="clients"
class="poc.DefaultAction">
<result name="success">/WEB-INF/client-select.jsp</result>
</action>
</package>
Now, neither action is mapped by the URLs "http://localhost:8080/poc/john/" and "http://localhost:8080/poc/john/clients".
Having given Dave Newton's comment some thought, I believe that he is correct that I was going about solving my problem (optional client selector prefix to URL) is probably not how I should be going about this.
URL rewriting seems like a better (and possible) choice, and instead putting the client into context via an attribute of the request. I have created a filter that appears before the Strut 2 filter in web.xml:
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws ServletException, IOException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final String requestServletPath = httpRequest.getServletPath();
// Obtain set of client strings here.
final List<String> clients = Arrays.asList("john");
String newServletPath = null;
for (String client : clients) {
final String toCheck = "/" + client;
if (requestServletPath.equals(toCheck) || requestServletPath.startsWith(toCheck + "/")) {
/*
* Put client into context here, {#link HttpSession#setAttribute(String, Object)} or
* {#link ServletRequest#setAttribute(String, Object)}.
*/
request.setAttribute("uriClientString", toCheck);
newServletPath = requestServletPath.substring(toCheck.length());
break;
}
}
if (newServletPath != null)
request.getRequestDispatcher(newServletPath).forward(request, response);
else
chain.doFilter(request, response);
}
It was also necessary Struts 2's filter mapping to support forwards:
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Unfortunately, it is necessary to rewrite the generated URLs to include the client prefix if it is being used, since otherwise Struts2 will just start from the actual namespace:
<s:a namespace="%{#request.uriClientString}" action="">Home page</s:a>
Finally, it is also necessary to rewrite the redirects to include the client prefix if it is being used, since, once again, Struts2 will just start from the actual namespace:
<action name="re">
<result type="redirectAction">
<param name="namespace">${#request.uriClientString}</param>
<param name="actionName">clients</param>
</result>
</action>
This is not as easy to implement as I was hoping at the outset, but it does seem like it will meet my needs once everything is updated.
I will accept this in a couple of days if nothing better is suggested.

Reuse of redirect-action in struts.xml?

I have multiple actions that after completion redirect back to a general page (showStuff). I'm looking for a way to NOT repeat the list of parameters for every redirect-action.
What I have is this:
<action name="doThis" class="com.domain.package.MyAction" method="doThis">
<result type="redirectAction">
<param name="actionName">showStuff</param>
<param name="parse">true</param>
<param name="selectedYear">${selectedYear}</param>
<param name="selectedMonth">${selectedMonth}</param>
<param name="selectedDay">${selectedDay}</param>
</result>
</action>
<action name="doThat" class="com.domain.package.MyAction" method="doThat">
<result type="redirectAction">
<param name="actionName">showStuff</param>
<param name="parse">true</param>
<param name="selectedYear">${selectedYear}</param>
<param name="selectedMonth">${selectedMonth}</param>
<param name="selectedDay">${selectedDay}</param>
</result>
</action>
I would like to keep the parameter list within the showStuff action definition, and then use is like so:
<action name="doThis" class="com.domain.package.MyAction" method="doThis">
<result type="redirectAction">
<param name="actionName">showStuff</param>
</result>
</action>
<action name="doThat" class="com.domain.package.MyAction" method="doThat">
<result type="redirectAction">
<param name="actionName">showStuff</param>
</result>
</action>
Is it possible?
There are a few options.
Honestly, I'd skip most of my workarounds, and put them into session.
Once they're in session, create an interceptor and interface (Dateable or something). In the interceptor check the session for the variables (see below) and if the action is a Dateable, set them on the action, and you're done.
Another option is to encapsulate these variables as a date and either use the built-in converter or use your own converter. Then you'd only need a single parameter. This option would work with the interceptor idea as well.
As it turns out, it is very much possible. This is how you do it:
Add a global result:
<global-results>
<result name="show-stats" type="redirectAction">
<param name="actionName">showStats</param>
<param name="parse">true</param>
<param name="selectedYear">${selectedYear}</param>
<param name="selectedMonth">${selectedMonth}</param>
<param name="selectedDay">${selectedDay}</param>
</result>
And then for the actions:
<action name="doThis" class="com.domain.package.MyAction" method="doThis"/>
<action name="doThat" class="com.domain.package.MyAction" method="doThat"/>
Finally in the java code, just:
return "show-stats";
And you're done.
As a sidenote, why do I have to spend so much time trying to adhere to the very basic DRY principle? Aren't all these frameworks supposed to .. you know.. simplify stuff? Just wondering...
I was facing the same problem with an endless list of params getting longer and longer, repeated in several places. What I ended up doing was that I created an external file and declared it in struts.xml as an entity then included it instead of repeating all the params
This goes in the doctype tag
<!ENTITY referenceName SYSTEM "fileName">
Then you include it like so
&referenceName;

In Struts2 HOWTO handle a url with same namespace but with or without the trailing slash similarly

In struts2 I am writing an app where I need to make sure that the url redirection works the same whether or not there is a trailing slash at the end.
E.g. example.com/app should behave same way as if user entered example.com/app/. Currently I changed mapping in struts.xml like so -
<struts>
<package name="default" namespace="/" extends="secure">
<interceptors> ... <interceptors>
<action name="app">
<result type="redirectAction">/app/</result>
</action>
</package>
</struts>
and
<struts>
<package name="app" namespace="/app" extends="secure">
<interceptors> ... <interceptors>
<action name="" class="com.example.action.app.LoginAction" method="display">
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<interceptor-ref name="basic" />
<result type="redirectAction">home</result>
<result name="display">/jsp/base/content/login/loginForm.jsp</result>
</action>
</package>
</struts>
But this seems hackish since if I go to example.com/app it will show example.com//app/.html in the URL.
Any help appreciated.
Answer was derived in comments under the answer.
Quaternion:
Personally I would write all my urls with out the trailing slash...
and then I would use something external to the application to rewrite
urls as appropriate, perhaps iptables could determine if there is a
trailing slash and if so always strip it.
Mohana Rao SV:
As suggested above follow without tailing slash. And override
StrutsPrepareAndExecuteFilter one of the filter job is from the url it
has to identify the namespace and action name and invoke respective
action. So here remove tailing slash from url.
Quaternion:
In namespace "/" you have an action called app. That is all there is
to it to invoke CONTEXT_ROOT/app (that is what struts2 expects), you
don't ever expect to see a "/" on the end of the url, so you want to
find a method that parses the url before struts2 resolves the mapping.
What you have described only requires something to remove a trailing
"/" if it exists. I'd look to iptables because I've used it before or
some other url rewriter... Mahana would keep it all part of the web
app and use a filter, methods differ but the effect is the same.

Resources