将Flash文件上载与JSF集成

我已经看到我们可以通过flash文件上传来上传多个文件。 像SWFUpload或YUI Uploader 。 是否可以将这些上传组件与JSF集成?

我想要的是一次选择多个文件。 Primefaces文件上传器具有此function,但在IE7中不起作用,因为IE7没有任何HTML5支持。

我需要创建一个包含各种字段的表单,如下拉菜单,文本输入等,还需要添加文件上传器以选择多个文件。 当点击JSF提交按钮时,表格将被validation,之后将继续。

我已经创建了一个用于上传多个文件的页面,但该页面使用多个输入文件组件来存储多个文件。

任何参考对我都非常有帮助。 我找到了另一个SO线程 ,其中发布的解决方案使用JSP。 我无法理解如何使用它来满足我的要求。

更新

我创建了以下托管bean:

import com.mhis.massupload.ucm.Service; import java.util.List; import java.util.UUID; import java.util.logging.Logger; import javax.faces.context.FacesContext; import org.apache.commons.fileupload.FileItem; public class UploadBean { private Logger log = Logger.getLogger(getClass().getName()); private Service service; private String key; public UploadBean() { super(); log.info("JYM"); init(); } private void init() { key = UUID.randomUUID().toString(); } public String upload() { System.out.println("Action Invoked."); List fileFields = (List)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(key); System.out.println(fileFields); return ""; } public void setKey(String key) { this.key = key; } public String getKey() { return key; } } 

Servlet是:

 import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class UploadServlet extends HttpServlet { @SuppressWarnings("compatibility:-3560436533054762606") private static final long serialVersionUID = 4122845079663279030L; public void init(ServletConfig config) throws ServletException { super.init(config); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("UploadServlet invoked."); List fileFields = new ArrayList(); try { List items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request); for (FileItem item : items) { if (!item.isFormField()) { fileFields.add(item); System.out.println(item.getName()); } } } catch (Exception e) { throw new ServletException(e); } String key = request.getParameter("key"); request.getSession().setAttribute(key, fileFields); } } 

jspx页面:

             $(document).ready(function() { $('#uploadify').uploadify({ 'swf': 'uploadify/uploadify.swf', 'uploader': '${pageContext.request.contextPath}/uploadServlet;jsessionid=${pageContext.session.id}?key=' }); }); var upload = function() { $('#uploadify').uploadify('upload','*'); }  test           

我在这里使用Uploadify。

我有两个问题:

  • upload方法的List fileFields有时返回null ,有时显示列表。 我无法找到原因。 我试图通过FacesContext.getCurrentInstance().getExternalContext().getSession(false)action方法中获取HttpSession ,然后在其上调用getAttribute() ,它也总是返回null

  • 如果我设置’auto’:false,那就是调用upload();后文件上传将启动upload(); 方法并将修改为: 然后我得到exception,即:

     org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. EOF after reading only: '2392369' of: '11626364' promised bytes, out of which at least: '0' were already buffered at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:367) at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126) at com.edfx.massupload.servlet.UploadServlet.doPost(UploadServlet.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227) at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125) at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300) at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26) at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56) at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:119) at java.security.AccessController.doPrivileged(Native Method) at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315) at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:442) at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:103) at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:171) at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:71) at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56) at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:139) at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56) at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27) at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56) at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3715) at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681) at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321) at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120) at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277) at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183) at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454) at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209) at weblogic.work.ExecuteThread.run(ExecuteThread.java:178) 

并且在这种情况下, action方法在servlet执行之前执行。

我该如何解决这两个问题?

PS

我需要修改uploadify.js来设置swf文件的正确路径,并更改取消按钮的css。 我已将uploadify的整个目录放在Web-Content中。

你需要一个servlet。 我已经回答了一个上传问题和Servlet问题,之前应提供足够的线索: Uploadify插件不会调用Java Servlet 。 SWFUpload和YUI Uploader的概念并没有那么不同。 请注意,您可以将纯HTML放在JSF页面中而不会出现问题。

您的主要问题是启用JSF支持bean和HTTP Servlet以相互交换数据。 为此,应使用HTTP会话。 首先让JSF bean在初始请求时生成一个唯一的密钥,用作会话属性名称:

 key = UUID.randomUUID().toString(); 

