struts 2 package names - struts2

In struts 2, if we have action declaration as :
<package name="pdfReports" namespace="/reportPdfs" extends="struts-default">
<action name="*" .......
What should be the action url corresponding to this?
This url:
/reportPdfsreports/12-008975/someActionName.action
is giving error:
There is no Action mapped for action name someActionName

The URL would be /reportPdfs/someActionName.action

Related

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>

How does the namespace attribute in a Struts2 package work?

I am still confused how to properly use the namespace attribute in Struts2.
In the namespace configuration, it was mentioned that:
Namespaces are not a path!
Namespace are not hierarchical like a file system path. There is one namespace level. For example if the URL /barspace/myspace/bar.action is requested, the framework will first look for namespace /barspace/myspace. If the action does not exist at /barspace/myspace, the search will immediately fall back to the default namespace "". The framework will not parse the namespace into a series of "folders". In the Namespace Example, the bar action in the default namespace would be selected.
I have tried making a simple Struts2 sample:
<?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="default" extends="struts-default">
<action name="defaultIndex">
<result name="success">/pages/default.jsp</result>
</action>
</package>
<package name="package1" namespace="/" extends="struts-default">
<action name="index1">
<result name="success">/pages/home1.jsp</result>
</action>
</package>
<package name="package2" namespace="/namespace1" extends="struts-default">
<action name="index2">
<result name="success">/pages/home2.jsp</result>
</action>
</package>
<package name="package3" namespace="/namespace1/namespace2" extends="struts-default">
<action name="index3">
<result name="success">/pages/home3.jsp</result>
</action>
</package>
</struts>
Where SampleDynamicWebProject is the context root.
Based on the documentation, if I try
.../SampleDynamicWebProject/randomText/defaultIndex
Then, Struts2 will look for the /randomText namespace and check for the defaultIndex action. If it doesn't exist, then it will look for the default namespace which is the package with no namespace attribute.
But if I try this URL:
.../SampleDynamicWebProject/namespace1/randomText/index2
Struts2 should look at the /namespace1/randomText namespace for the index2 action and if it cannot see one, then it should look at the default namespace. However, the URL above is still directed at the index2 action in the /namespace1.
The same thing is happening when I try
.../SampleDynamicWebProject/randomText/index1
The index1 in the root namespace is invoked.
Can you please clarify how exactly it works?
You're definitely right, nowhere in the documentation is mentioned that if a namespace is part of the URL, it is enough to make the whole thing work.
But it does, and here is how it works in detail:
To parse an URL and call the appropriate namespace and action, Struts2 uses an ActionMapper:
The ActionMapper interface provides a mapping between HTTP requests and action invocation requests and vice-versa.
There are different implementations, but the default one is the DefaultActionMapper.
When an URL is analyzed, the parseNameAndNamespace() method is invoked. If it's not the default "" nor the root "/" one, and the alwaysSelectFullNamespace attribute is set to false (that is the default), then the available namespaces are scanned:
The magic is in this line:
if (ns != null
&& prefix.startsWith(ns)
&& (prefix.length() ==ns.length() || prefix.charAt(ns.length()) == '/')) {
if (ns.length() > namespace.length()) {
namespace = ns;
}
///...
}
name = uri.substring(namespace.length() + 1);
In your example:
/namespace1/randomText/index2
prefix = /namespace1/randomText/
ns = /namespace1
In your case it is not null, the URI starts with the namespace, the length is not the same BUT the character after the /namespace1 String in the URI is a slash, then the action mapper decides that:
namespace = /namespace1
action = randomText/index2
This is why the namespace is taken. But then why it works, since the action name is index2 and not randomText/index2 ?
The second magic is in this other line:
if (!allowSlashesInActionNames) {
int pos = name.lastIndexOf('/');
if (pos > -1 && pos < name.length() - 1) {
name = name.substring(pos + 1);
}
}
If the allowSlashesInActionNames attribute is set to false (that is the default) and the action contains slashes (like in randomText/index2), then strips everything up to the last slash, transforming randomText/index2 in index2.
Then as long as you have an URI that is starting with a namespace and ending with an action, no matter what's in the middle, it works.
It should not work instead using /randomText/namespace1/index2, because no namespace is starting with /randomText.

How to prevent the wildcard namespace in struts?

I am facing a problem that I couldn't find a key word for googleing the following situation:
<package name="Main" namespace="/" extends="struts-default">
<action name="administrator" class="com.xyz.AdminAction">
<result name="success">/WEB-INF/jsp/admin.jsp</result>
</action>
</package>
The above url should be http://xyz.com/administrator and it works fine. However, if I change the url to http://xyz.com/asdasd/asdasdasd/administrator and it still works, but I can't accept this! So any setting to tell struts only http://xyz.com/administrator is accepted? Thanks!
Set the alwaysSelectFullNamespace property to true.
From struts-default.properties:
### Whether to always select the namespace to be everything before the last slash or not
struts.mapper.alwaysSelectFullNamespace=true
XML configuration is preferred, so in your struts.xml:
<struts>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="true" />
...

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>

url links in struts2 tiles gets namespace added on second time after click. How do I stop this?

I am using struts 2, tiles, and namespaces and am having a problem that after I click a link the menu appends the namespace a second time. I am using the struts tag url with an action and a namespace. When the page is first displayed, the links in the menu are correct land have the namespace before the action. After I click on one of the links, the page redisplays and although the source looks okay, when I hover over it firefox shows the url with the namespace in there twice. I.E.
localhost/ar/customermaint becomes localhost/ar/ar/customermaint. If I have clicked on a link that has a different namespace such as "ss" first then it becomes localhost/ss/ar/customermaint.
any idea what I'm doing wrong? Or is it a problem with tiles and namespaces.
I had faced this issue before. Each time when the action is called, the namespace gets appended in the URL and it looked ugly
Example: http://localhost:8080/RmAirlines/user/user/user/user/user/login for calling the action login from a namespace user each time
Setting the namespace to "/" isn't an ideal solution either.
Solution: Suppose the namespace of the package is "/user" and there's an action named "login" inside it (in your struts.xml). Then where ever you call the action, refer it as action="/user/login" (or action="/user/login.action") - i.e. putting a "/" before the namespace will save your day!
Example:
struts.xml
<package name="userManagement" namespace="/user" extends="struts-default">
<action name="login" class="com.rm.airlines.action.Login">
<result name="success">/user.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
login.jsp
<s:form action="/user/login">
<s:textfield label="Email" key="email" />
<s:password label="Password" key="password" />
<s:submit />
</s:form>
To avoid this, always follow a simple principle.
For all namespace declaration, use a slash "/" followed by the namespace name.
In this way, it will not append the earlier namespace in new url.
What struts assume, if you don't specify "/" in new namespace, it tries to find it in currently used namespace. If you specify "/" before namespace name, it takes it as a root namespace.
Example:-
<package name="default" namespace="/nsp" extends="struts-default">
<action name="validate" class="login.LoginAction">
<result name="success">/home.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
<package name="cricket" namespace="/cricket" extends="struts-default">
<action name="findcaptain" class="cricket.CaptainAction">
<result>/showCaptain.jsp</result>
</action>
</package>
Look in each of my package declaration, I am using namespace name prefixed by a slash. i.e. /nsp and /cricket). And that's how we could avoid this namespace appending issue.

Resources