In the following piece of code about Struts action class,
@Namespace("/admin_side")
@ResultPath("/WEB-INF/content") // Default.
public final class TestAction extends ActionSupport implements Serializable
{
private static final long serialVersionUID = 1L;
private static final String SUCCESS = "success";
private String name;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
@Action(value="test",results={@Result(name="success",location="Test.jsp")})
public String execute() throws Exception
{
System.out.println("name = "+name);
System.out.println("email = "+email);
return SUCCESS;
}
// Some annotations to map this method to <s:submit>
public String postAction()
{
System.out.println("postAction() invoked.");
System.out.println("name = "+name);
System.out.println("email = "+email);
return SUCCESS;
}
}
I want to invoke the postAction()
method on the given submit button like so,
<s:form action="test">
<s:textfield id="name" name="name" label="Enter your name"/>
<s:textfield id="email" name="email" label="Enter your email"/>
<s:submit value="Submit" method="postAction"/>
</s:form>
I have seen some questions like this one but all of them use XML configurations in struts.xml
.
How to make it possible using convention plugin?
You need to use namespace
attribute because your action is mapped with @Namespace
.
<s:form namespace="/admin_side" action="test">
<s:textfield id="name" name="name" label="Enter your name"/>
<s:textfield id="email" name="email" label="Enter your email"/>
<s:submit value="Submit" method="postAction"/>
</s:form>
If this doesn't work in the latest version according to WW-4023 then you can invoke a method directly
<s:url var="myUrl" namespace="/admin_side" action="test" method="postAction"/>
<s:form action="%{#myUrl}">
<s:textfield id="name" name="name" label="Enter your name"/>
<s:textfield id="email" name="email" label="Enter your email"/>
<s:submit value="Submit"/>
</s:form>
or configure params
interceptor parameter excludeParams
to remove method
parameter from excluded parameters.
Note, either you use DMI and the methods above or don't use it, in this case you should map an action to the method and don't use attributes method
or submit
tag's method
and action
as the issue above restrict using special parameters. If you have multiple submit buttons if you follow that restriction you have to dynamically change form
tag's action attribute using JavaScript onclick
event.
Different methods are achievable by:
moving the @Action
annotation from method-level to class-level:
@Action(value="test",results={@Result(name="success",location="Test.jsp")})
public final class TestAction extends ActionSupport implements Serializable {
renaming the execute()
method into something else, eg. test()
:
public String test() throws Exception {
System.out.println("name = "+name);
System.out.println("email = "+email);
return SUCCESS;
}
public String postAction() {
System.out.println("postAction() invoked.");
System.out.println("name = "+name);
System.out.println("email = "+email);
return SUCCESS;
}
From the documentation:
Applying @Action and @Actions at the class level
There are circumstances when this is desired, like when using Dynamic
Method Invocation. If an execute method is defined in the class, then
it will be used for the action mapping, otherwise the method to be
used will be determined when a request is made (by Dynamic Method
Invocation for example)
, and obviously by enabling Dynamic Method Invocation in Struts.xml.
But this should be avoided; read this article to understand why: Making Struts2 app more secure: disable DMI.
Note that Struts2 Maven archetypes already has DMI set to false, because it is discouraged.
Then, you should turn off DMI, and start using multiple Actions instead of multiple methods, by simply annotating the other Action's methods too, and using different action
attributes in the <s:submit/>
button :
@Action(value="test",results={@Result(name="success",location="Test.jsp")})
public String test() throws Exception {
System.out.println("name = "+name);
System.out.println("email = "+email);
return SUCCESS;
}
@Action(value="postAction",results={@Result(name="success",location="Test.jsp")})
public String postAction() {
System.out.println("postAction() invoked.");
System.out.println("name = "+name);
System.out.println("email = "+email);
return SUCCESS;
}
and in JSP:
<s:form namespace="/admin_side">
<s:textfield id="name" name="name" label="Enter your name" />
<s:textfield id="email" name="email" label="Enter your email" />
<s:submit value="Submit to test()" action="test" />
<s:submit value="Submit to postAction()" action="postAction" />
</s:form>
EDIT: Since Struts 2.3.15.3
, you need to explicitly enable the action:
suffix with:
<constant name="struts.mapper.action.prefix.enabled" value="true"/>
Because it won't work by default.