使用Spring WebFlow 2.4.0上传文件,参数未绑定 [英] File Upload using Spring WebFlow 2.4.0, parameter not binded
问题描述
我正在使用Spring Framework 4.1.5,Spring Security 4.0.0.RC2,Spring Webflow 2.4.0.RELEASE和Tomcat 8.0.15。
I'm using Spring Framework 4.1.5, Spring Security 4.0.0.RC2, Spring Webflow 2.4.0.RELEASE and Tomcat 8.0.15.
I遵循webflow中的示例文档,但我无法在我的表单bean中获取该文件。
I followed the example in the webflow documentation, but I can't get the file in my form bean.
表单
<form:form action="${flowExecutionUrl}" method="post" commandName="fileForm" enctype="multipart/form-data">
<form:input type="file" value="" path="multipartFileUpload"/>
<button type="submit" name="_eventId_forward"><spring:message code="signup.forward"/></button>
<sec:csrfInput/>
</form:form>
表单bean
public class FileForm implements Serializable {
private static final long serialVersionUID = 1L;
private transient MultipartFile multipartFileUpload;
public MultipartFile getMultipartFileUpload() {
return multipartFileUpload;
}
public void setMultipartFileUpload(final MultipartFile multipartFileUpload) {
this.multipartFileUpload = multipartFileUpload;
}
}
流程
<view-state id="companyLogo" view="signup/company-logo" model="fileForm">
<var name="fileForm" class="it.openex.pmcommonw.form.FileForm"/>
<transition on="back" to="chooseProfile" bind="false" validate="false"/>
<transition on="forward" to="companyInfo">
<evaluate expression="userCommonBean.uploadImage(fileForm)"/>
</transition>
</view-state>
支持对象
@Component
public class UserCommonBean {
public static void uploadImage(final FileForm fileForm) throws IOException, ServletException {
fileForm.getMultipartFileUpload(); // always null!!!
}
}
multipartResolver
The multipartResolver
@Bean
public CommonsMultipartResolver filterMultipartResolver() {
final CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(10 * 1024 * 1024);
multipartResolver.setMaxInMemorySize(1048576);
multipartResolver.setDefaultEncoding("UTF-8");
return multipartResolver;
}
webflow配置
@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
@Autowired
TilesViewResolver viewResolver;
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.setFlowBuilderServices(flowBuilderServices())
.setBasePath("/WEB-INF/flows/")
.addFlowLocation("signup.xml", UrlMap.SIGNUP_WEBFLOW)
.addFlowLocation("user-edit.xml", UrlMap.PROFILE_EDIT_WEBFLOW)
.build();
}
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry()).build();
}
@Bean
public FlowHandlerAdapter flowHandlerAdapter() {
final FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowExecutor(flowExecutor());
return flowHandlerAdapter;
}
@Bean
public FlowHandlerMapping flowHandlerMapping() {
final FlowHandlerMapping flowHandlerMapping = new FlowHandlerMapping();
flowHandlerMapping.setFlowRegistry(flowRegistry());
// this has to be less than -1
flowHandlerMapping.setOrder(-2);
return flowHandlerMapping;
}
@Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
final MvcViewFactoryCreator mvcViewFactoryCreator = new MvcViewFactoryCreator();
final List<ViewResolver> viewResolvers = Collections.singletonList(viewResolver);
mvcViewFactoryCreator.setViewResolvers(viewResolvers);
return mvcViewFactoryCreator;
}
@Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder().setViewFactoryCreator(mvcViewFactoryCreator())
.setValidator(localValidatorFactoryBean()).build();
}
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}
}
Tomcat的 context.xml内
我已添加 allowCasualMultipartParsing =true
Inside Tomcat's context.xml
I already added allowCasualMultipartParsing="true"
调试应用程序我可以看到请求中的文件数据,如果我尝试将表单发布到普通控制器,我可以得到它。
Debugging the application I can see the file data inside the request, and I can get it if I try to post the form to a normal controller.
我还试图删除Spring Security,但它仍然没有在Spring WebFlow中工作。
I tried also to remove Spring Security but it still didn't work inside Spring WebFlow.
在requestParameters对象中,只有3个对象:
In the requestParameters object there are only 3 objects:
- 执行
- _eventid_forward
- _csrf
日志中有一些相关的行
DEBUG 2015-03-13 18:03:15,053: org.springframework.web.multipart.support.MultipartFilter - Using MultipartResolver 'filterMultipartResolver' for MultipartFilter
DEBUG 2015-03-13 18:03:15,053: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'filterMultipartResolver'
DEBUG 2015-03-13 18:03:15,053: org.springframework.web.multipart.support.MultipartFilter - Resolving multipart request [/registrazione] with MultipartFilter
DEBUG 2015-03-13 18:03:15,060: org.springframework.web.multipart.commons.CommonsMultipartResolver - Found multipart file [multipartFileUpload] of size 469217 bytes with original filename [PoliziaMunicipale.png], stored in memory
....
DEBUG 2015-03-13 18:03:15,072: org.springframework.binding.mapping.impl.DefaultMapper - Beginning mapping between source [org.springframework.webflow.core.collection.LocalParameterMap] and target [it.openex.pmcommonw.form.FileForm]
DEBUG 2015-03-13 18:03:15,072: org.springframework.binding.mapping.impl.DefaultMapping - Adding mapping result [TargetAccessError@34bc31ea mapping = parameter:'execution' -> execution, code = 'propertyNotFound', error = true, errorCause = org.springframework.binding.expression.PropertyNotFoundException: Property not found, originalValue = 'e1s2', mappedValue = [null]]
DEBUG 2015-03-13 18:03:15,072: org.springframework.binding.mapping.impl.DefaultMapper - Completing mapping between source [org.springframework.webflow.core.collection.LocalParameterMap] and target [it.openex.pmcommonw.form.FileForm]; total mappings = 1; total errors = 1
multipartFileUpload
属性是没有绑定在 FileForm
bean中。
The multipartFileUpload
property is not binded in the FileForm
bean.
我不确定它是否有用,但在<$ c $里面c> org.springframework.webflow.context.servlet.HttpServletRequestParameterMap 第52行
I'm not sure if it's useful, but inside org.springframework.webflow.context.servlet.HttpServletRequestParameterMap
at line 52
if (request instanceof MultipartHttpServletRequest) {
// ... process multipart data
}
它未通过检查,因为该请求是 org.springframework.security.web.context.HttpSessionSecurityContextRepository的实例$ Servlet3SaveToSessionRequestWrapper
it fails the check because the request is an instance of org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper
我可以确认multipartRequest.getFile(file)也可以。
I can confirm that multipartRequest.getFile("file") also works.
I无法启用 org.springframework.web.multipart.support.MultipartFilter
过滤器。
如果已启用multipartRequest是 StandardMultipartHttpSe的一个实例rvletRequest
包含 Servlet3SecurityContextHolderAwareRequestWrapper
,包装 Servlet3SaveToSessionRequestWrapper
,最后包含无法访问的 DefaultMultipartHttpServletRequest
我需要的multipartFile,但我无法得到它。
If it's enabled the multipartRequest is an instance of StandardMultipartHttpServletRequest
containing a Servlet3SecurityContextHolderAwareRequestWrapper
, wrapping a Servlet3SaveToSessionRequestWrapper
, finally containing an unreachable DefaultMultipartHttpServletRequest
with the multipartFile I need, but I can't get it.
禁用它我能够得到它因为multipartRequest成为 DefaultMultipartHttpServletRequest
的实例,但没有文件验证,并且不遵守 CommonsMultipartResolver
的maxUploadSize限制。
Disabling it I'm able to get it because multipartRequest became an instance of DefaultMultipartHttpServletRequest
, but there's no file validation and the maxUploadSize limit of CommonsMultipartResolver
is not respected.
如果Tomcat因为Tomcat的maxPostSize限制文件过大而引发异常,则我的 CustomAccessDeniedHandler
会捕获该异常,因为它的类型是 org.springframework.security.access.AccessDeniedException
,错误消息是在请求参数'上找到了无效的CSRF令牌'null' _csrf'或标题'X-CSRF-TOKEN'。
。
Plus if Tomcat launches an exception because the file is too big for Tomcat's maxPostSize limit, the exception is caught by my CustomAccessDeniedHandler
because its type is org.springframework.security.access.AccessDeniedException
, and the error message is Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
.
查看请求对象,我可以看到原始的Tomcat异常 org.apache.tomcat.util.http.fileupload.FileUploadBase $ SizeLimitExceededException
。似乎没有什么可以正确处理它,但是,正如我所说,如果我启用MultipartFilter我无法获取文件。
Looking at the request object I can see the original Tomcat exception org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException
. It seems like there's nothing to handle it properly, but, as I said, if I enable the MultipartFilter I can't get the file.
推荐答案
我们遇到了同样的问题,因为我们在Web应用程序中使用Spring Security 4.xx。
问题是 org.springframework.security.web.context.HttpSessionSecurityContextRepository $ Servlet3SaveToSessionRequestWrapper
不是 org.springframework的实例。 web.multipart.MultipartHttpServletRequest
但它包含一个。强制转换为无效, ClassCastException
将会发生。
We ran into the same problems, since we use Spring Security 4.xx in our web application.
The Problem is that a org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper
isn't instance of org.springframework.web.multipart.MultipartHttpServletRequest
but it contains one. A cast to won't work and ClassCastException
will occur.
这就是为什么
if (request instanceof MultipartHttpServletRequest) {
// ... process multipart data
}
永远不能 true
。
想法是创建 org.springframework.web.multipart.support来自本地
,它可以工作。 HttpServletRequest
的.StandardMultipartHttpServletRequest
The idea was to create a org.springframework.web.multipart.support.StandardMultipartHttpServletRequest
from the native HttpServletRequest
and it works.
在我们的WebApp中,我们使用Pojo操作在 Spring Webflow文档中指出第6.5.1节。调用POJO操作。
In our WebApp we use Pojo Actions indicated in Spring Webflow documentation Section 6.5.1. Invoking a POJO action.
我们的解决方法:
PojoAction.java
PojoAction.java
public String fileUpload(RequestContext requestContext) {
final ServletExternalContext context = (ServletExternalContext) requestContext.getExternalContext();
final MultipartHttpServletRequest multipartRequest = new StandardMultipartHttpServletRequest((HttpServletRequest)context.getNativeRequest());
final File file = multipartRequest.getFile("file");
fileUploadHandler.processFile(file); //do something with the submitted file
}
在flow.xml中我们有一个动作这样的状态:
In flow.xml we have an action state like this:
<action-state id="upload-action">
<evaluate expression="pojoAction.uploadFile(flowRequestContext)"/>
<transition to="show"/>
</action-state>
在这种情况下,不需要绑定到模型。
我希望它有所帮助!
In this case the binding to a model is not needed. I hope it helps!
根据更新1
在web.xml中,CSRF保护过滤器必须在SpringSecurityFilterChain之前声明。
In web.xml the CSRF-Protection Filter must declared before SpringSecurityFilterChain.
在我们的应用程序中,web.xml看起来像这样
In our application the web.xml looks like this
<filter>
<filter-name>csrfFilter</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>csrfFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
这篇关于使用Spring WebFlow 2.4.0上传文件,参数未绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!