jsf – ICEfaces / Seam文件上传组件不上传文件

更新

我目前正在ICEfaces论坛上解决我的问题 – 遗憾的是,现在没有一个提供的选项导致了解决方案,但是他们确实让我对整个JSF主题有了更多的了解(相关信用归功于BalusC,经常:-)).

我会尽量保持这个线程的最新状态并发布一个答案,如果问题最终得到解决,以帮助其他可能遇到它的人.

到目前为止我的发现是:

>需要禁用Seam Multipart Filter,因为它会阻止fileEntry组件正常工作
>我的应用程序中仍然存在一些讨厌的库问题导致(无声)ClassLoading-问题:存在2个icefaces-ace.jar文件,一个在EAR / lib中,一个在EAR / WAR / WEB-INF / lib中.从WEB-INF中删除该组件会导致组件无效,从EAR / lib中删除该组件导致我的应用程序不再部署.

将所有前端jar(icefaces.jar,icefaces-ace.jar,icefaces-compat.jar)从EAR / lib移动到WEB-INF / lib时,我收到了我的EAR jar部分的各种ClassNotFoundExceptions:ValueChangeEvent,RowSelectorEvent等无法找到(这意味着,所有这些事件都从视图进入后端).例:

12:12:42,145 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-16) MSC00001: 
Failed to start service jboss.deployment.subunit."myApp.ear"."myApp.jar".POST_MODULE: 
org.jboss.msc.service.StartException in service 
jboss.deployment.subunit."myApp.ear"."myApp.jar".POST_MODULE: Failed to process phase 
POST_MODULE of subdeployment "myApp.jar" of deployment "myApp.ear"
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:119) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) [rt.jar:1.7.0_06]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) [rt.jar:1.7.0_06]
at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_06]

Caused by: java.lang.RuntimeException: Error getting reflective information for class my.company.myApp.myExampleBean with ClassLoader ModuleClassLoader for Module "deployment.myApp.ear.myApp.jar:main" from Service Module Loader
at org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex.getClassIndex(DeploymentReflectionIndex.java:70) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.ee.metadata.MethodAnnotationAggregator.runtimeAnnotationInformation(MethodAnnotationAggregator.java:58)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.handleAnnotations(InterceptorAnnotationProcessor.java:85)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.processComponentConfig(InterceptorAnnotationProcessor.java:70)
at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.deploy(InterceptorAnnotationProcessor.java:55)
at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:113) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
... 5 more

Caused by: java.lang.NoClassDefFoundError: com/icesoft/faces/component/ext/RowSelectorEvent
at java.lang.Class.getDeclaredMethods0(Native Method) [rt.jar:1.7.0_06]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2442) [rt.jar:1.7.0_06]
at java.lang.Class.getDeclaredMethods(Class.java:1808) [rt.jar:1.7.0_06]
at org.jboss.as.server.deployment.reflect.ClassReflectionIndex.<init>(ClassReflectionIndex.java:65) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex.getClassIndex(DeploymentReflectionIndex.java:66) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
... 10 more
Caused by: java.lang.ClassNotFoundException: com.icesoft.faces.component.ext.RowSelectorEvent from [Module "deployment.myApp.ear.myApp.jar:main" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) [jboss-modules.jar:1.1.1.GA]
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120) [jboss-modules.jar:1.1.1.GA]
... 15 more

整个故事

我正在使用Seam 2.3和ICEfaces 3.1.0开发Web应用程序.这意味着,正在使用JSF2.

我的应用程序作为EAR部署在JBoss AS 7.1.0上,包含应用程序逻辑的JAR和所有视图相关内容的WAR.

我最近从Seam 2.1.2迁移到Seam 2.3和ICEfaces 1.8.2到3.1.0.这一步很糟糕,但现在一切正常,抛开一些小问题.

唯一的大问题是,当我使用组件上传文件时,无论我使用Seam组件还是ICEfaces组件 – 在Seam中,上传的文件始终为null,而在ICEfaces中,我的fileEntryListener-Method永远不会被调用.

使用ICEfaces:

在2.X之前的ICEfaces版本中,有一些ice:inputFile-component,它已被2.X删除并替换为ace:fileEntry.

InputFile运行良好,但FileEntry没有.我的问题与描述完全相同
JSF : Issues with File Upload using Icefaces component – 永远不会调用fileEntryListener.我尝试了那里的建议(在周围的表单上使用enctype =“multipart / form-data”,使用h:commandButton进行表单提交),但它不起作用.提供的唯一解决方案是切换到Richfaces,这对我来说不是一个选择.

使用Seam:

很高兴,Seam拥有自己的内置fileUpload-component,s:fileUpload.

