struts2 NoSuchMethodException when trying to access Action method from JSP - java

Struts2 newbie here. I've got a JSP file that has an anchor linking to an Action called "authenticate". When I click on the anchor, I get an error message: java.lang.NoSuchMethodException: mypackage.DisplayStuff.authenticate()
java.lang.Class.getMethod(Unknown Source)
Here is my struts.xml
<package name="default" extends="struts-default" namespace="/">
<action name="display" method="authenticate"
class="mypackage.DisplayStuff">
<result name="error">Boo.jsp</result>
<result name="success">Yay.jsp</result>
</action>
</package>
And here is my action file:
package mypackage;
public class DisplayStuff {
public String authenticate() {
return "success";
}
}
And finally, in my JSP, I have this anchor:
click here
The interesting part, is if I rename my method to the default "execute" I don't get this error. Shouldn't I be able to call any method in my DisplayStuff action?

There are a few possibilities.
That the error message references a different package my first guess is that you haven't deployed the latest version of your code: struts.DisplayStuff.authenticate isn't how it's configured.
Second guess is an issue with a Struts 2 plugin (like "convention") mucking with your configuration.
Without more details, however, it's difficult to think much more about it.

This should be
click here

Related

How do I do a Simple Redirect in Struts 2?

I have been searching web for hours, and I can't find answer to a simple question in Struts 2. Basically, I have the following action in Struts 1 which is a simple forward, and I want to reproduce the same in Struts 2:
<action path="/az/api/v22/my-tenants" forward="/components/c/apis/v22/my-tenants.jsp">
</action>
I could write an action class to do this, but I think Struts2 has to have some way of doing this without having to write an action class since it is is a simple redirection.
Create actionless result in the struts.xml
struts.xml:
<package name="v22" namespace="/az/api/v22" extends="struts-default">
<action name="my-tenants">
<result>/components/c/apis/v22/my-tenants.jsp</result>
</action>
</package>
This configuration defines a package with namespace /az/api/v22 and action name my-tenants. So if you use path /az/api/v22/my-tenants it will be mapped to the action config above, because default action mapper is using namespace and action name together to get the action config.
There's no class attribute in the action tag, and it uses class ActionSupport instead. This class is configured by default in struts-default package.
In the result it's enough to define the location of the JSP, because struts2 defaults are using a dispatcher that forwards to JSP, and it's using "success" result code by default in the result config which is returned by default by ActionSupport class.

SocketTimeOut Exception using Struts 2 and Apache commons-fileupload

I want to post a picture to my server(tomcat 7.0.40).
And the project is built on apache-struts2-2.2.1 and spring 3.6 and apache-commons-fileupload.
First, I do some html code.
<input type="file" name="xxx" id="ccc" />
OK,next. I make an action extends ActionSupport.
public XxxAction extends ActionSupport{
private java.io.File xxx;
public String execute() throws Exception{
......
}
//getter and setter below
}
And next,this action injected by spring config like:
<bean id="xxxAction" class="xxx.xxx.XxxAction" />
May be you have found I lost scope="prototype",but please ignore it, because the problem is not there.
Next, configured by struts2.xml like:
<package name="xxx" namespace="/xxx" extends="json-default">
<action name="upload" class="xxxAction">
<interceptor-ref name="fileUpload">
<param name="allowedTypes">image/bmp,image/gif,image/jpg</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result>
<param name="root">toFrontJson</param>
</result>
</action>
</package>
OK,now submit a pic file to server.We assume the file can be received by action. But when the pic is large enough to passing for a moment, and half of passing I closed the web browser. It will get SocketTimeOut Exception. I find the server.xml in tomcat config folder, the connection timeout is settled to 20000. And the most important when I got this exception. Other request to this action cannot access. It will get:
cannot find aciton or result ......
I think the SocketTimeOut Excepiton must cause some things happen. It let the action instance disappear. So I add scope="prototype" in spring.xml. It works. Although when I interrupt fileupload operation, I got some other exception,but Other request is OK.
But I hope know what happened before I add scope="prototype", why other request cannot find action, and why I got SocketTimeOut Exception.
In apache-commons-fileupload? Or Struts 2?
The default scope used by Spring is singleton. So your code is failed because of synchronization IO operation on the file.
When you changed it to prototype then each action has its own instance of the action bean, so they are use its own field and don't stuck on each other.

Struts2 Is there a way to add metadata to action definition in struts.xml file?

I use the Struts2 framework to create a webapp. I have an interceptor that should have different behaviour depending on which action is invoked. For example, a login interceptor that should always allow some actions to execute, but it should block other actions if the user is not yet logged in.
The way I solve this now is by manually checking the name (and/or namespace) of the action in the interceptor, and determine my behaviour based on that. The downside of this "hardcocded" logic is that it is hard to maintain if I edit my struts.xml file, and it is also not obvious what is going on for other developers.
I would like to know if these is some way to add 'metadata' INSIDE the struts.xml file (or other file?) to "mark" certain actions as being certain "type". For example, something like this:
Struts.xml
<action name="loginPage" types="login, user, viewpage" class="login.controller.LoginPage">
<result name="success">/login/jsp/Login.jsp</result>
</action>
And then in my interceptor class:
#Override
public String intercept(ActionInvocation invocation)
throws Exception
{
Set<String> actionTypes = invocation.getInvocationContext().getTypes();
if(actionTypes.contains("login")
{
doSomething();
}
else
{
doSomethingElse();
}
}
Is this possible, or is the hardcoded parsing of name(space) the only way?
Obviously you can't do that because the DTD won't allow you.
Another good example of the XY problem:
The XY problem is asking about your attempted solution rather than your actual problem.
That is, you are trying to solve problem X, and you think solution Y would work, but instead of asking about X when you run into trouble,
you ask about Y.
What you really need is to define a group of actions running free, and other groups running under login control.
For this, you can manually include the Interceptor in each single action (useful when using the Convention plugin, a waste of time otherwise), or configuring the actions logically in the struts.xml.
The <package> is your friend here: define two (or more) packages, one running with the default settings, the other running your custom Interceptor for each action of the package:
<package name="unsecure-package" namespace="/unsecure" extends="struts-default">
<action name="login" class="org.foo.bar.actions.LoginAction">
...
</action>
<action name="askHelp" class="org.foo.bar.actions.AskHelpAction">
...
</action>
</package>
<package name="secure-package" namespace="/secure" extends="struts-default">
<interceptors>
<interceptor name="authInterceptor"
class="org.foo.bar.interceptor.AuthInterceptor"/>
<interceptor-stack name="securedStack">
<interceptor-ref name="authInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="securedStack"/>
<action name="write" class="org.foo.bar.actions.WriteAction">
...
</action>
<action name="delete" class="org.foo.bar.actions.DeleteAction">
...
</action>
</package>
This way every time you or somebody else will add an Action in struts.xml, it will just need to drop it in the right package, and it will work automatically.
It's better to keep the Interceptor action-agnostic whenever possible ;)

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.

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