I want to add 3 button into struts form. My code is :
@Action("/admin/product/insert")
public String insert() throws Exception {
if(upload.hasFile()){
model.setImage(upload.getFileFileName());
upload.saveTo("../images/customers/");
}
else{
model.setImage("product.png");
}
XHibernate.save(model);
return "new";
}
@Action("/admin/product/update")
public String update() throws Exception {
if(upload.hasFile()){
model.setImage(upload.getFileFileName());
upload.saveTo("../images/customers/");
}
System.out.println("update");
XHibernate.update(model);
return "input";
}
@Action("/admin/product/delete")
public String delete() throws Exception {
XHibernate.delete(model);
return "new";
}
In jsp:
<s:form enctype="multipart/form-data" theme="simple" role="form">
<div class="form-group col-md-4">
<label for="id">Product Id</label>
<s:textfield id="productId" name="id" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="name">Product Name</label>
<s:textfield name="name" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="unitPrice">Unit Price</label>
<s:textfield name="unitPrice" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="unitBrief">Unit Description</label>
<s:textfield name="unitBrief" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="discount">Discount</label>
<s:textfield name="discount" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="quantity">Quantity</label>
<s:textfield name="quantity" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="productDate">Product Date</label>
<s:textfield name="productDate" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="supplier.id">Supplier</label>
<s:select name="supplier.id" list="suppliers" listKey="id"
listValue="name" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label for="category.id">Category</label>
<s:select name="category.id" list="categories" listKey="id"
listValue="name" cssClass="form-control" />
</div>
<div class="form-group col-md-4">
<label>Features</label>
<div>
<label><s:checkbox name="available" /> Available</label> <label><s:checkbox
name="special" /> Special</label> <label><s:checkbox
name="latest" /> latest</label>
</div>
</div>
<div class="form-group col-md-4">
<label for="image">Image</label> <input id="image" type="file"
name="upload.file">
<s:hidden name="image" />
</div>
<div class="form-group col-md-12">
<label for="description">Description</label>
<s:textarea id="index_description" name="description" rows="30"
cssClass="form-control" />
</div>
<div class="col-md-12">
<s:submit value="Thêm mới" action="admin/product/insert"
cssClass="btn btn-default" />
<s:submit value="Cập nhật" action="admin/product/update"
cssClass="btn btn-default" />
<s:submit value="Xóa" action="admin/product/delete" cssClass="btn btn-default" />
<a href="product/index" class="btn btn-default">Nhập lại</a>
</div>
</s:form>
The problem is it can't call the exactly action.
I always got the error: " There is no Action mapped for namespace /admin/product and action name admin/product/update.".
Do i have to split it to 3 forms ? OR Is there any way to have 3 buttons for 3 actions in 1 form like my code ? Any help would be great.
updated the logging when enable devmode:
ognl.MethodFailedException: Method "setDiscount" failed for object eshop.entity.Product@48e4d3df [java.lang.NoSuchMethodException: setDiscount([Ljava.lang.String;)]
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:823)
at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:964)
at ognl.ObjectPropertyAccessor.setPossibleProperty(ObjectPropertyAccessor.java:75)
at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:131)
at com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty(ObjectAccessor.java:28)
at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1656)
at com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor.setProperty(CompoundRootAccessor.java:50)
at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1656)
at ognl.ASTProperty.setValueBody(ASTProperty.java:101)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
at ognl.SimpleNode.setValue(SimpleNode.java:246)
at ognl.Ognl.setValue(Ognl.java:476)
at com.opensymphony.xwork2.ognl.OgnlUtil.setValue(OgnlUtil.java:192)
at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:155)
at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:143)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.setParameters(ParametersInterceptor.java:273)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:187)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:148)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:93)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:306)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:89)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:128)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at org.apache.struts2.interceptor.ProfilingActivationInterceptor.intercept(ProfilingActivationInterceptor.java:104)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:267)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:126)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:138)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:148)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:128)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:176)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:236)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:468)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
To fix your current problem, you should add
in struts.xml, that is false by default, and will take all the part before the last slash as namespace instead of action name. BTW this has side effects:
To fix the problem the right way, you need to make a correct usage of namespaces:
Action
JSP
You should also refactor the package structure for Actions and JSPs to follow the namespace structure.
P.S: remember to set action prefix enabled as explained in this answer if you are using a Struts2 version higher than 2.3.15.2:
EDIT
If the
namespace
of the Action you are using to show your JSP is not the same of the actions called (in this case,/admin/product
), you need to specify it in<s:form>
tag:And (if you are using a Struts2 version higher than 2.3.15.2), set the following property in struts.xml:
because it has been disabled by default due to security reason.