Struts2 URL unreachable - java

I'm really racking my head here with Struts2 - I'm able to access the JSP pages by omitting part of the path. Note the path suppose to include pages/welcome_user.jsp. The key is to look at the word pages in the path.
here's the struts.xml file:
<?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>
<package name="default" namespace="/User" extends="struts-default">
<action name="Login">
<result>pages/login.jsp</result>
</action>
<action name="Welcome" class="com.mkyong.user.action.WelcomeUserAction">
<result name="SUCCESS">pages/welcome_user.jsp</result>
</action>
</package>
</struts>
I'm able to access login.jsp via: http://localhost/Struts2Example/User/Login
and welcome_user.jsp via: http://localhost/Struts2Example/User/Welcome
Note that in both URL, I'm able to drop pages, why?
source:
http://www.mkyong.com/misc/how-to-use-mkyong-tutorial/
Can someone go through the above tutorial and tell me what's wrong?

First, you have used URLs that are mapped to the actions in the struts.xml.
The action method is executed and returns a result code SUCCESS. This result you can find in the action config. Then result is executed, if the type of result isn't set the default is dispatcher, and request is forwarded to the location specified in the result config.
If location is relative the final absolute location will be determined by the namespace of the package used for this action.
More detailed example of usage namespaces and explanation you can find in the example Struts 2 Namespace configuration example and explanation.
You can't drop pages if you are using dispatcher result that forwards to JSP. In this case the URL has been rewritten and you can't see the final URL.

Related

Is prefix needed for Struts2 namespace in forms and links?

