I have the multipart resolver configured for the project:
@EnableWebMvc
@ComponentScan({"com.dg"})
@Configuration
@SuppressWarnings("deprecation")
public class AppConfig extends AbstractFlowConfiguration {
@Bean
public CommonsMultipartResolver fileResolver() {
CommonsMultipartResolver cr = new CommonsMultipartResolver();
cr.setDefaultEncoding("UTF-8");
cr.setMaxUploadSize(26214400);
return cr;
}
}
I am using a serializable object as the model:
public class NewRequestModel implements Serializable {
private static final long serialVersionUID = -5372803991673351564L;
private String entry;
private transient MultipartFile attachment;
... // getters and setters
}
When the page loads, I initialize the model:
WEBFLOW
<var name="requestModel" class="com.dg.model.request.NewRequestModel" />
<on-start>
<evaluate expression="newRequestAction.initTestRequest" />
</on-start>
ACTION
public Event initTestRequest(RequestContext context) {
NewRequestModel model = (NewRequestModel)context.getFlowScope().get("requestModel");
if (model==null) {
model = new NewRequestModel();
}
context.getFlowScope().put("requestModel", model);
return new Event(this, "DONE");
}
I bind the values in the JSP:
<form:form id="actionForm" method="POST" modelAttribute="requestModel" enctype="multipart/form-data">
<div class="panel-heading">
Test Request
</div>
<div class="panel-body">
<div class="form-group">
<form:input path="entry" />
</div>
<div class="form-group">
<form:input type="file" path="attachment" />
</div>
<div>
<button type="button" class="btn btn-primary" onclick="app.submitEvent({formSelector: '#actionForm',event: 'submitAndValidate'});">
Submit Request
</button>
</div>
</div>
</form:form>
When the button is clicked, the form is submitted with event "submitAndValidate"
<view-state id="start" view="request/test/test-request" model="requestModel">
<transition on="submitAndValidate" to="submitAndValidate" />
</view-state>
<action-state id="submitAndValidate">
<evaluate expression="newRequestAction.testRequest" />
<transition to="start" />
</action-state>
When I debug into the Action class, testRequest method, The model does not retain the values submitted with the form.
public Event testRequest(RequestContext context) {
NewRequestModel model = (NewRequestModel)context.getFlowScope().get("requestModel");
String entry= model.getEntry();
MultipartFile file = model.getAttachment();
if (entry==null) {
// is null when enctype is included on form
// is populated when enctype is not included on form
}
if (file==null) {
// always null for some reason
}
return new Event(this, "DONE");
}
If I remove enctype="multipart/form-data" from the form, the binding works for the "entry" variable. Of course, this won't allow for uploading a document. So I need to be able to include the enctype on the form.
I've gone over this and looked up answers and read the guides and I just am not seeing why this would fail. I appreciate any help in finding the offending configuration/code.
The problem was in my MultipartResolver bean configuration. Spring is looking specifically for a bean named "multipartResolver." Therefore I had 2 options to fix this:
OPTION 1 - specify the name in the @Bean annotation
@Bean(name="multipartResolver")
public CommonsMultipartResolver fileResolver() {
CommonsMultipartResolver cr = new CommonsMultipartResolver();
cr.setDefaultEncoding("UTF-8");
cr.setMaxUploadSize(26214400);
return cr;
}
OPTION 2 - rename the method
@Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver cr = new CommonsMultipartResolver();
cr.setDefaultEncoding("UTF-8");
cr.setMaxUploadSize(26214400);
return cr;
}
For most people, the above change will likely resolve the issue. However, I also needed to add Apache Commons IO to my project due to ClassNotFoundException errors that appeared after making the above change.
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
With these updates in place, the form now binds properly. My issues are resolved.