这一段代码是在工作之余自己练手玩的代码,因为不喜欢引入别人的js,就自己写一个jsp的页面,以后可以重用,界面上是达不到商业软件的标准了,但是功能还是实现了的。
这个异步的多文件上传初衷是为了上传图片,所以有个预览图这一栏。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<!--
这是一个实现了多文件异步上传的html页面,因为用到了FileReader,所以需要对html5的支持
相对应的浏览器有:
Firefox (Gecko) Chrome Internet Explorer* Opera* Safari
3.6 (1.9.2) 7 10 -- --
-->
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="imagetoolbar" content="no">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<link href="Resources/axurerppage.css" type="text/css"
rel="stylesheet">
<style type="text/css">
table {
border-collapse: collapse;
}
tr,td,th {
border: 1px solid #000000;
}
#verUploadTable {
position: absolute;
top: 10%;
left: 15%;
}
.verUploadTable {
width: 480px;
}
.Bar ,.Bars {
position: relative;
width: 400px;
/* 宽度 */
border: 1px solid #B1D632;
padding: 1px;
}
.Bar div,.Bars div {
display: block;
position: relative;
/* 进度条背景颜色 */
background:#0FF;
color: #333333;
height: 20px;
/* 高度 */
line-height: 20px; /* 必须和高度一致,文本才能垂直居中 */
}
.Bars div{ background:#090}
.Bar div span,.Bars div span {
position: absolute;
width: 400px;
/* 宽度 */
text-align: center;
font-weight: bold;
}
img{
width:100px;
height: 80px;
}
</style>
</head>
<body>
<form name="hiddenForm" action="" enctype="multipart/form-data" method="post">
<!-- <input type="file" id="uFile" style="display:none" οnchange="fileOnchange(this)">-->
</form>
<input type="hidden" id="uploadBasePath" value="<%=basePath%>">
<input type="button" value="+添加文件" id="btnUpload" onClick="addFile()">
<div>
<div>
</div>
<div>
<table id="fileListTable">
<tr>
<th width="100px">预览图(上传后)</th>
<th width="400px">路径</th>
<th width="250px">文本描述</th>
<th width="200px">上传进度(已传/总大小)</th>
</tr>
</table>
</div>
<div>
</div>
</div>
<input type="button" value="开始上传" οnclick="filesUpload()" />
</body>
<script type="text/javascript">
// author jacob_ye 20120924 in insigma
var index = 1;
var fileListTable = document.getElementById("fileListTable");
var hiddenForm = document.hiddenForm;
function addFile(){
var file_name = "file" + index;
var input_file = document.createElement("input");
input_file.setAttribute("type", "file");
input_file.setAttribute("size", "50");
input_file.setAttribute("name", file_name);
input_file.setAttribute("hidden", "true");
input_file.setAttribute("style","display:none ;");
input_file.setAttribute("onchange", "fileOnchange(this)");
input_file.setAttribute("accept", "image/*");//加一个文件类型的指定
hiddenForm.appendChild(input_file);
input_file.click();
index =index + 1;
}
function fileOnchange(uFile){
var fileName = uFile.name;
var tr_file = document.createElement("tr");
var td_file1 = document.createElement("td");//图预览(上传后)
var td_file2 = document.createElement("td");//文件位置
var td_file3 = document.createElement("td");//字节进度
var td_file4 = document.createElement("td");//文本描述
//创建各种Element
var td1_img_file = document.createElement("img");
var td2_span = document.createElement("span");
var td2_div_Bar = document.createElement("div");
var td2_div_2 = document.createElement("div");
var td3_span_loaded = document.createElement("span");
var td3_span_total = document.createElement("span");
var td4_textarea = document.createElement("textarea");
//给Element各种setAttribute
td1_img_file.setAttribute("id", fileName+"_Img");
td1_img_file.setAttribute("alt", "图片预览");
td1_img_file.setAttribute("src", "#");
td2_span.textContent = uFile.value;
td2_div_2.setAttribute("id", fileName+"_path");
td2_div_Bar.setAttribute("class", "Bar");
td3_span_loaded.setAttribute("id", fileName +"_byteloaded");
td3_span_total.setAttribute("id", fileName + "_bytetotal");
td3_span_total.textContent = uFile.files[0].size;
td3_span_loaded.textContent = "0";
td4_textarea.setAttribute("id", fileName+"_alt");
td4_textarea.setAttribute("rows", "3");
td4_textarea.setAttribute("cols", "35");
//单元格挂节点
td_file1.appendChild(td1_img_file);
td2_div_2.appendChild(td2_span);
td2_div_Bar.appendChild(td2_div_2);
td_file2.appendChild(td2_div_Bar);
td_file3.style.width= "200px;";
td_file3.appendChild(td3_span_loaded);
td_file3.insertAdjacentText("beforeEnd","/");
td_file3.appendChild(td3_span_total);
td_file4.appendChild(td4_textarea);
tr_file.appendChild(td_file1);
tr_file.appendChild(td_file2);
tr_file.appendChild(td_file4);
tr_file.appendChild(td_file3);
fileListTable.appendChild(tr_file);
}
function filesUpload(){
//getElementsByTagName确保files是[object NodeList]
var input_files = hiddenForm.getElementsByTagName("input");
var length = input_files.length;
//var afile = input_files[0].files[0];
//alert("go here 3");
if(length > 0){
for(var i=0;i<length;i++){
var file = input_files[i].files[0];
one_file_upload(file,input_files[i].name,input_files[i].value);
}
}else{
alert("please choose a file.");
}
}
function one_file_upload(file,fileName,filePath){
// try sending
// FileReader是HTML5的东东,所以需要HTML5的支持
var reader = new FileReader();
var fType = null;
//保存只需要读取一次的元素
var lodedByteSpan = document.getElementById(fileName+"_byteloaded");
var td_file = document.getElementById(fileName+"_path");
fType = filePath.substring(filePath.lastIndexOf("."), filePath.length);
var byteTotal = file.size;
// 这个事件在读取开始时触发
reader.onloadstart = function() {
console.log("onloadstart");
document.getElementById(fileName+"_bytetotal").textContent = byteTotal;
} ;
// 这个事件在读取进行中定时触发
reader.onprogress = function(p) {
console.log("onprogress");
lodedByteSpan.textContent = p.loaded;
processRenderer(p.loaded, byteTotal,td_file);
} ;
// 这个事件在读取成功结束后触发
reader.onload = function() {
console.log("load complete");
} ;
reader.onloadend = function() {
// 这个事件在读取结束后,无论成功或者失败都会触发
if (reader.error) {
console.log(reader.error);
} else {
document.getElementById(fileName+"_bytetotal").textContent = file.size;
// 构造 XMLHttpRequest 对象,发送文件 Binary 数据
var xhr = getXmlHttp();
var basePath = document.getElementById("uploadBasePath").value;
var imgAlt = document.getElementById(fileName+"_alt").value;
xhr.open(/* method */ "POST",
/* target url */ "servlet/ImageServlet?fType="+fType+"&flag=imgUpload&uploadBasePath="+basePath+"&imgAlt="+imgAlt
/*, async, default to true */);
xhr.overrideMimeType("application/octet-stream");
xhr.sendAsBinary(reader.result);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log("upload complete");
console.log("response: " + xhr.responseText);
var responseText = xhr.responseText;
if("false" == responseText){
alert("上传错误");
}else{
//alert(responseText);//从pop框可以看到最后一个file路径返回的responseText返回了多次,为什么?
document.getElementById(fileName+"_Img").src = responseText;
}
}
}
};
}
};
//try{
//readAsBinaryString的好处是能够一次把一个完整的文件发送回去,缺点是处理大文件时,因为文件都存在浏览器内存中,
//所以会导致大文件下,页面崩溃。所以此方法用来异步提交小文件是可以的。
//QQ邮箱的超大附件做的异步提交,是用到了浏览器插件的支持。
reader.readAsBinaryString(file);
//}catch (err){
//alert( err.description );
//}
}
function getXmlHttp(){
var xmlHttp = null;
if (window.XMLHttpRequest) {
//针对FirFox,Mozilla,Opera,Safari,IE7,IE8
xmlHttp = new XMLHttpRequest();
if (xmlHttp.overrideMimeType) {
//针对Mozilla不同版本差别
xmlHttp.overrideMimeType("text/xml");
}
} else if (window.ActiveXObject) {
var activexml = [ "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" ];
for ( var i = 0; i < activexml.length; i++) {
try {
//取出一个空间进行创建,如果创建成功,则终止
//如果创建失败,回抛出异常,然后继续循环,继续创建
xmlHttp = new ActiveXObject(activexml[i]);
break;
} catch (e) {
}
}
}
return xmlHttp;
}
function processRenderer(byteLoaded, byteTotal,td_file){
var percent = byteLoaded / byteTotal;
td_file.style.width = parseInt(percent * 100) +"%";
//alert(parseInt(percent * 100) +"%");
}
//参考网页 http://royaltutorials.com/object-has-no-method-sendasbinary/
//大概意思是,chrome浏览器下面的XMLHttpRequest没有sendAsBinary,所以就自己给XMLHttpRequest原型定义一个这样的属性,并且这个属性是一个方法
if(!XMLHttpRequest.prototype.sendAsBinary){//如果XMLHttpRequest没有sendAsBinary
XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
function byteValue(x) {
return x.charCodeAt(0) & 0xff;
}
var ords = Array.prototype.map.call(datastr, byteValue);
var ui8a = new Uint8Array(ords);
this.send(ui8a.buffer);
};
}
</script>
</html>
文件存储的代码写得不好,就贴一部分吧:
/**
* 图片上传
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void imgUpload(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String fileType = request.getParameter("fType");
BufferedInputStream fin = new BufferedInputStream(request.getInputStream());
//生成随机文件名
String fileName = uuid.generate() + fileType;
//path是本地路径
String path = getURI() + "/uploadFolder/" + fileName;
//uploadBasePath是从前台页面拿到的网页路径
String uploadBasePath = request.getParameter("uploadBasePath");
String imgAlt = request.getParameter("imgAlt");
if(null != uploadBasePath && imgAlt != null){
//url拼接出来以后是http://xxx.xxx.xxx/smdtx/uploadFolder/xxxx.jpg
String url = uploadBasePath + "uploadFolder/" + fileName;
PrintWriter out = response.getWriter();
if(saveFile(fin,path)){//成功了就返回url给jsp页面
Image img = new Image();
img.setUrl(url);
img.setAlt(imgAlt);
try{
imgDao.add(img);
out.write(url);
out.flush();
}catch(Exception e){
mLog.error(" method imgUpload() catch exception by " + e.getMessage());
e.printStackTrace();
}finally{
if(out != null){
out.close();
}
}
}else{
try{
out.write("false");
out.flush();
}catch(Exception e){
mLog.error(" method imgUpload() catch exception by " + e.getMessage());
e.printStackTrace();
}finally{
if(out != null){
out.close();
}
}
}
}
}
/**
* 保存文件到本地
* @param in 输入流
* @param path 保存地址
* @return boolean 成功标识
* @throws IOException
*/
private boolean saveFile(InputStream in,String path) throws IOException{
File file = new File(path);
byte[] buff = new byte[1024];
int buffLength = -1;
OutputStream out = null;
boolean result = false;
try{
out = new FileOutputStream(file);
while((buffLength = in.read(buff)) != -1){
out.write(buff, 0, buffLength);
}
result = true;
}catch(Exception e){
mLog.error(" method saveFile() catch exception by " + e.getMessage());
e.printStackTrace();
}finally{
if(out != null){
out.close();
}
}
return result;
}
大概就是这个样子。自己有一个疑问,为什么最后一个file路径返回了多次?希望有经验的朋友能够留言解惑。