然后,在您告诉Uploadify / SWFUpload / etc使用的上传URL中,您需要包含jsessionid URL片段(以便servlet将使用相同的HTTP会话)和key作为URL查询字符串参数(以便servlet将使用此密钥存储有关文件上载的相关状态)。 假设您需要将其指定为JS对象键:

 url: '${pageContext.request.contextPath}/uploadServlet;jsessionid=${pageContext.session.id}?key=' 

现在,servlet将在同一个HTTP会话中调用(即request.getSession()将与JSF中的ExternalContext#getSession()ExternalContext#getSession()的属性完全相同。 所以,在doPost()只需:

 String key = request.getParameter("key"); request.getSession().setAttribute(key, someStateAboutTheUpload); 

最后,当JSF即将处理表单提交时,只需通过键获取所需数据(如果是请求范围的bean,则通过存储后续请求) ):

 SomeState someState = (SomeState) externalContext.getSessionMap().get(key); 

唯一键对于function不是必需的,它甚至可以是静态键,但是基于每个视图生成的键确保当最终用户在多个浏览器选项卡/窗口中打开相同视图时数据不会发生冲突同一个会议。

这是我所做的解决方案,BalusC帮助我开发了很多。

平台和框架

  • Uploadify v3.2
  • JSF 1.2
  • jQuery 1.8.3
  • WebLogic 10.3.5.0
  • Apache Commons Fileupload 1.2.2

多部分请求的问题

JSF 1.2无法处理多部分请求。 因此,如果包含enctype="multipart/form-data"作为属性,则命令组件的action方法(如将不会触发。 解决方案是创建一个Filter,它将与Faces Servlet一起工作并显式处理多部分请求。 这是filter:

 package com.mhis.massupload.filter; import java.io.IOException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class MultipartFilter implements Filter { private FilterConfig filterConfig = null; public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void destroy() { filterConfig = null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest)) { chain.doFilter(request, response); return; } HttpServletRequest httpRequest = (HttpServletRequest)request; boolean isMultipartContent = ServletFileUpload.isMultipartContent(httpRequest); if (!isMultipartContent) { chain.doFilter(request, response); return; } try { DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); upload.setSizeMax(-1); List items = upload.parseRequest(httpRequest); final Map parameterMap = new HashMap(); for (FileItem item : items) { if (item.isFormField()) { processFormField(item, parameterMap); } } chain.doFilter(new HttpServletRequestWrapper(httpRequest) { public Map getParameterMap() { return parameterMap; } public String[] getParameterValues(String name) { return (String[])parameterMap.get(name); } public String getParameter(String name) { String[] params = getParameterValues(name); if (params == null) { return null; } return params[0]; } public Enumeration getParameterNames() { return Collections.enumeration(parameterMap.keySet()); } }, response); } catch (Exception ex) { ServletException servletException = new ServletException(); servletException.initCause(ex); throw servletException; } } private void processFormField(FileItem formField, Map parameterMap) { String name = formField.getFieldName(); String value = formField.getString(); String[] values = parameterMap.get(name); if (values == null) { parameterMap.put(name, new String[] { value }); } else { int length = values.length; String[] newValues = new String[length + 1]; System.arraycopy(values, 0, newValues, 0, length); newValues[length] = value; parameterMap.put(name, newValues); } } } 

web.xml中此filter的配置是:

  MultipartFilter com.mhis.massupload.filter.MultipartFilter   MultipartFilter Faces Servlet  

Javasctipt for Uploadify

 $('#uploadify').uploadify({ 'auto': false, 'buttonText' : 'Browse', 'fileSizeLimit': 0, 'swf': 'uploadify/uploadify.swf', 'uploader': '${pageContext.request.contextPath}/uploadservlet?key=', 'onQueueComplete' : function(queueData) { $('.checkIn').click(); } }); 

在我的要求中,我需要在单击表单的提交按钮时上传所有文件,而不是在文件添加到队列中时。 这就是为什么我设置'auto': false 。 uploadify文件夹已放在我项目的Web内容中,因此该插件无法找到uploadify.swf文件和取消按钮的图像。 我必须修改jquery.uploadify.js的第99行,我将其更改为swf: 'uploadify/uploadify.swf'以及uploadify.css的第74行,我将其更改为:

 .uploadify-queue-item .cancel a { background: url('../uploadify/uploadify-cancel.png') 0 0 no-repeat; float: right; height: 16px; text-indent: -9999px; width: 16px; } 

