html5的formData对象可以向正常的form表单一样通过ajax请求发送,包括上传文件并且可以一次性上传多个文件。并且可以根据监听事件,监视上传进度,终止,结束等等。下面的实例代码使用到了bootstrap,跑的话先搭建好bootstrap环境。并且要支持html5的浏览器。
jsp页面代码
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<link rel="stylesheet" href="${pageContext.request.contextPath }/bootstrap.css">
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<div class="navbar-brand">
HellpPeng
</div>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="true" aria-controls="navbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="#">上传文件</a></li>
</ul>
</div>
</div>
</nav>
<div class="container center-block" style="width:60%; max-width: 600px; margin-top: 100px;">
<form id="form1" class="form-horizontal" enctype="multipart/form-data" method="POST">
<div class="form-group">
<label class=" col-sm-3" for="fileName">文件名称</label>
<input class="form-control " type="text" id="fileName" name="fileName" style="max-width: 250px;" disabled="disabled">
</div>
<div class="form-group">
<label class="col-sm-3">文件类型</label>
<input type="text" class="form-control" id="fileType" name="fileType" style="max-width: 200px;" disabled="disabled">
</div>
<div class="form-group">
<label class="col-sm-4" >文件大小</label>
<input id="fileSize" type="text" class="form-control" name="fileSize" style="max-width: 200px;" disabled="disabled">
</div>
<div class="form-group">
<label class="col-sm-4 " for="upFile">选择文件</label>
<div>
<input style="opacity: 0; position: absolute;" type="file" id="upFile" name="file" οnchange="fileSelect()" multiple="multiple">
<label class="label label-danger" style="font-size: 1em">点击上传图片</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="name">上传者</label>
<input class="form-control " type="text" name="name" id="name">
</div>
<div class="form-group">
<label id="progress" class=col-sm-3">上传进度</label>
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: 0%;"></div>
</div>
</div>
<div class="form-group text-center">
<input type="button" class="btn-lg btn btn-primary col-sm-3" style="margin: 10px;" οnclick="uploadFile()" value="提交">
<input type="button" class="btn-lg btn btn-warning col-sm-3" style="margin: 10px;" οnclick="cancleUploadFile()" value="取消">
</div>
</form>
</div>
<script src="${pageContext.request.contextPath }/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath }/bootstrap.min.js" type="text/javascript"></script>
</body>
<script type="text/javascript">
var ajax = new XMLHttpRequest();
//文件上传
function uploadFile(){
//通过form1表单构建FormData对象
var fd = new FormData(document.getElementById("form1"));
//添加参数
// fd.append("dd",$("#fileName").val())
// fd.append("fileName",$("#upFile")[0].files[0]);
//添加上传事件
ajax.upload.addEventListener("progress",uploadProgress,false);
ajax.addEventListener("load",uploadComplete,false);
ajax.addEventListener("error",uploadFailed,false);
ajax.addEventListener("abort",uploadCanaeled,false);
//请求地址
ajax.open("POST","http://localhost:8080/st/demo7.action");
ajax.send(fd);
}
//上传进度evt.loaded已读取字节 evt.total总字节大小
function uploadProgress(evt){
if(evt.lengthComputable){
var percentComplete = Math.round(evt.loaded*100/evt.total);
$("#progress").text("上传进度"+percentComplete+"%");
$(".progress-bar.progress-bar-success").css("width",percentComplete+"%");
}
}
//取消上传
function cancleUploadFile(){
alert("取消");
ajax.abort();
}
//上传成功响应
function uploadComplete(evt){
alert(evt.target.responseText);
}
//上传失败
function uploadFailed(evt){
alert("上传失败!");
alert(evt.target.responseText);
}
//取消上传
function uploadCanaeled(evt){
alert("取消上传!");
alert(evt.target.responseText);
}
//选择文件后显示在input框
function fileSelect(){
var file = $("#upFile")[0].files[0];
if(file){
var fileSize = 0;
if(file.size > 1024*1024)
fileSize = (Math.round(file.size*100/(1024*1024)/100).toString()+"MB");
else
fileSize = (Math.round(file.size*100/1024).toString()+"KB");
$("#fileSize").val(fileSize);
$("#fileName").val(file.name);
$("#fileType").val(file.type);
//$("#image").attr("src", $("#upFile").val()) ;
}
}
</script>
</html>
服务器部分:
因为是案例就随便将工程建立在了struts2环境上面了但是使用的是fileUpload.jar包的源生写法,因为request对象经过struts2的封装,如果直接使用parseRequest()方法直接解析request对象是解析不到任何数据的。所以为了解决这个问题,我们需要将struts2对request对象的封装取消。
首先在struts2的配置文件中添加以下语句(好像struts2.3.4以前的版本需要改变继承的包):
<bean type= "org.apache.struts2.dispatcher.multipart.MultiPartRequest"
name= "myRequestParser" class= "com.ljp.struts.Demo6"
scope= "default" optional= "true " />
<constant name="struts.multipart.parser" value= "myRequestParser" />
之后在制定的java文件里面覆盖struts2的原本方法:
@Override
public void parse(HttpServletRequest request, String saveDir)throws IOException {
// TODO Auto-generated method stub
}经过这些步骤之后就可以实现服务器端的操作了
struts.xml

