Java 使用SpringWebflow 2.4.0上传文件,参数未绑定

Java 使用SpringWebflow 2.4.0上传文件,参数未绑定,java,spring-security,spring-webflow,Java,Spring Security,Spring Webflow,我使用的是SpringFramework 4.1.5、SpringSecurity 4.0.0.RC2、SpringWebflow2.4.0.RELEASE和Tomcat8.0.15 我在webflow中遵循了这个示例,但是我无法在表单bean中获取该文件 形式 <form:form action="${flowExecutionUrl}" method="post" commandName="fileForm" enctype="multipart/form-data">

我使用的是SpringFramework 4.1.5、SpringSecurity 4.0.0.RC2、SpringWebflow2.4.0.RELEASE和Tomcat8.0.15

我在webflow中遵循了这个示例,但是我无法在表单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>
流动

<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>
多部件解析器

@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();
    }
}
FileFormbean中未绑定multipartFileUpload属性

我不确定它是否有用,但在org.springframework.webflow.context.servlet.HttpServletRequestParameterMap的第52行

if (request instanceof MultipartHttpServletRequest) {
        // ... process multipart data
    }
检查失败,因为请求是org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper的实例

更新1 我可以确认multipartRequest.getFilefile也可以工作

但我无法启用org.springframework.web.multipart.support.MultipartFilter过滤器

如果启用了multipartRequest,则multipartRequest是标准multipartttpServletRequest的实例,其中包含Servlet3Security ContextHolderWareRequestWrapper,包装Servlet3SaveToSessionRequestWrapper,最后包含无法访问的默认multipartttpServletRequest和我需要的multipartFile,但我无法获取它

禁用它我可以获得它,因为multipartRequest成为DefaultMultipartTTpServletRequest的实例,但是没有文件验证,并且CommonMultipartResolver的maxUploadSize限制没有得到遵守

另外,如果Tomcat因为文件太大而无法满足Tomcat的maxPostSize限制而启动异常,则我的CustomAccessDeniedHandler会捕获该异常,因为它的类型是org.springframework.security.access.AccessDeniedException,错误消息为无效CSRF令牌“null”,在请求参数“_CSRF”或标头“X-CSRF-Token”上找到该令牌


查看请求对象,我可以看到原始的Tomcat异常org.apache.Tomcat.util.http.fileupload.FileUploadBase$sizelimiteExceedeException。似乎没有什么可以正确处理它,但是,正如我所说的,如果启用MultipartFilter,我将无法获取文件。

我们遇到了同样的问题,因为我们在web应用程序中使用了Spring Security 4.xx。 问题在于org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper不是org.springframework.web.multipart.MultipartHttpServletRequest的实例,但它包含一个实例。转换为将不起作用,并且将发生ClassCastException

这就是原因

if (request instanceof MultipartHttpServletRequest) {
    // ... process multipart data
}
永远都不可能是真的

其想法是从本机HttpServletRequest创建一个org.springframework.web.multipart.support.StandardMultipartTTpServletRequest,它可以工作

在我们的WebApp中,我们使用中指示的Pojo操作

我们的解决办法:

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中,我们有一个如下的操作状态:

<action-state id="upload-action">
    <evaluate expression="pojoAction.uploadFile(flowRequestContext)"/>
    <transition to="show"/>
</action-state>
在这种情况下,不需要绑定到模型。 我希望有帮助

根据更新1

在web.xml中,CSRF保护筛选器必须在SpringSecurityFilterChain之前声明

在我们的应用程序中,web.xml如下所示

    <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>

我们遇到了同样的问题,因为我们在web应用程序中使用了SpringSecurity4.xx。 问题在于org.springframework.security.web.context.HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper不是org.springframework.web.multipart.MultipartHttpServletRequest的实例,但它包含一个实例。转换为将不起作用,并且将发生ClassCastException

这就是原因

if (request instanceof MultipartHttpServletRequest) {
    // ... process multipart data
}
永远都不可能是真的

其想法是从本机HttpServletRequest创建一个org.springframework.web.multipart.support.StandardMultipartTTpServletRequest,它可以工作

在我们的WebApp中,我们使用中指示的Pojo操作

我们的解决办法:

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中,我们有一个如下的操作状态:

<action-state id="upload-action">
    <evaluate expression="pojoAction.uploadFile(flowRequestContext)"/>
    <transition to="show"/>
</action-state>
在这种情况下,不需要绑定到模型。 我希望有帮助

根据更新1

在web.xml中,CSRF保护筛选器必须在SpringSecurityFilterChain之前声明

在我们的应用程序中,web.xml如下所示

    <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>

谢谢,按照你的建议,我成功了。但是,您的PojoAction.java代码有点不正确。它应该是final multipartttpServletRequest multipartRequest=新标准multipartttpServletRequestHttpServletRequest context.getNativeRequest;final MultipartFile multipartFileUpload=multipartRequest.getMultiFileMap.getFirstmultipartFileUpload;。另外,我必须删除指示的MultipartFilter,否则它将无法工作。谢谢您的建议。我修好了。对不起。multipartRequest.getFilefile也应该可以工作。所示的多部分过滤器在启用了CSRF-Protection的web应用程序中工作。您是否使用带有ServletApi 3.0的CommonsMultipartResolver?也许您可以使用所描述的StandardServletMultipartResolver。是的,就是它!非常感谢你!!不幸的是,现在我有另一个问题发布了谢谢,f
遵照你的建议,我得以使它生效。但是,您的PojoAction.java代码有点不正确。它应该是final multipartttpServletRequest multipartRequest=新标准multipartttpServletRequestHttpServletRequest context.getNativeRequest;final MultipartFile multipartFileUpload=multipartRequest.getMultiFileMap.getFirstmultipartFileUpload;。另外,我必须删除指示的MultipartFilter,否则它将无法工作。谢谢您的建议。我修好了。对不起。multipartRequest.getFilefile也应该可以工作。所示的多部分过滤器在启用了CSRF-Protection的web应用程序中工作。您是否使用带有ServletApi 3.0的CommonsMultipartResolver?也许您可以使用所描述的StandardServletMultipartResolver。是的,就是它!非常感谢你!!不幸的是,现在我有另一个问题张贴