background设置为url('../img/uploadify-cancel.png') 0 0 no-repeat; ,但我没有img文件夹。

Servlet的

为了上传文件,我使用了Servlet ,即UplaodServlet ; 这个servlet的配置是:

  UploadServlet com.mhis.massupload.servlet.UploadServlet   UploadServlet /uploadservlet  

uploadservlet已被用作uploadify配置的uploader属性。 我还需要传递一个唯一的密钥作为Servlet请求参数。 Servlet的代码是:

 package com.mhis.massupload.servlet; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class UploadServlet extends HttpServlet { @SuppressWarnings("compatibility:-6472602315203858426") private static final long serialVersionUID = -3714619333861571457L; private transient Logger log = Logger.getLogger(getClass().getName()); @Override public void init(ServletConfig config) throws ServletException { super.init(config); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { boolean isMultipartContent = ServletFileUpload.isMultipartContent(request); if (!isMultipartContent) { return; } FileItem fileField = null; try { DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); upload.setSizeMax(-1); List items = upload.parseRequest(request); final Map parameterMap = new HashMap(); for (FileItem item : items) { if (!item.isFormField()) { fileField = item; } } } catch (Exception ex) { log.severe(ex.getMessage()); } if (fileField == null) { return; } String key = request.getParameter("key"); List fileFields = (List)getServletContext().getAttribute(key); if (fileFields == null) { fileFields = new ArrayList(); getServletContext().setAttribute(key, fileFields); } fileFields.add(fileField); } } 

我无法使用Session来提供有关上传文件的信息,所以我使用了ServletContext 。 有关更多信息,请参阅此处

JSF页面和上传按钮

由于我的需要是仅在validation后提交表单时上传文件,所以我在uploadify的配置中设置了'auto': false 。 但这给我带来了麻烦,我在原来的问题中发布了这个问题。 为了解决这个问题,我已经声明了三个input[type=button] 。 其中两个是普通的HTML按钮,最后一个是 。 我已将此的可见性设置为false,并使用了一个虚拟按钮来启动文件上载。 当上传完成后,我已经以编程方式生成了click “`” . Also I have shown a dummy button which don't have any click event associated with it; this the fail safe if, someone clicks on the Upload button twice during the upload is taking place then the the aforementioned click event fire will work unexpectedly. That why I am showing and hiding the buttons. Here is the completed . Also I have shown a dummy button which don't have any click event associated with it; this the fail safe if, someone clicks on the Upload button twice during the upload is taking place then the the aforementioned click event fire will work unexpectedly. That why I am showing and hiding the buttons. Here is the completed . Also I have shown a dummy button which don't have any click event associated with it; this the fail safe if, someone clicks on the Upload button twice during the upload is taking place then the the aforementioned click event fire will work unexpectedly. That why I am showing and hiding the buttons. Here is the completed .jspx` pag:

             Upload             

通过这个whay,当uplaodify完成它上传到servlet时,acution JSF被解雇了。

管理Bean

托管bean具有作用域Session ,这里是它的代码:

 package com.mhis.massupload.bean; import com.mhis.massupload.dto.DocInfo; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.faces.context.FacesContext; import javax.servlet.ServletContext; import oracle.stellent.ridc.IdcClientException; import org.apache.commons.fileupload.FileItem; import org.apache.commons.lang3.StringUtils; public class UploadBean implements Serializable { @SuppressWarnings("compatibility:-930710930183135088") private static final long serialVersionUID = -491462816764274947L; private transient Logger log = Logger.getLogger(getClass().getName()); private String key; private transient Service service; public UploadBean() throws IdcClientException { init(); } private void init() throws IdcClientException { key = UUID.randomUUID().toString(); } public String upload() { List fileFields = (List) FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().remove(key); List docInfos = new ArrayList(); if (fileFields != null) { for (FileItem fileField : fileFields) { if(StringUtils.isNotBlank(fileField.getName())) { try { System.out.println("Check in: " + fileField.getName()); } catch (Exception e) { log.log(Level.SEVERE, e.getMessage()); } } } } FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("docInfos", docInfos); return "report"; } public void setKey(String key) { this.key = key; } public String getKey() { return key; } } 

这就像魅力一样。

希望它会有所帮助。