Demo6.java

服务器接收文件代码:
Demo7.java?
?package com.ljp.struts;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class Demo7 extends ActionSupport{
/**
* 接受html5的formdata文件上传
*/
private static final long serialVersionUID = 1L;
@Override
public String execute() throws Exception {
// 获取servelt原始的request、response、context对象
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext context = ServletActionContext.getServletContext();
System.out.println("文件上传");
//设置request字符格式
request.setCharacterEncoding("UTF-8");
//建造DisFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(context.getRealPath("/WEB-INF/temp")));
//获取文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//文件上传添加解析器对象
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long arg0, long arg1, int arg2) {
// TODO Auto-generated method stub
System.out.println("文件大小为:"+arg1+" 当前已上传"+arg0);
}
});
//设置解析器格式
upload.setHeaderEncoding("UTF-8");
//如果表单不是以multipart/form-data方式提交则return
if(!upload.isMultipartContent(request)){
return NONE;
}
try{
//解析request对象(通过struts2获取的对象经过封装如果直接解析会解析不出来)
List<FileItem> list = upload.parseRequest(request);
//拿到request中的表单数据
for(FileItem item:list){
//正常表单数据获取
if(item.isFormField()){
System.out.println(item.getString("UTF-8"));
}else{
String filename = item.getName();
System.out.println(filename);
//获取上传文件的流
InputStream in = item.getInputStream();
//接受上传文件并保存
FileOutputStream out = new FileOutputStream(context.getRealPath("/WEB-INF/temp")+"\\"+filename);
byte buffer[] = new byte[1024];
int len = 0;
while((len=in.read(buffer))>0){
out.write(buffer, 0, len);
}
//对象的清理
in.close();
out.close();
item.delete();
System.out.println("完成");
}
}
//向页面返回成功消息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
response.getWriter().write("成功");
}catch(Exception e){
//向页面返回失败消息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
response.getWriter().write("失败");
response.getWriter().flush();
e.printStackTrace();
}
return NONE;
}
}
效果图:

本案例可以多个文件同时提交(选择文件是一并选择,并不是每次选择一个)?由于上传多个文件也是在同一个ajax请求中提交的所以上传成功的话所有文件都上传成功失败的话就会全部失败,进度条显示的是整体数据上传的进度,如果想分开显示每个文件的上传进度的话,只要分成多个ajax请求再多加几个progess就可以了。当然应该也有其他的实现方法,下去可以在研究研究。
关于更多的FormData以及File对象请参看W3C文档。
由于本案例只是练手的随意写的,并没有经过严格的审查,如果发现错误请一定指正,以免将错误传递给更多的人,谢谢!
文档参考:http://www.open-open.com/lib/view/open1388925158468.html
jsp页面代码
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<link rel="stylesheet" href="${pageContext.request.contextPath }/bootstrap.css">
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<div class="navbar-brand">
HellpPeng
</div>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="true" aria-controls="navbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="#">上传文件</a></li>
</ul>
</div>
</div>
</nav>
<div class="container center-block" style="width:60%; max-width: 600px; margin-top: 100px;">
<form id="form1" class="form-horizontal" enctype="multipart/form-data" method="POST">
<div class="form-group">
<label class=" col-sm-3" for="fileName">文件名称</label>
<input class="form-control " type="text" id="fileName" name="fileName" style="max-width: 250px;" disabled="disabled">
</div>
<div class="form-group">
<label class="col-sm-3">文件类型</label>
<input type="text" class="form-control" id="fileType" name="fileType" style="max-width: 200px;" disabled="disabled">
</div>
<div class="form-group">
<label class="col-sm-4" >文件大小</label>
<input id="fileSize" type="text" class="form-control" name="fileSize" style="max-width: 200px;" disabled="disabled">
</div>
<div class="form-group">
<label class="col-sm-4 " for="upFile">选择文件</label>
<div>
<input style="opacity: 0; position: absolute;" type="file" id="upFile" name="file" οnchange="fileSelect()" multiple="multiple">
<label class="label label-danger" style="font-size: 1em">点击上传图片</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3" for="name">上传者</label>
<input class="form-control " type="text" name="name" id="name">
</div>
<div class="form-group">
<label id="progress" class=col-sm-3">上传进度</label>
<div class="progress">
<div class="progress-bar progress-bar-success" style="width: 0%;"></div>
</div>
</div>
<div class="form-group text-center">
<input type="button" class="btn-lg btn btn-primary col-sm-3" style="margin: 10px;" οnclick="uploadFile()" value="提交">
<input type="button" class="btn-lg btn btn-warning col-sm-3" style="margin: 10px;" οnclick="cancleUploadFile()" value="取消">
</div>
</form>
</div>
<script src="${pageContext.request.contextPath }/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath }/bootstrap.min.js" type="text/javascript"></script>
</body>
<script type="text/javascript">
var ajax = new XMLHttpRequest();
//文件上传
function uploadFile(){
//通过form1表单构建FormData对象
var fd = new FormData(document.getElementById("form1"));
//添加参数
// fd.append("dd",$("#fileName").val())
// fd.append("fileName",$("#upFile")[0].files[0]);
//添加上传事件
ajax.upload.addEventListener("progress",uploadProgress,false);
ajax.addEventListener("load",uploadComplete,false);
ajax.addEventListener("error",uploadFailed,false);
ajax.addEventListener("abort",uploadCanaeled,false);
//请求地址
ajax.open("POST","http://localhost:8080/st/demo7.action");
ajax.send(fd);
}
//上传进度evt.loaded已读取字节 evt.total总字节大小
function uploadProgress(evt){
if(evt.lengthComputable){
var percentComplete = Math.round(evt.loaded*100/evt.total);
$("#progress").text("上传进度"+percentComplete+"%");
$(".progress-bar.progress-bar-success").css("width",percentComplete+"%");
}
}
//取消上传
function cancleUploadFile(){
alert("取消");
ajax.abort();
}
//上传成功响应
function uploadComplete(evt){
alert(evt.target.responseText);
}
//上传失败
function uploadFailed(evt){
alert("上传失败!");
alert(evt.target.responseText);
}
//取消上传
function uploadCanaeled(evt){
alert("取消上传!");
alert(evt.target.responseText);
}
//选择文件后显示在input框
function fileSelect(){
var file = $("#upFile")[0].files[0];
if(file){
var fileSize = 0;
if(file.size > 1024*1024)
fileSize = (Math.round(file.size*100/(1024*1024)/100).toString()+"MB");
else
fileSize = (Math.round(file.size*100/1024).toString()+"KB");
$("#fileSize").val(fileSize);
$("#fileName").val(file.name);
$("#fileType").val(file.type);
//$("#image").attr("src", $("#upFile").val()) ;
}
}
</script>
</html>
服务器部分:
因为是案例就随便将工程建立在了struts2环境上面了但是使用的是fileUpload.jar包的源生写法,因为request对象经过struts2的封装,如果直接使用parseRequest()方法直接解析request对象是解析不到任何数据的。所以为了解决这个问题,我们需要将struts2对request对象的封装取消。
首先在struts2的配置文件中添加以下语句(好像struts2.3.4以前的版本需要改变继承的包):
<bean type= "org.apache.struts2.dispatcher.multipart.MultiPartRequest"
name= "myRequestParser" class= "com.ljp.struts.Demo6"
scope= "default" optional= "true " />
<constant name="struts.multipart.parser" value= "myRequestParser" />
之后在制定的java文件里面覆盖struts2的原本方法:
@Override
public void parse(HttpServletRequest request, String saveDir)throws IOException {
// TODO Auto-generated method stub
}经过这些步骤之后就可以实现服务器端的操作了
struts.xml
Demo6.java
服务器接收文件代码:
Demo7.java?
?package com.ljp.struts;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class Demo7 extends ActionSupport{
/**
* 接受html5的formdata文件上传
*/
private static final long serialVersionUID = 1L;
@Override
public String execute() throws Exception {
// 获取servelt原始的request、response、context对象
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext context = ServletActionContext.getServletContext();
System.out.println("文件上传");
//设置request字符格式
request.setCharacterEncoding("UTF-8");
//建造DisFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(context.getRealPath("/WEB-INF/temp")));
//获取文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//文件上传添加解析器对象
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long arg0, long arg1, int arg2) {
// TODO Auto-generated method stub
System.out.println("文件大小为:"+arg1+" 当前已上传"+arg0);
}
});
//设置解析器格式
upload.setHeaderEncoding("UTF-8");
//如果表单不是以multipart/form-data方式提交则return
if(!upload.isMultipartContent(request)){
return NONE;
}
try{
//解析request对象(通过struts2获取的对象经过封装如果直接解析会解析不出来)
List<FileItem> list = upload.parseRequest(request);
//拿到request中的表单数据
for(FileItem item:list){
//正常表单数据获取
if(item.isFormField()){
System.out.println(item.getString("UTF-8"));
}else{
String filename = item.getName();
System.out.println(filename);
//获取上传文件的流
InputStream in = item.getInputStream();
//接受上传文件并保存
FileOutputStream out = new FileOutputStream(context.getRealPath("/WEB-INF/temp")+"\\"+filename);
byte buffer[] = new byte[1024];
int len = 0;
while((len=in.read(buffer))>0){
out.write(buffer, 0, len);
}
//对象的清理
in.close();
out.close();
item.delete();
System.out.println("完成");
}
}
//向页面返回成功消息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
response.getWriter().write("成功");
}catch(Exception e){
//向页面返回失败消息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
response.getWriter().write("失败");
response.getWriter().flush();
e.printStackTrace();
}
return NONE;
}
}
效果图:
本案例可以多个文件同时提交(选择文件是一并选择,并不是每次选择一个)?由于上传多个文件也是在同一个ajax请求中提交的所以上传成功的话所有文件都上传成功失败的话就会全部失败,进度条显示的是整体数据上传的进度,如果想分开显示每个文件的上传进度的话,只要分成多个ajax请求再多加几个progess就可以了。当然应该也有其他的实现方法,下去可以在研究研究。
关于更多的FormData以及File对象请参看W3C文档。
由于本案例只是练手的随意写的,并没有经过严格的审查,如果发现错误请一定指正,以免将错误传递给更多的人,谢谢!
文档参考:http://www.open-open.com/lib/view/open1388925158468.html