第一次寫博客,也不知怎麼去寫,這次也算是一個開頭吧。之前也一直關注別人寫的博客,他們寫的挺好,我從中也收穫不少。
首先,對於編程,我並非科班出身。我本科學的是統計學,其實更確切的說是學數學的,因爲我們大部分的課程是被數學佔滿了。可能有些人會奇怪,統計學幹嘛學那麼數學。因爲我學的是數理統計,學校很深厚的數學功底,也因爲這樣我纔會轉行做軟件的。這次我分享的是用js實現文件上傳的功能,首先說明一下,此技術並非都是我原創,我是阿發你好課程的基礎上改編的,他原創的沒有圖片預覽的功能,我在他的基礎上增加圖片預覽的功能。順便給發哥打一下廣告,他的課程真心不錯,我在他那裏學到很多原理上的東西,這是他的官方網址http://afanihao.cn/我只負責推薦,學不學看你自己。
好了廢話不多說了,直接上代碼吧,所有思路代碼都有註釋。
一、前端HTML部分
<div class='main'>
<input type='file' class='filebutton' style='display:none' onchange='fileSelected()' /> <br>
<button class="upload" onclick='openFileDialog()' > 選擇文件上傳 </button>
<div class="img">
</div>
</div>
二、js部分
//點擊普通按鈕,打開文件選擇框
function openFileDialog()
{
$(".filebutton").click();
}
//選擇一個文件時onchange時間被觸發
function fileSelected()
{
var fbutton = $(".filebutton")[0];//dom元素
//讀取文件
var reader = new FileReader();
reader.onload = function(e)
{
var dataURL = e.target.result;//'data:image/jpeg;base64,/9j/4AAQSk...(base64編碼)...'
//alert(data);
var htmlImg = "<img src = '" + dataURL + "'/>";
$(".img").html(htmlImg);
}
var file = fbutton.files[0];
reader.readAsDataURL(file);
startFileUpload(file);
}
//開始上傳
function startFileUpload(file)
{
var uploadURL = "FileUploadServer";
//手工構造一個form對象
var formData = new FormData();
formData.append("file" , file);// 'file' 爲HTTP Post裏的字段名, file 對瀏覽器裏的File對象
//手工構造一個請求對象,用這個對象發送表單數據
//設置 progress, load, error, abort 4個事件處理器
var request = new XMLHttpRequest();
request.upload.addEventListener("progress" , window.evt_upload_progress , false);
request.addEventListener("load", window.evt_upload_complete, false);
request.addEventListener("error", window.evt_upload_failed, false);
request.addEventListener("abort", window.evt_upload_cancel, false);
request.open("POST", uploadURL ); // 設置服務URL
request.send(formData); // 發送表單數據
}
window.evt_upload_progress = function(evt)
{
if(evt.lengthComputable)
{
var progress = Math.round(evt.loaded * 100 / evt.total);
console.log("上傳進度" + progress);
}
};
window.evt_upload_complete = function (evt)
{
if(evt.loaded == 0)
{
console.log ("上傳失敗!");
}
else
{
console.log ("上傳完成!");
var response = JSON.parse(evt.target.responseText);
console.log (response);
}
};
window.evt_upload_failed = function (evt)
{
console.log ("上傳出錯");
};
window.evt_upload_cancel = function (evt)
{
console.log( "上傳中止!");
};
三、後端部分,需要兩個jar包的支持,他們分別是:commons-fileupload-1.3.1.jar commons-io-2.4.jar
package my.fileUpload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.json.JSONObject;
public class FileUploadServer extends HttpServlet {
File tmpDir;//文件保存的臨時目錄
@Override
public void init() throws ServletException {
System.out.println("初始化");
File webRoot = new File(getServletContext().getRealPath("/"));
tmpDir = new File(webRoot , "upload");
if(!tmpDir.exists()) tmpDir.mkdirs();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request , response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("進入");
int error = 0;
String reason = "OK";
String data = null;
try {
data = doUpload(request , response);
} catch (Exception e) {
error = -1;
reason = e.getMessage();
// TODO Auto-generated catch block
e.printStackTrace();
}
JSONObject jreq = new JSONObject();
jreq.put("error", error);
jreq.put("reason", reason);
if(data != null) jreq.put("data", data);
response.setCharacterEncoding("utf-8");
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.write(jreq.toString(2));
}
private String doUpload(HttpServletRequest request, HttpServletResponse response) throws Exception
{
String result = null;
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart)
throw new Exception("請求編碼必須爲: multipart/form-data !");
request.setCharacterEncoding("utf-8");
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
while(iter.hasNext())
{
//表單域
FileItemStream item = iter.next();
String fieldName = item.getFieldName();
InputStream fieldStream = item.openStream();
if(item.isFormField())
{
//普通表單域直接讀取
String fieldValue = Streams.asString(fieldStream , "utf-8");
System.out.println("表單域:" + fieldName + "=" + fieldValue);
}
else
{
String realName = item.getName();//原始文件名
//文件的後綴名
String suffix = realName.substring(realName.lastIndexOf(".")+1);
System.out.println("文件名:" + realName + "....." + "後綴名:" + suffix);
//創建已個臨時文件名
String s = UUID.randomUUID().toString();
String s2 = s.substring(0,8)+s.substring(9,13)+s.substring(14,18)+s.substring(19,23)+s.substring(24);
s2 = s2.toUpperCase();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
String dateStr = sdf.format(new Date());
String fileName = dateStr +"-" + s2 + "." + suffix;
result = fileName;
System.out.println("文件名:" + fileName);
File file = new File(tmpDir , fileName);
long fileSsize = 0;//文件大小
System.out.println("===========文件開始上傳=============");
//從FieldStream讀取數據,保存到目標文件
file.getParentFile().mkdirs();
FileOutputStream fileStream = new FileOutputStream(file);
try
{
byte[] buf = new byte[1024];
while(true)
{
int n = fieldStream.read(buf);
if(n < 0) break;
if(n == 0) continue;
fileStream.write(buf, 0, n);
fileSsize += n;
}
}finally
{
fileStream.close();
fieldStream.close();
}
System.out.println("上傳完成!");
}
}
return result;
}
}
最後再說一下,代碼會很多需要改進的地方,歡迎各位同僚給出意見,謝謝!