我看到我们可以通过flash文件上传来上传多个文件。喜欢SWFUpload或 YUI Uploader .是否可以将这些上传组件与 JSF 集成?
我想要的是一次选择多个文件。 Primefaces 文件 uploader 具有此功能,但在 IE7 中不起作用,因为 IE7 不支持 HTML5。
我需要创建一个包含各种字段的表单,例如下拉菜单、文本输入等,还需要添加一个文件 uploader 来选择多个文件。当单击 JSF 提交按钮时,表单将被验证,然后将继续。
我创建了一个用于上传多个文件的页面,但该页面对多个文件使用了多个输入文件组件。
任何引用都会对我很有帮助。我找到了另一个 SO thread那里发布的解决方案使用 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<FileItem> fileFields = (List<FileItem>)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<FileItem> fileFields = new ArrayList<FileItem>();
try {
List<FileItem> 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页面:
<?xml version='1.0' encoding='utf-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<jsp:directive.page contentType="text/html;utf-8"/>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script src="js/jquery-1.8.3.min.js" type="text/javascript"></script>
<script src="uploadify/jquery.uploadify.js" type="text/javascript"></script>
<link rel="stylesheet" media="screen" href="uploadify/uploadify.css"
type="text/css"/>
<script type="text/javascript">
$(document).ready(function() {
$('#uploadify').uploadify({
'swf': 'uploadify/uploadify.swf',
'uploader': '${pageContext.request.contextPath}/uploadServlet;jsessionid=${pageContext.session.id}?key=<h:outputText value="#{uploadBean.key}" />'
});
});
var upload = function() {
$('#uploadify').uploadify('upload','*');
}
</script>
<title>test</title>
</head>
<body>
<h:form enctype="multipart/form-data">
<input id="uploadify" type="file"/>
<h:commandLink action="#{uploadBean.upload}" value="Upload" />
</h:form>
</body>
</html>
</f:view>
</jsp:root>
我在这里使用 Uploadify。
我有两个问题:
List<FileItem> fileFields
的upload
方法有时会返回null
,有时会显示列表。我找不到原因。我试图获得HttpSession
来自action
方法FacesContext.getCurrentInstance().getExternalContext().getSession(false)
然后调用getAttribute()
在它上面,那也总是在返回null
.如果我设置 'auto': false,文件上传将在调用
upload();
后启动方法并修改<h:commandLink/>
如:<h:commandLink action="#{uploadBean.upload}" value="Upload" onclick="upload();"/>
然后我得到异常,这是: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 执行之前执行。
我该如何解决这两个问题?
附言
我需要修改 uploadify.js 以设置 swf 文件的正确路径并更改取消按钮的 css。我已将 uploadify 的整个目录放在 Web-Content 中。
最佳答案
这是我做的解决方案,BalusC 对我的开发帮助很大。
平台和框架
- 上传 v3.2
- JSF 1.2
- jQuery 1.8.3
- 网络逻辑 10.3.5.0
- Apache Commons 文件上传 1.2.2
多部分请求问题
JSF 1.2 无法处理多部分请求。所以如果<h:form/>
包含 enctype="multipart/form-data"
作为属性然后是 action
命令组件的方法,如 <h:commandButton/>
不会开火。解决方案是创建一个过滤器,它将与 Faces Servlet
一起工作。并显式处理多部分请求。这是过滤器:
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<FileItem> items = upload.parseRequest(httpRequest);
final Map<String, String[]> parameterMap = new HashMap<String, String[]>();
for (FileItem item : items) {
if (item.isFormField()) {
processFormField(item, parameterMap);
}
}
chain.doFilter(new HttpServletRequestWrapper(httpRequest) {
public Map<String, String[]> 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<String> 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<String, String[]> 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>
<filter-name>MultipartFilter</filter-name>
<filter-class>com.mhis.massupload.filter.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
用于上传的 Javasctipt
$('#uploadify').uploadify({
'auto': false,
'buttonText' : 'Browse',
'fileSizeLimit': 0,
'swf': 'uploadify/uploadify.swf',
'uploader': '${pageContext.request.contextPath}/uploadservlet?key=<h:outputText value="#{uploadBean.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
, 即 UplaodServlet
;这个 servlet 的配置是:
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.mhis.massupload.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/uploadservlet</url-pattern>
</servlet-mapping>
uploadservlet
已被用作uploader
uploadify
的属性的配置。我还需要传递一个唯一键作为 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<FileItem> items = upload.parseRequest(request);
final Map<String, String[]> parameterMap = new HashMap<String, String[]>();
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<FileItem> fileFields = (List<FileItem>)getServletContext().getAttribute(key);
if (fileFields == null) {
fileFields = new ArrayList<FileItem>();
getServletContext().setAttribute(key, fileFields);
}
fileFields.add(fileField);
}
}
我无法使用 Session
放置有关上传文件的信息,所以我使用了ServletContext
反而。有关更多信息,请参阅 here .
JSF 页面和上传按钮
因为我的需求是只有在验证后提交表单时才上传文件,所以我设置了'auto': false
在 uploadify 的配置中。但这给我带来了麻烦,我已经在我原来的问题中发布了这个问题。为了解决这个问题,我声明了三个 input[type=button]
.其中两个是普通的 HTML 按钮,最后一个是 <h:commandButton/>
.我已经设置了这个 <h:commandButton/>
的可见性为 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
.jspx` 页面:
<?xml version='1.0' encoding='utf-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<jsp:directive.page contentType="text/html;charset=utf-8"/>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script src="js/jquery-1.8.3.min.js" type="text/javascript"></script>
<script src="uploadify/jquery.uploadify.js" type="text/javascript"></script>
<link rel="stylesheet" media="screen" href="uploadify/uploadify.css" type="text/css"/>
<script type="text/javascript">
$(function() {
$('#uploadify').uploadify({
'auto': false,
'buttonText' : 'Browse',
'fileSizeLimit': 0,
'swf': 'uploadify/uploadify.swf',
'uploader': '${pageContext.request.contextPath}/uploadservlet?key=<h:outputText value="#{uploadBean.key}" />',
'onQueueComplete' : function(queueData) {
$('.checkIn').click();
}
});
$('input[name=actualCheckIn]').on('click', function(event){
event.stopPropagation();
$(this).hide();
$('input[name=fakeCheckIn]').show();
$('#uploadify').uploadify('upload','*');
return false;
});
});
var upload = function() {
}
</script>
<title>Upload</title>
</head>
<body>
<h:form enctype="multipart/form-data">
<input id="uploadify" type="file"/>
<h:commandButton value="Check In" action="#{uploadBean.upload}" styleClass="checkIn" style="display: none"/>
<input type="button" value="Check In" name="actualCheckIn"/>
<input type="button" value="Check In" onclick="return false;" name="fakeCheckIn" style="display: none"/>
</h:form>
</body>
</html>
</f:view>
</jsp:root>
通过这种方式,当 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<FileItem> fileFields = (List<FileItem>) FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().remove(key);
List<DocInfo> docInfos = new ArrayList<DocInfo>();
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;
}
}
这很有效。
希望对您有所帮助。
关于java - 将 Flash 文件上传与 JSF 集成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14260583/