From the Apache documentation:
While the prefix appears in the browser URI, the tags are "namespace
aware", so the namespace prefix does not need to be embedded in forms
and links.
struts.xml:
<package name="testpkg" namespace="/test" extends="struts-default">
<action name="doTest" class="otes.test.TestAction">
<result>/success.jsp</result>
</action>
</package>
index.jsp: (http://localhost:8080/nsdemo/)
<h2>Using HTML tags:</h2>
<h3>doTest without namespace</h3> <!-- 404 error -->
<h3>doTest with namespace</h3> <!-- works -->
<h2>Using Struts2 tags:</h2>
<h3><s:a href="doTest">doTest without namespace (s:a href)</s:a></h3> <!-- 404 error -->
<h3><s:a href="test/doTest">doTest with namespace (s:a href)</s:a></h3> <!-- works -->
<!-- 404 error -->
<s:url action="doTest" var="myAction" />
<h3><s:a href="%{myAction}">doTest without namespace (s:url action)</s:a></h3>
<!-- works -->
<s:url action="test/doTest" var="myAction" />
<h3><s:a href="%{myAction}">doTest with namespace (s:url action)</s:a></h3>
Does this mean I really have to specify the namespace in my forms and links?
(I am using Struts 2.3.20 if that matters.)
First of all: the tags referred in the docs are Struts2 tags (e.g. <s:url>, <s:a>).
And namespace aware means that if you already executed some action in particular namespace then in the JSP you don't need to prefix S2 links and forms with the current namespace.
E.g. if you have this package configuration:
<package name="testpkg" namespace="/test" extends="struts-default">
<action name="index">/index.jsp</action>
<action name="doTest" class="otes.test.TestAction">
<result>/success.jsp</result>
</action>
</package>
and executed the index action (http://localhost/app/test/index.action). Then in index.jsp you can write
<s:a action="doTest">test</s:a>
and that url will take you to the same namespace.
If you want to change namespace there is namespace attribute in some tags that you can use.
E.g. you are in some page (http://localhost/app/index.action) - note no namespace in url, then following link will execute doTest in /test namespace.
<s:a action="doTest" namespace="/test">test</s:a>
BTW don't add action extension to actions in S2 tags.
This is wrong:
<s:form action="doTest.action">
This is correct:
<s:form action="doTest">
The rule is simple: if you defined a package with the namespace attribute then its actions belong to this namespace. And when you use url or a, or form tags you should specify a namespace attribute along with action name which is in action attribute. If you specify both parameters Struts can easy map your URL to the action from the package with namespace. Don't use action extension in these attributes. Struts is using UrlHelper class to build the url and if it can't find the action mapping it will return the string as is. Also if you are using href attribute then Url helper is not involved, so the string remains as is.
This code should work:
<s:url namespace="/test" action="doTest" var="myAction" />
<h2><s:a href="%{#myAction}">doTest with href (s:url action)</s:a></h2>
<h2><s:a namespace="/test" action="doTest">doTest with namespace and action (s:url action)</s:a></h2>

How to re-map Action implementation class in struts.xml?

How do I inject the implementation class of a action in struts.xml from struts2.xml?
Suppose struts.xml looks like the following:
<struts>
<action name="EnginesList" class="example.EnginesListAction">
<result name="*">viewengines.jsp</result>
</action>
</struts>
Then I wanted to achieve: when struts2.xml exists(or is not blank), then the class-mappings in struts2.xml overrides those in struts.xml. So if I have the following definition, at runtime EnginesList is mapped to example.EnginesListAction2 instead of example.EnginesListAction.
// struts.xml:
<struts>
<action name="EnginesList" class="example.EnginesListAction">
<result name="*">viewengines.jsp</result>
</action>
<include file="struts2.xml" />
</struts>
// struts2.xml
<struts>
<action name="EnginesList" class="example.EnginesListAction2">
<result name="*">viewengines.jsp</result>
</action>
</struts>
This seems not working due to name conflict. So what's the best way of achieving my end goal?
Background added:
Team-A develops and maintains struts.xml. My team(team-B) uses the codebase of team-A and deploys it in a separate data center.
Team-B needs to have some actions be mapped to different classes. However we cannot directly modify it in struts.xml since it will change the behavior of Team-A's service.
So what I wanted is to have a separate file(struts2.xml) whose class-mappings can override those in struts.xml. No changes in action package name. No changes in JSP code. This struts2.xml will be deployed ONLY in team-B's data center.
The easy way you could do this, is by using multiple ( separate ) struts configuration files and importing them into your main struts.xml file.
In your case rename struts.xml to struts1.xml. Include these two file in your main struts.xml
<include file="struts1.xml"></include>
<include file="struts2.xml"></include>
I am not sure about the order of imports of these file, so cannot comment on whether mappings in 2nd file will shadow the mappings in 1st or vice versa. Try that for yourself to decide which file must be included first.
For more information regarding including configuration refer this.
Refer this link for a full example.

Strut2 having multiple packages cause problems

This is my package structure in Struts.xml file
<package name="default" namespace="/" extends="struts-default">
<!-- Default action name <default-action-ref name="Index" /> -->
<action name="Index" method="index"
class="com.convergent.struts2.actions.UserAction">
<result name="success" type="dispatcher">/WEB-INF/html/index.jsp</result>
</action>
</package>
<include file="struts-admin.xml"></include>
My Index.jsp is access through this url
http://localhost:8888/Index
In Index page there is hyper link that redirect that user to Setting Page. Setting action is in the 'Admin' namespace so it is access as:
Setting
In setting page there is a hyper link to redirect the user to index.jsp page. action is called like this:
go back
As you can seen 'Index' action is in the default package having namespace '/'. So to handle this action namespace is changed and user is redirected to the index.jsp page. My problem is that although user is redirected to index.jsp page but the web url looks like
http://localhost:8888/Admin/Index
I want this url to
http://localhost:8888/Index
I don't know how to solve this problem. can anyone suggest me ?
"As you can see 'Index' action is in the default name space." - no it is in the default package and the namespace "/".
Advice: 1) Don't create namespaces without leading a leading '/', it generally isn't want you want. For basic use of namespaces see http://struts.apache.org/release/2.1.x/docs/namespace-configuration.html although that page does not cover the creation of namespaces without a leading slash, and the interesting behaviour you've experienced.
2) Use the namespace attribute of the struts2 url tag. When using Struts the tag reference is your friend: http://struts.apache.org/release/2.3.x/docs/tag-reference.html
As Roman mentioned, using the anchor tag will be a touch more straight forward.
Using just the url tag you would have:
go back
When this is a bit clearer:
<s:a namespace="/" action="Back">go back</s:a>
To solve this problem what i do rather than redirecting the user to index.jsp I first redirect the user to another action like this
go back
To handle this action mapping in struts-admin.xml is:
<action name="Back">
<result name="success" type="redirectAction">
<param name="namespace">/</param>
<param name="actionName">Index</param>
</result>
</action>
This way I solve the problem.

Populating a Struts 2 select menu and redirecting action

I have a JSP file with form. That form contains a select drop-down menu
<s:select label="Make a selection" headerKey="-1" headerValue="Select Option" list="stuff" name="books" />
Now, to populate the select menu I created a java file to do that. I also created a SelectAction that will populate the menu and made the form's action pointed to the SelectAction
In my .xml file I adjusted it so it contains action for populating Select then redirect to the action that will deal with the form
XML file
<?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>
<package name="example" namespace="/example" extends="struts-default">
<action name="SelectAction" class="example.SelectAction">
<result type="redirectAction">
<param name="ActionName">AddSubmitAction</param>
<param name="namespace">/example</param>
</result>
</action>
<action name="AddSubmitAction" class="example.AddSubmittAction">
<result type="chain">
<result>/example/addOrder.jsp</result>
</result>
</action>
</package>
</struts>
What I am trying to do in the xml is first have the SelectAction (so select menu populates) then redirect it to AddSubmitAction which will take care of the form input.
HOWEVER, this is not working. I get a dispatcher not found error. Is my approach incorrect? Is the redirectAction being misused here?
Parameter for action name is case sensitive
<param name="actionName">AddSubmitAction</param>
Best Way to Populate Your select Tag value is to make prepare method. prepare method is always call first when your action class is called.
So in your one Action class make prepare method:
public void prepare(){
//set your list here
}
You can also define prepare method for each method define in your action class:
if your method is
public String execute(){
}
then your prepare method should be
public void prepareExecute(){
And implement Preparable interface in your action class.
For further reading:prepare interceptor

Struts2 - have two packages in struts.xml point to dynamic web root

First off, please forgive me for my lack of understanding... I'm still learning :)
I have 2 packages in my struts.xml that extend a base package and I want to be able to access them by typing in my browser something similar to http://site.com/application/1/ThisAction.action and /application/2/ThisAction.action (examples).
I created two directories in my webapp folder, named '1' and '2' and I am able to navigate to both packages using the urls above. What I want to do is actually put my jsps within the jsp directory, instead of webapps. so instead of my two folders residing inside /webapp, they should reside in /webapp/jsp/.
I tried changing the namespace of the two packages to something like /1/jsp/ instead of simply '/1', but i get nothing. It just keeps telling me there is no action mapped to that action name.
Does anyone have any insight on how I can accomplish this? Google's not giving me a lot of help, but it may just be that I'm not searching for the right thing.
Here's a quick sample of what I'm referring to:
<struts>
<!-- Base-->
<package name="base" extends="struts-default" abstract = "true" namespace="/base">
<global-results>
<result name="cancel" type="redirectAction">CancelAction</result>
<result name="close">closewindow.jsp</result>
<result name="error">/jsp/wizard/GeneralError.jsp</result>
</global-results>
</package>
<package name="1" extends="base" namespace="/1">
In Struts 2 you do not need to put your JSP's in various folders according to the URL that you use to access them. Rather the package and the action comes together to create the URL and the result will determine the next view. So you start by writing your action:
public class MyActionClass ...{
...
public String actionMethod() {
//Your action code here
return SUCCESS;
}
}
Next you will create an entry in struts.xml that points to this action.
<package name="default" extends="struts-default">
<!--Interceptors, Global Results etc.-->
<action name="myaction" class="my.package.MyActionClass" method="actionMethod">
<result>/WEB-INF/path/to/yourpage.jsp</result>
</action>
...
</package>
Now, to access this action in the default package you simply use the URL: http://yourserver/myaction.action.
If you create a second package with a different name like this:
<package name="2" extends="default" namespace="/2" >
<action name="myaction" class="my.package.MyActionClass" method="actionMethod">
<result>/WEB-INF/path/to/yourpage.jsp</result>
</action>
...
</package>
Then you can access that action with the URL: http://yourserver/2/myaction.action.
So you can go ahead and put your JSP in the directory called jsp if you wish and you only have to modify the result to point to the correct place.

Categories