它也不起作用,但至少向我展示了一个可以进一步观察的地方.在调试这个组件的doDecode-Methods时,我发现我的请求不是MultipartRequest.疯狂的事!用于上载文件的所有表单都将enctype声明为multipart / form-data.我想,当我尝试使用ICEfaces组件时,也会发生同样的情况 – 没有多部分请求,导致没有调用侦听器.

那么:我如何让它发挥作用?什么是没有Request作为MultipartRequest进入?我是否想念web / components.xml中的内容?

web.xml中:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xmlns/
javaee/web-app_3_0.xsd"
version="3.0">
<listener>
    <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>

<filter>
    <filter-name>Seam Filter</filter-name>
    <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Seam Filter</filter-name>
    <url-pattern>*.seam</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/icefaces/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.seam</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>Resource Servlet</servlet-name>
    <servlet-class>com.icesoft.faces.webapp.CompatResourceServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Resource Servlet</servlet-name>
    <url-pattern>/xmlhttp/*</url-pattern>
</servlet-mapping>

<session-config>
    <session-timeout>60</session-timeout>
</session-config>

<context-param>
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
</context-param>

<context-param>
    <param-name>facelets.DEVELOPMENT</param-name>
    <param-value>true</param-value>
</context-param>

<context-param>
    <param-name>com.icesoft.faces.actionURLSuffix</param-name>
    <param-value>.seam</param-value>
</context-param>

<context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>-1</param-value>
</context-param>

<context-param>
    <param-name>com.icesoft.faces.synchronousUpdate</param-name>
    <param-value>false</param-value>
</context-param>

<context-param>
    <param-name>com.icesoft.faces.doJSFStateManagement</param-name>
    <param-value>true</param-value>
</context-param>

<context-param>
    <param-name>com.icesoft.faces.standardRequestScope</param-name>
    <param-value>true</param-value>
</context-param>

<context-param>
    <param-name>com.icesoft.faces.uploadDirectory</param-name>
    <param-value>upload</param-value>
</context-param>

<context-param>
    <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
    <param-value>false</param-value>
</context-param>

components.xml(省略了Seam 2.3名称空间声明

<core:init jndi-pattern="java:app/myApp/#{ejbName}" debug="false"
    distributable="false" />


<component class="org.jboss.seam.transaction.EjbSynchronizations"
    jndi-name="java:app/jboss-seam/EjbSynchronizations" />

<core:manager concurrent-request-timeout="500"
    conversation-timeout="90000000" conversation-id-parameter="cid"
    parent-conversation-id-parameter="pid" />

<web:hot-deploy-filter url-pattern="*.seam" />

<web:multipart-filter create-temp-files="true" 
    max-request-size="1000000" 
    url-pattern="/*"/>


<persistence:managed-persistence-context
    name="entityManager" auto-create="true" persistence-unit-jndi-name="java:/myAppEntityManagerFactory" />

<security:identity authenticate-method="#{authenticator.authenticate}" />
<security:remember-me enabled="true" />

<security:rule-based-permission-resolver
    security-rules="#{securityRules}" />

<drools:rule-base name="securityRules">
    <drools:rule-files>
        <value>/security.drl</value>
    </drools:rule-files>
</drools:rule-base>

<async:quartz-dispatcher />

<factory name="sessionTimeoutSeconds" scope="SESSION"
    value="#{facesContext.externalContext.getSession(true).getMaxInactiveInterval()}" />

<factory name="basePath"
    value="#{facesContext.externalContext.request.scheme}://#{facesContext.externalContext.request.serverName}:
                #{facesContext.externalContext.request.serverPort}#{facesContext.externalContext.request.contextPath}" />

<factory name="contextPath"
    value="#{facesContext.externalContext.request.contextPath}" />

示例JSF-source(Seam)

<h:form enctype="multipart/form-data">
    <s:decorate>
    <s:fileUpload data="#{uploadBean.fileData}"
        contentType="#{uploadBean.contentType}"
            fileName="#{uploadBean.fileName}" />
    <h:commandButton value="Upload File" type="submit" />
   </s:decorate>
</h:form>

示例JSF源(ICEfaces)

<h:form enctype="multipart/form-data">
    <ace:fileEntry id="file-entry" relativePath="/files/"
            fileEntryListener="#{uploadBean.uploadFile}"
        useSessionSubdir="true" />

    <h:commandButton id="submit" type="submit" value="Send File" />
</h:form>

JSF映射到Seam组件,fileData为byte [],fileName和contentType为String. fileEntryListener映射到void方法,该方法将FileEntryEvent作为输入.

更新

为了让你及时了解我的发现到目前为止:

考虑到BalusC的答案,我更深入地研究了过滤器的内容.我已经尝试添加/删除Seam Multipart Filter,但现在我发现当我在components.xml中添加它并通过显式禁用它时

<web:multipart-filter disabled="true"/>

ICEfaces至少发生了一些事情:FileEntryPhaseListener抛出了异常,这是以前从未发生的事情:

09:26:19,124 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-
localhost-127.0.0.1-8080-2) JSF1071: javax.faces.event.AbortProcessingException erfasst 
während beforePhase()-Verarbeitung von RENDER_RESPONSE 6 : UIComponent-ClientId=, Message=/
template/patient/documents/instantiation/documentInsertPopup.xhtml @135,98 
fileEntryListener="#{uploadBean.fileUploadListener}": 
Method not found: 
my.company.package.stuff.UploadBean@313d
62f1.fileUploadListener(org.icefaces.ace.component.fileentry.FileEntryEvent)

09:26:19,126 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-
localhost-127.0.0.1-8080-2) /template/upload.xhtml @135,98 fileEntryListener="#
{uploadBean.fileUploadListener}": Method not found: 
my.company.package.stuff.UploadBean@313d
62f1.fileUploadListener(org.icefaces.ace.component.fileentry.FileEntryEvent): 
javax.faces.event.AbortProcessingException: /upload.xhtml @135,98 fileEntryListener="#
{uploadBean.fileUploadListener}": Method not found: 
my.company.package.stuff.UploadBean@313d
62f1.fileUploadListener(org.icefaces.ace.component.fileentry.FileEntryEvent)

    at org.icefaces.ace.component.fileentry.FileEntry.broadcast(FileEntry.java:350) 
[icefaces-ace.jar:]
    at org.icefaces.ace.component.fileentry.FileEntryPhaseListener$1.visit(FileEntryPhaseListener.java:95) [icefaces-ace.jar:]
    at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183) [javax.faces.jar:2.1.4-FCS]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1612) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIForm.visitTree(UIForm.java:371) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1623) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.icefaces.ace.component.fileentry.FileEntryPhaseListener.beforePhase(FileEntryPhaseListener.java:100) [icefaces-ace.jar:]
    at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:228) [javax.faces.jar:2.1.4-FCS]
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:99) [javax.faces.jar:2.1.4-FCS]
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) [javax.faces.jar:2.1.4-FCS]
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) [jboss-seam.jar:2.3.0.Final]
    at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) [jboss-seam.jar:2.3.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
    at java.lang.Thread.run(Thread.java:722) [rt.jar:1.7.0_06]

至少这是值得关注的.如果我使用fileEntryListener之类的

fileEntryListener="#{uploadBean.fileUploadListener}"

抛出上面的异常,如果我使用:

fileEntryListener="#{uploadBean.fileUploadListener()}"

它抱怨该方法需要参数,如果我使用它,如:

fileEntryListener="#{uploadBean.fileUploadListener(null)}"

没有抛出异常,但由于事件为null,没有文件到达我的UploadBean.闻起来像一些图书馆问题,但至少还有别的东西要看.

上传bean

这里没有太多发生,它只是:

@Stateful
@Name("uploadBean")
@Scope(ScopeType.SESSION)
@JndiName(value = "java:app/myApp.jar/UploadBean")
public class UploadBean implements IUploadBean
{
public void fileUploadListener(FileEntryEvent event)
{
    System.out.println("listener called!");
}   
 }

监听器也在bean的接口中声明.

最佳答案 首先是一些技术背景信息:直到即将推出的JSF 2.2,JSF本身不支持multipart / form-data请求.因此,提供文件上载组件的组件库必须提供自定义过滤器本身.这应该正确解析multipart / form-data请求,并将所有必要的常规数据存储在HTTP请求参数映射中,并将上载的文件存储为请求属性.这样,JSF可以通常的方式继续使用request.getParameter()获取常规数据,组件库本身可以将上传的文件作为请求属性获取.

如果是Seam的< s:fileUpload>,则需要org.jboss.seam.web.MultipartFilter来执行multipart / form-data解析作业.我从未使用过Seam(也不是ICEfaces),但Google告诉我你在webapp的web.xml中基本上需要这个

<filter>
    <filter-name>Seam Multipart Filter</filter-name>
    <filter-class>org.jboss.seam.web.MultipartFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>Seam Multipart Filter</filter-name>
    <url-pattern>*.seam</url-pattern>
</filter-mapping>

或者这在Seam components.xml中:

<web:multipart-filter url-pattern="*.seam" />

ICEfaces组件必须配置类似的Filter. ICEfaces 3.x文档缺乏(或者我的Google / icefaces.com搜索技能不好),所以我不能详细说明这一点.

重要的是要记住,HTTP请求只能被解析一次(客户端只发送一次,而不是多次),因此你不能在同一个请求上同时使用这两个multipart / form-data解析器.在第一个之后开始的那个将获得一个空的请求主体,这个主体不能解析为任何合理的东西.因此,如果您正在使用使用后一个过滤器的组件,那么您将无法获得模型中的任何内容.确保您没有偶然或通过实验配置两者.

点赞