jsp上傳多個文件
① 如何實現同時上傳多個文件
含義 ENCTYPE="multipart/form-data" 說明:
通過 http 協議上傳文件 rfc1867協議概述,jsp 應用舉例,客戶端發送內容構造
1、概述在最初的 http 協議中,沒有上傳文件方面的功能。 rfc1867 (http://www.ietf.org/rfc/rfc1867.txt) 為 http 協議添加了這個功能。客戶端的瀏覽器,如 Microsoft IE, Mozila, Opera 等,按照此規范將用戶指定的文件發送到伺服器。伺服器端的網頁程序,如 php, asp, jsp 等,可以按照此規范,解析出用戶發送來的文件。Microsoft IE, Mozila, Opera 已經支持此協議,在網頁中使用一個特殊的 form 就可以發送文件。絕大部分 http server ,包括 tomcat ,已經支持此協議,可接受發送來的文件。各種網頁程序,如 php, asp, jsp 中,對於上傳文件已經做了很好的封裝。
2、上傳文件的實例:用 servelet 實現(http server 為 tomcat 4.1.24)1. 在一個 html 網頁中,寫一個如下的form :
load multi files :
text field :
用戶可以選擇多個文件,填寫表單其它項,點擊「提交」按鈕後就開始上傳給 http://192.168.29.65/upload_file/UploadFile
這是一個 servelet 程序注意 enctype="multipart/form-data", method=post, type="file" 。根據 rfc1867, 這三個屬性是必須的。multipart/form-data 是新增的編碼類型,以提高二進制文件的傳輸效率。具體的解釋請參閱 rfc18672. 服務端 servelet 的編寫現在第三方的 http upload file 工具庫很多。Jarkata 項目本身就提供了fileupload 包http://jakarta.apache.org/commons/fileupload/ 。
文件上傳、表單項處理、效率問題基本上都考慮到了。在 Struts 中就使用了這個包,不過是用 Struts 的方式另行封裝了一次。這里我們直接使用 fileupload 包。至於Struts 中的用法,請參閱 Struts 相關文檔。這個處理文件上傳的 servelet 主要代碼如下:
public void doPost( HttpServletRequest request, HttpServletResponse response )
{
DiskFileUpload diskFileUpload = new DiskFileUpload(); // 允許文件最大長度
diskFileUpload.setSizeMax( 100*1024*1024 ); // 設置內存緩沖大小
diskFileUpload.setSizeThreshold( 4096 ); // 設置臨時目錄
diskFileUpload.setRepositoryPath( "c:/tmp" );
List fileItems = diskFileUpload.parseRequest( request );
Iterator iter = fileItems.iterator(); for( ; iter.hasNext(); )
{
FileItem fileItem = (FileItem) iter.next();
if( fileItem.isFormField() ) { // 當前是一個表單項
out.println( "form field : " + fileItem.getFieldName() + ", " + fileItem.getString() );
} else {
// 當前是一個上傳的文件
String fileName = fileItem.getName();
fileItem.write( new File("c:/uploads/"+fileName) );
}
}}
為簡略起見,異常處理,文件重命名等細節沒有寫出。3、 客戶端發送內容構造假設接受文件的網頁程序位於 http://192.168.29.65/upload_file/UploadFile.假設我們要發送一個二進制文件、一個文本框表單項、一個密碼框表單項。文件名為 E:\s ,其內容如下:(其中的XXX代表二進制數據,如 01 02 03)abbXXXccc 客戶端應該向 192.168.29.65 發送如下內容:
POST /upload_file/UploadFile HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.29.65:80
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
Content-Length: 424
Connection: Keep-Alive -----------------------------7d33a816d302b6
Content-Disposition:form-data;
name="userfile1";
filename="E:\s"Content-Type:
application/octet-stream abbXXXccc
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
name="text1" foo
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
name="password1" bar
-----------------------------7d33a816d302b6--
(上面有一個回車)此內容必須一字不差,包括最後的回車。
注意:Content-Length: 424 這里的424是紅色內容的總長度(包括最後的回車)
注意這一行:Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6
根據 rfc1867, multipart/form-data是必須的.---------------------------7d33a816d302b6 是分隔符,分隔多個文件、表單項。
其中33a816d302b6 是即時生成的一個數字,用以確保整個分隔符不會在文件或表單項的內容中出現。前面的 ---------------------------7d 是 IE 特有的標志。
Mozila 為---------------------------71用手工發送這個例子,在上述的 servlet 中檢驗通過。
使用POST發送數據
以POST方式發送數據主要是為了向伺服器發送較大量的客戶端的數據,它不受URL的長度限制。POST請求將數據以URL編碼的形式放在HTTP正文中,欄位形式為fieldname=value,用&分隔每個欄位。注意所有的欄位都被作為字元串處理。實際上我們要做的就是模擬瀏覽器POST一個表單。以下是IE發送一個登陸表單的POST請求:
POST http://127.0.0.1/login.do HTTP/1.0
Accept: image/gif, image/jpeg, image/pjpeg, */*
Accept-Language: en-us,zh-cn;q=0.5
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Content-Length: 28
\r\n
username=admin&password=1234
要在MIDP應用程序中模擬瀏覽器發送這個POST請求,首先設置HttpConnection的請求方式為POST:
hc.setRequestMethod(HttpConnection.POST);
然後構造出HTTP正文:
byte[] data = "username=admin&password=1234".getBytes();
並計算正文長度,填入Content-Type和Content-Length:
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
hc.setRequestProperty("Content-Length", String.valueOf(data.length));
然後打開OutputStream將正文寫入:
OutputStream output = hc.openOutputStream();
output.write(data);
需要注意的是,數據仍需要以URL編碼格式編碼,由於MIDP庫中沒有J2SE中與之對應的URLEncoder類,因此,需要自己動手編寫這個encode()方法,可以參考java.net.URLEncoder.java的源碼。剩下的便是讀取伺服器響應,代碼與GET一致,這里就不再詳述。
使用multipart/form-data發送文件
如果要在MIDP客戶端向伺服器上傳文件,我們就必須模擬一個POST multipart/form-data類型的請求,Content-Type必須是multipart/form-data。
以multipart/form-data編碼的POST請求格式與application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP請求頭設置一個分隔符,例如ABCD:
hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=ABCD");
然後,將每個欄位用「--分隔符」分隔,最後一個「--分隔符--」表示結束。例如,要上傳一個title欄位"Today"和一個文件C:\1.txt,HTTP正文如下:
--ABCD
Content-Disposition: form-data; name="title"
\r\n
Today
--ABCD
Content-Disposition: form-data; name="1.txt"; filename="C:\1.txt"
Content-Type: text/plain
\r\n
--ABCD--
\r\n
請注意,每一行都必須以\r\n結束,包括最後一行。如果用Sniffer程序檢測IE發送的POST請求,可以發現IE的分隔符類似於---------------------------7d4a6d158c9,這是IE產生的一個隨機數,目的是防止上傳文件中出現分隔符導致伺服器無法正確識別文件起始位置。我們可以寫一個固定的分隔符,只要足夠復雜即可。
發送文件的POST代碼如下:
String[] props = ... // 欄位名
String[] values = ... // 欄位值
byte[] file = ... // 文件內容
String BOUNDARY = "---------------------------7d4a6d158c9"; // 分隔符
StringBuffer sb = new StringBuffer();
// 發送每個欄位:
for(int i=0; i
sb = sb.append("--");
sb = sb.append(BOUNDARY);
sb = sb.append("\r\n");
sb = sb.append("Content-Disposition: form-data; name=\""+ props[i] + "\"\r\n\r\n");
sb = sb.append(URLEncoder.encode(values[i]));
sb = sb.append("\r\n");
}
// 發送文件:
sb = sb.append("--");
sb = sb.append(BOUNDARY);
sb = sb.append("\r\n");
sb = sb.append("Content-Disposition: form-data; name=\"1\"; filename=\"1.txt\"\r\n");
sb = sb.append("Content-Type: application/octet-stream\r\n\r\n");
byte[] data = sb.toString().getBytes();
byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
// 設置HTTP頭:
hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);
hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length + end_data.length));
// 輸出:
output = hc.openOutputStream();
output.write(data);
output.write(file);
output.write(end_data);
// 讀取伺服器響應:
// TODO...
② struts2 在jsp一個上傳框如何實現全選多個文件一次上傳呢
jsp代碼
<s:form action="uploadAction!uploadFilemuch.action" method="post" enctype="multipart/form-data" >
File1:<s:file name="uploadmuch" label="selectfile"></s:file>
File2:<s:file name="uploadmuch" label="selectfile"></s:file>
File3:<s:file name="uploadmuch" label="selectfile"></s:file>
<s:submit value="submit" />
</s:form>
action代碼
public class UpLoadFiled extends ActionSupport {
private File upload;
private String uploadFileName;
private File[] uploadmuch;
private String[] uploadmuchFileName;
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public File[] getUploadmuch() {
return uploadmuch;
}
public void setUploadmuch(File[] uploadmuch) {
this.uploadmuch = uploadmuch;
}
public String[] getUploadmuchFileName() {
return uploadmuchFileName;
}
public void setUploadmuchFileName(String[] uploadmuchFileName) {
this.uploadmuchFileName = uploadmuchFileName;
}
public String uploadFilemuch() throws IOException {
if (this.getUploadmuch() != null) {
for (int i = 0; i < this.getUploadmuch().length; i++) {
FileOutputStream fos = new FileOutputStream(
ServletActionContext.getRequest().getRealPath(
"\\upload")
+ "\\" + this.getUploadmuchFileName()[i]);
FileInputStream fis = new FileInputStream(this.getUploadmuch()[i]);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
}
ActionContext.getContext().put("message", "上傳成功");
Log.addLog("上傳成功");
return "message";
}
}
③ 求commons-fileupload 多文件上傳例子項目是使用jsp+jdbc。謝謝
環境:MyEclipse 6.5 + Tomcat5.5 + Jdk 1.6 並引入 commons-fileupload-1.2.jar
jsp上傳文件代碼 :
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'multiFileUpload.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<script type="text/javascript">
function addMore(){
var td=document.getElementById("moreFile");
var br=document.createElement("br");
var input=document.createElement("input");
var button=document.createElement("input");
input.type="file";
input.name="file";
button.type="button";
button.value="-";
button.onclick=function(){
td.removeChild(br);
td.removeChild(input);
td.removeChild(button);
}
td.appendChild(br);
td.appendChild(input);
td.appendChild(button);
}
</script>
</head>
<body>
<form action="upload/uploadAction.jsp" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>多文件上傳</td>
<td></td>
</tr>
<tr>
<td>文件:</td>
<td id="moreFile"><input name="file1" type="file" /><input type="button" value=" + " onclick="addMore()"/></td>
</tr>
<tr>
<td><input type="submit" value="開始上傳" /></td>
<td></td>
</tr>
</table>
</form>
</body>
</html>
jsp處理請求頁面代碼:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="org.apache.commons.fileupload.FileUpload"%>
<%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
<%@page import="java.io.File"%>
<%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%>
<%@page import="org.apache.commons.fileupload.FileItem"%>
<%@page import="java.io.FileOutputStream"%>
<%@page import="java.io.BufferedReader"%>
<%@page import="java.io.InputStreamReader"%>
<%@page import="org.apache.commons.fileupload.FileUploadException"%>
<%
//設定請求字元集,防止中文文件名亂碼
request.setCharacterEncoding("UTF-8");
//錯誤或異常提示信息
String errorMsg="";
String strFileName = "";
String path = request.getRealPath("/") + File.separator + "upload/";//上傳文件的路徑
//判斷form是否是multpart/form-data
if(FileUpload.isMultipartContent(request)){
DiskFileItemFactory factory = new DiskFileItemFactory();
// 設置上傳工廠的限制
factory.setSizeThreshold(1024 * 1024 * 20);
//new File(request.getRealPath("/")可以具體執行路徑
factory.setRepository(new File(path));
// 創建一個上傳文件的ServletFileUpload對象
ServletFileUpload upload = new ServletFileUpload(factory);
// 設置最大的上傳限制,-1表示無限制
upload.setSizeMax(1024 * 1024 * 20);
// 處理HTTP請求,items是所有的表單項
try {
List<FileItem> items = upload.parseRequest(request);
if(null==items){
errorMsg = "未上傳文件,請選擇...";
}else{
for(FileItem fi : items){
//判斷提交表單元素,是否是上傳組件(type=file)
if(fi.isFormField()){
errorMsg = "上傳的不是文件類型";
}else{
// 取得文件類型
String fileName = fi.getName();
if(fileName!=null && !"".equals(fileName)&&fileName.length()>0)
{
strFileName = fileName.substring(fileName.lastIndexOf("\\"),fileName.length());
FileOutputStream fos = new FileOutputStream(path + strFileName);
if (fi.isInMemory()) {
fos.write(fi.get());
} else {
BufferedReader is = new BufferedReader(
new InputStreamReader(fi.getInputStream()));
String str = null;
while ((str += is.readLine()) != null) {
byte[] buffer = str.getBytes("ISO-8859-1");
fos.write(buffer);
}
is.close();
}
fos.close();
}
}
}
errorMsg="文件上傳成功";
}
} catch (FileUploadException e) {
errorMsg = "文件上傳發生錯誤"+e.getMessage();
e.printStackTrace();
}
}else{
errorMsg = "提交的表單屬性設置不正確,不是上傳文件的表單";
}
request.setAttribute("msg", errorMsg);
request.getRequestDispatcher("/result.jsp").forward(request, response);
%>
處理結果頁面:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>文件上傳結果</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
上傳結果:${msg }
</body>
</html>
④ jsp如何同時添加多個附件進行上傳
單一採用文件瀏覽框比較難實現。可以從網上下載一些插件,支持多個選擇的。
⑤ jsp上傳一個文件夾下的所有文件
jsp上傳一個文件夾下的所有文件:
1、上傳的upload.jsp:
<%@pagelanguage="java"contentType="text/html;charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-1">
<title>FileUpload</title>
</head>
<body>
<formmethod="post"action="UploadServlet"enctype="multipart/form-data">
Selectfiletoupload:
<inputtype="file"name="dataFile"id="fileChooser"/><br/><br/>
<inputtype="submit"value="Upload"/>
</form>
</body>
</html>
2、後台servlet:
{
protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
booleanisMultipart=ServletFileUpload.isMultipartContent(request);
if(isMultipart){
//Createafactoryfordisk-basedfileitems
FileItemFactoryfactory=newDiskFileItemFactory();
//Createanewfileuploadhandler
ServletFileUploapload=newServletFileUpload(factory);
try{
//Parsetherequest
Listitems=upload.parseRequest(request);
Iteratoriterator=items.iterator();
while(iterator.hasNext()){
FileItemitem=(FileItem)iterator.next();
if(!item.isFormField()){
StringfileName=item.getName();
Stringroot=getServletContext().getRealPath("/");
Filepath=newFile(root+"/uploads");
if(!path.exists()){
booleanstatus=path.mkdirs();
}
FileuploadedFile=newFile(path+"/"+fileName);
System.out.println(uploadedFile.getAbsolutePath());
item.write(uploadedFile);
}
}
}catch(FileUploadExceptione){
e.printStackTrace();
}catch(Exceptione){
e.printStackTrace();
}
}
}
}
⑥ 如何用jsp實現文件上傳功能
上傳文件示例:
<form action="doUpload.jsp" method="post" enctype="multipart/form-data">
<%-- 類型enctype用multipart/form-data,這樣可以把文件中的數據作為流式數據上傳,不管是什麼文件類型,均可上傳。--%>
請選擇要上傳的文件<input type="file" name="upfile" size="50">
<input type="submit" value="提交">
</form>
</body>
</html>
⑦ jsp 大文件分片上傳處理如何實現
javaweb上傳文件
上傳文件的jsp中的部分
上傳文件同樣可以使用form表單向後端發請求,也可以使用 ajax向後端發請求
1.通過form表單向後端發送請求
<form id="postForm" action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
<div class="bbxx wrap">
<inputtype="text" id="side-profile-name" name="username" class="form-control">
<inputtype="file" id="example-file-input" name="avatar">
<button type="submit" class="btn btn-effect-ripple btn-primary">Save</button>
</div>
</form>
改進後的代碼不需要form標簽,直接由控制項來實現。開發人員只需要關注業務邏輯即可。JS中已經幫我們封閉好了
this.post_file = function ()
{
$.each(this.ui.btn, function (i, n) { n.hide();});
this.ui.btn.stop.show();
this.State = this.Config.state.Posting;//
this.app.postFile({ id: this.fileSvr.id, pathLoc: this.fileSvr.pathLoc, pathSvr:this.fileSvr.pathSvr,lenSvr: this.fileSvr.lenSvr, fields: this.fields });
};
通過監控工具可以看到控制項提交的數據,非常的清晰,調試也非常的簡單。
2.通過ajax向後端發送請求
$.ajax({
url : "${pageContext.request.contextPath}/UploadServlet",
type : "POST",
data : $( '#postForm').serialize(),
success : function(data) {
$( '#serverResponse').html(data);
},
error : function(data) {
$( '#serverResponse').html(data.status + " : " + data.statusText + " : " + data.responseText);
}
});
ajax分為兩部分,一部分是初始化,文件在上傳前通過AJAX請求通知服務端進行初始化操作
this.md5_complete = function (json)
{
this.fileSvr.md5 = json.md5;
this.ui.msg.text("MD5計算完畢,開始連接伺服器...");
this.event.md5Complete(this, json.md5);//biz event
var loc_path = encodeURIComponent(this.fileSvr.pathLoc);
var loc_len = this.fileSvr.lenLoc;
var loc_size = this.fileSvr.sizeLoc;
var param = jQuery.extend({}, this.fields, this.Config.bizData, { md5: json.md5, id: this.fileSvr.id, lenLoc: loc_len, sizeLoc: loc_size, pathLoc: loc_path, time: new Date().getTime() });
$.ajax({
type: "GET"
, dataType: 'jsonp'
, jsonp: "callback" //自定義的jsonp回調函數名稱,默認為jQuery自動生成的隨機函數名
, url: this.Config["UrlCreate"]
, data: param
, success: function (sv)
{
_this.svr_create(sv);
}
, error: function (req, txt, err)
{
_this.Manager.RemoveQueuePost(_this.fileSvr.id);
alert("向伺服器發送MD5信息錯誤!" + req.responseText);
_this.ui.msg.text("向伺服器發送MD5信息錯誤");
_this.ui.btn.cancel.show();
_this.ui.btn.stop.hide();
}
, complete: function (req, sta) { req = null; }
});
};
在文件上傳完後向伺服器發送通知
this.post_complete = function (json)
{
this.fileSvr.perSvr = "100%";
this.fileSvr.complete = true;
$.each(this.ui.btn, function (i, n)
{
n.hide();
});
this.ui.process.css("width", "100%");
this.ui.percent.text("(100%)");
this.ui.msg.text("上傳完成");
this.Manager.arrFilesComplete.push(this);
this.State = this.Config.state.Complete;
//從上傳列表中刪除
this.Manager.RemoveQueuePost(this.fileSvr.id);
//從未上傳列表中刪除
this.Manager.RemoveQueueWait(this.fileSvr.id);
var param = { md5: this.fileSvr.md5, uid: this.uid, id: this.fileSvr.id, time: new Date().getTime() };
$.ajax({
type: "GET"
, dataType: 'jsonp'
, jsonp: "callback" //自定義的jsonp回調函數名稱,默認為jQuery自動生成的隨機函數名
, url: _this.Config["UrlComplete"]
, data: param
, success: function (msg)
{
_this.event.fileComplete(_this);//觸發事件
_this.post_next();
}
, error: function (req, txt, err) { alert("文件-向伺服器發送Complete信息錯誤!" + req.responseText); }
, complete: function (req, sta) { req = null; }
});
};
這里需要處理一個MD5秒傳的邏輯,當伺服器存在相同文件時,不需要用戶再上傳,而是直接通知用戶秒傳
this.post_complete_quick = function ()
{
this.fileSvr.perSvr = "100%";
this.fileSvr.complete = true;
this.ui.btn.stop.hide();
this.ui.process.css("width", "100%");
this.ui.percent.text("(100%)");
this.ui.msg.text("伺服器存在相同文件,快速上傳成功。");
this.Manager.arrFilesComplete.push(this);
this.State = this.Config.state.Complete;
//從上傳列表中刪除
this.Manager.RemoveQueuePost(this.fileSvr.id);
//從未上傳列表中刪除
this.Manager.RemoveQueueWait(this.fileSvr.id);
//添加到文件列表
this.post_next();
this.event.fileComplete(this);//觸發事件
};
這里可以看到秒傳的邏輯是非常 簡單的,並不是特別的復雜。
var form = new FormData();
form.append("username","zxj");
form.append("avatar",file);
//var form = new FormData($("#postForm")[0]);
$.ajax({
url:"${pageContext.request.contextPath}/UploadServlet",
type:"post",
data:form,
processData:false,
contentType:false,
success:function(data){
console.log(data);
}
});
java部分
文件初始化的邏輯,主要代碼如下
FileInf fileSvr= new FileInf();
fileSvr.id = id;
fileSvr.fdChild = false;
fileSvr.uid = Integer.parseInt(uid);
fileSvr.nameLoc = PathTool.getName(pathLoc);
fileSvr.pathLoc = pathLoc;
fileSvr.lenLoc = Long.parseLong(lenLoc);
fileSvr.sizeLoc = sizeLoc;
fileSvr.deleted = false;
fileSvr.md5 = md5;
fileSvr.nameSvr = fileSvr.nameLoc;
//所有單個文件均以uuid/file方式存儲
PathBuilderUuid pb = new PathBuilderUuid();
fileSvr.pathSvr = pb.genFile(fileSvr.uid,fileSvr);
fileSvr.pathSvr = fileSvr.pathSvr.replace("\\","/");
DBConfig cfg = new DBConfig();
DBFile db = cfg.db();
FileInf fileExist = new FileInf();
boolean exist = db.exist_file(md5,fileExist);
//資料庫已存在相同文件,且有上傳進度,則直接使用此信息
if(exist && fileExist.lenSvr > 1)
{
fileSvr.nameSvr = fileExist.nameSvr;
fileSvr.pathSvr = fileExist.pathSvr;
fileSvr.perSvr = fileExist.perSvr;
fileSvr.lenSvr = fileExist.lenSvr;
fileSvr.complete = fileExist.complete;
db.Add(fileSvr);
//觸發事件
up6_biz_event.file_create_same(fileSvr);
}//此文件不存在
else
{
db.Add(fileSvr);
//觸發事件
up6_biz_event.file_create(fileSvr);
FileBlockWriter fr = new FileBlockWriter();
fr.CreateFile(fileSvr.pathSvr,fileSvr.lenLoc);
}
接收文件塊數據,在這個邏輯中我們接收文件塊數據。控制項對數據進行了優化,可以方便調試。如果用監控工具可以看到控制項提交的數據。
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List files = null;
try
{
files = upload.parseRequest(request);
}
catch (FileUploadException e)
{// 解析文件數據錯誤
out.println("read file data error:" + e.toString());
return;
}
FileItem rangeFile = null;
// 得到所有上傳的文件
Iterator fileItr = files.iterator();
// 循環處理所有文件
while (fileItr.hasNext())
{
// 得到當前文件
rangeFile = (FileItem) fileItr.next();
if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))
{
pathSvr = rangeFile.getString();
pathSvr = PathTool.url_decode(pathSvr);
}
}
boolean verify = false;
String msg = "";
String md5Svr = "";
long blockSizeSvr = rangeFile.getSize();
if(!StringUtils.isBlank(blockMd5))
{
md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());
}
verify = Integer.parseInt(blockSize) == blockSizeSvr;
if(!verify)
{
msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;
}
if(verify && !StringUtils.isBlank(blockMd5))
{
verify = md5Svr.equals(blockMd5);
if(!verify) msg = "block md5 error";
}
if(verify)
{
//保存文件塊數據
FileBlockWriter res = new FileBlockWriter();
//僅第一塊創建
if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));
res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);
up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));
JSONObject o = new JSONObject();
o.put("msg", "ok");
o.put("md5", md5Svr);
o.put("offset", blockOffset);//基於文件的塊偏移位置
msg = o.toString();
}
rangeFile.delete();
out.write(msg);
⑧ 如何上傳多個文件
含義 ENCTYPE="multipart/form-data" 說明:
通過 http 協議上傳文件 rfc1867協議概述,jsp 應用舉例,客戶端發送內容構造
1、概述在最初的 http 協議中,沒有上傳文件方面的功能。 rfc1867 (http://www.ietf.org/rfc/rfc1867.txt) 為 http 協議添加了這個功能。客戶端的瀏覽器,如 Microsoft IE, Mozila, Opera 等,按照此規范將用戶指定的文件發送到伺服器。伺服器端的網頁程序,如 php, asp, jsp 等,可以按照此規范,解析出用戶發送來的文件。Microsoft IE, Mozila, Opera 已經支持此協議,在網頁中使用一個特殊的 form 就可以發送文件。絕大部分 http server ,包括 tomcat ,已經支持此協議,可接受發送來的文件。各種網頁程序,如 php, asp, jsp 中,對於上傳文件已經做了很好的封裝。
2、上傳文件的實例:用 servelet 實現(http server 為 tomcat 4.1.24)1. 在一個 html 網頁中,寫一個如下的form :
load multi files :
text field :
用戶可以選擇多個文件,填寫表單其它項,點擊「提交」按鈕後就開始上傳給 http://192.168.29.65/upload_file/UploadFile
這是一個 servelet 程序注意 enctype="multipart/form-data", method=post, type="file" 。根據 rfc1867, 這三個屬性是必須的。multipart/form-data 是新增的編碼類型,以提高二進制文件的傳輸效率。具體的解釋請參閱 rfc18672. 服務端 servelet 的編寫現在第三方的 http upload file 工具庫很多。Jarkata 項目本身就提供了fileupload 包http://jakarta.apache.org/commons/fileupload/ 。
文件上傳、表單項處理、效率問題基本上都考慮到了。在 Struts 中就使用了這個包,不過是用 Struts 的方式另行封裝了一次。這里我們直接使用 fileupload 包。至於Struts 中的用法,請參閱 Struts 相關文檔。這個處理文件上傳的 servelet 主要代碼如下:
public void doPost( HttpServletRequest request, HttpServletResponse response )
{
DiskFileUpload diskFileUpload = new DiskFileUpload(); // 允許文件最大長度
diskFileUpload.setSizeMax( 100*1024*1024 ); // 設置內存緩沖大小
diskFileUpload.setSizeThreshold( 4096 ); // 設置臨時目錄
diskFileUpload.setRepositoryPath( "c:/tmp" );
List fileItems = diskFileUpload.parseRequest( request );
Iterator iter = fileItems.iterator(); for( ; iter.hasNext(); )
{
FileItem fileItem = (FileItem) iter.next();
if( fileItem.isFormField() ) { // 當前是一個表單項
out.println( "form field : " + fileItem.getFieldName() + ", " + fileItem.getString() );
} else {
// 當前是一個上傳的文件
String fileName = fileItem.getName();
fileItem.write( new File("c:/uploads/"+fileName) );
}
}}
為簡略起見,異常處理,文件重命名等細節沒有寫出。3、 客戶端發送內容構造假設接受文件的網頁程序位於 http://192.168.29.65/upload_file/UploadFile.假設我們要發送一個二進制文件、一個文本框表單項、一個密碼框表單項。文件名為 E:\s ,其內容如下:(其中的XXX代表二進制數據,如 01 02 03)abbXXXccc 客戶端應該向 192.168.29.65 發送如下內容:
POST /upload_file/UploadFile HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.29.65:80
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
Content-Length: 424
Connection: Keep-Alive -----------------------------7d33a816d302b6
Content-Disposition:form-data;
name="userfile1";
filename="E:\s"Content-Type:
application/octet-stream abbXXXccc
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
name="text1" foo
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
name="password1" bar
-----------------------------7d33a816d302b6--
(上面有一個回車)此內容必須一字不差,包括最後的回車。
注意:Content-Length: 424 這里的424是紅色內容的總長度(包括最後的回車)
注意這一行:Content-Type: multipart/form-data; boundary=---------------------------7d33a816d302b6
根據 rfc1867, multipart/form-data是必須的.---------------------------7d33a816d302b6 是分隔符,分隔多個文件、表單項。
其中33a816d302b6 是即時生成的一個數字,用以確保整個分隔符不會在文件或表單項的內容中出現。前面的 ---------------------------7d 是 IE 特有的標志。
Mozila 為---------------------------71用手工發送這個例子,在上述的 servlet 中檢驗通過。
使用POST發送數據
以POST方式發送數據主要是為了向伺服器發送較大量的客戶端的數據,它不受URL的長度限制。POST請求將數據以URL編碼的形式放在HTTP正文中,欄位形式為fieldname=value,用&分隔每個欄位。注意所有的欄位都被作為字元串處理。實際上我們要做的就是模擬瀏覽器POST一個表單。以下是IE發送一個登陸表單的POST請求:
POST http://127.0.0.1/login.do HTTP/1.0
Accept: image/gif, image/jpeg, image/pjpeg, */*
Accept-Language: en-us,zh-cn;q=0.5
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Content-Length: 28
\r\n
username=admin&password=1234
要在MIDP應用程序中模擬瀏覽器發送這個POST請求,首先設置HttpConnection的請求方式為POST:
hc.setRequestMethod(HttpConnection.POST);
然後構造出HTTP正文:
byte[] data = "username=admin&password=1234".getBytes();
並計算正文長度,填入Content-Type和Content-Length:
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
hc.setRequestProperty("Content-Length", String.valueOf(data.length));
然後打開OutputStream將正文寫入:
OutputStream output = hc.openOutputStream();
output.write(data);
需要注意的是,數據仍需要以URL編碼格式編碼,由於MIDP庫中沒有J2SE中與之對應的URLEncoder類,因此,需要自己動手編寫這個encode()方法,可以參考java.net.URLEncoder.java的源碼。剩下的便是讀取伺服器響應,代碼與GET一致,這里就不再詳述。
使用multipart/form-data發送文件
如果要在MIDP客戶端向伺服器上傳文件,我們就必須模擬一個POST multipart/form-data類型的請求,Content-Type必須是multipart/form-data。
以multipart/form-data編碼的POST請求格式與application/x-www-form-urlencoded完全不同,multipart/form-data需要首先在HTTP請求頭設置一個分隔符,例如ABCD:
hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=ABCD");
然後,將每個欄位用「--分隔符」分隔,最後一個「--分隔符--」表示結束。例如,要上傳一個title欄位"Today"和一個文件C:\1.txt,HTTP正文如下:
--ABCD
Content-Disposition: form-data; name="title"
\r\n
Today
--ABCD
Content-Disposition: form-data; name="1.txt"; filename="C:\1.txt"
Content-Type: text/plain
\r\n
--ABCD--
\r\n
請注意,每一行都必須以\r\n結束,包括最後一行。如果用Sniffer程序檢測IE發送的POST請求,可以發現IE的分隔符類似於---------------------------7d4a6d158c9,這是IE產生的一個隨機數,目的是防止上傳文件中出現分隔符導致伺服器無法正確識別文件起始位置。我們可以寫一個固定的分隔符,只要足夠復雜即可。
發送文件的POST代碼如下:
String[] props = ... // 欄位名
String[] values = ... // 欄位值
byte[] file = ... // 文件內容
String BOUNDARY = "---------------------------7d4a6d158c9"; // 分隔符
StringBuffer sb = new StringBuffer();
// 發送每個欄位:
for(int i=0; i
sb = sb.append("--");
sb = sb.append(BOUNDARY);
sb = sb.append("\r\n");
sb = sb.append("Content-Disposition: form-data; name=\""+ props[i] + "\"\r\n\r\n");
sb = sb.append(URLEncoder.encode(values[i]));
sb = sb.append("\r\n");
}
// 發送文件:
sb = sb.append("--");
sb = sb.append(BOUNDARY);
sb = sb.append("\r\n");
sb = sb.append("Content-Disposition: form-data; name=\"1\"; filename=\"1.txt\"\r\n");
sb = sb.append("Content-Type: application/octet-stream\r\n\r\n");
byte[] data = sb.toString().getBytes();
byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
// 設置HTTP頭:
hc.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);
hc.setRequestProperty("Content-Length", String.valueOf(data.length + file.length + end_data.length));
// 輸出:
output = hc.openOutputStream();
output.write(data);
output.write(file);
output.write(end_data);
// 讀取伺服器響應:
// TODO...
⑨ (緊急求助)jsp 多組多文件上傳問題
如果你的jsp應用了struts就方便得多了:
<html:form action="/contract.do" method="post"
enctype="multipart/form-data" >
<tr id="date_1">
<th>1:</th>
<td>
<html:file size="40" property="contractFile1" name="contractForm">
</html:file>
<img src="<%= request.getContextPath() %>/images/add_icon.gif" style="cursor:pointer;" onClick="addRowLevel()"/>
</td>
</tr>
<tr id="date_2" style="display:none;">
<th><bean:message key="per.contract.extraprotocal" />2:</th>
<td>
<html:file size="40" property="contractFile2" name="contractForm" ></html:file>
<img src="<%= request.getContextPath() %>/images/add_icon.gif" style="cursor:pointer;" onClick="addRowLevel()"/>
<img src="<%= request.getContextPath() %>/images/sub_icon.gif" style="cursor:pointer;" onClick="deleteRowLevel(2)"/>
</td>
</tr>
</html:form>
//script
function addRowLevel(){ }
主要是利用FormFile來獲取
⑩ jsp文上傳如何實現將上傳的多個文件都同時顯示出來
需要寫一個servlet來處理上傳的文件,你可以修改保存路徑或選擇將圖片保存在資料庫中,只需要做簡單的修改就行了,servlet代碼如下:
package com.ek.servlet;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.ek.image.ImageUtil;
publicclass FileUploadServlet extends HttpServlet {
/**
*
*/
privatestaticfinallong serialVersionUID = 1L;
privatestatic String filePath = "";
/**
* Destruction of the servlet.
*/
publicvoid destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doPost method of the servlet.
*
* This method is called when a form has its tag value method equals to
* post.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
publicvoid doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html; charset=UTF-8");
DiskFileItemFactory factory = new DiskFileItemFactory();
// maximum size that will be stored in memory
factory.setSizeThreshold(4096);
// the location for saving data that is larger than getSizeThreshold()
factory.setRepository(new File(filePath));
ServletFileUpload upload = new ServletFileUpload(factory);
// maximum size before a FileUploadException will be thrown
upload.setSizeMax(1000000);
try {
List fileItems = upload.parseRequest(req);
Iterator iter = fileItems.iterator();
// Get the file name
String regExp = ".+\\\\(.+\\.?())$";
Pattern fileNamePattern = Pattern.compile(regExp);
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()) {
String name = item.getName();
long size = item.getSize();
if ((name == null || name.equals("")) && size == 0)
continue;
Matcher m = fileNamePattern.matcher(name);
boolean result = m.find();
if (result) {
try {
// String type =
// m.group(1).substring(m.group(1).lastIndexOf('.')+1);
InputStream stream = item.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = newbyte[1000];
while (stream.read(b) > 0) {
baos.write(b);
}
byte[] imageByte = baos.toByteArray();
String type = ImageUtil.getImageType(imageByte);
if (type.equals(ImageUtil.TYPE_NOT_AVAILABLE))
thrownew Exception("file is not a image");
BufferedImage myImage = ImageUtil
.readImage(imageByte);
// display the image
ImageUtil.printImage(myImage, type, res
.getOutputStream());
// save the image
// if you want to save the file into database, do it here
// when you want to display the image, use the method printImage in ImageUtil
item.write(new File(filePath + "\\" + m.group(1)));
stream.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
} else {
throw new IOException("fail to upload");
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (FileUploadException e) {
e.printStackTrace();
}
}
/**
* Initialization of the servlet.
*
* @throws ServletException
* if an error occure
*/
public void init() throws ServletException {
// Change the file path here
filePath = getServletContext().getRealPath("/");
}
}
servlet中使用到一個ImageUtil類,其中封裝了圖片處理的實用方法,用於讀寫圖片,代碼如下:
package com.ek.image;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.MemoryCacheImageInputStream;
import net.jmge.gif.Gif89Encoder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.imageio.plugins.bmp.BMPImageReader;
import com.sun.imageio.plugins.gif.GIFImageReader;
import com.sun.imageio.plugins.jpeg.JPEGImageReader;
import com.sun.imageio.plugins.png.PNGImageReader;
/**
* @author Erick Kong
* @see ImageUtil.java
* @createDate: 2007-6-22
* @version 1.0
*/
publicclass ImageUtil {
publicstaticfinal String TYPE_GIF = "gif";
publicstaticfinal String TYPE_JPEG = "jpeg";
publicstaticfinal String TYPE_PNG = "png";
publicstaticfinal String TYPE_BMP = "bmp";
publicstaticfinal String TYPE_NOT_AVAILABLE = "na";
privatestatic ColorModel getColorModel(Image image)
throws InterruptedException, IllegalArgumentException {
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
if (!pg.grabPixels())
thrownew IllegalArgumentException();
return pg.getColorModel();
}
privatestaticvoid loadImage(Image image) throws InterruptedException,
IllegalArgumentException {
Component mmy = new Component() {
privatestaticfinallong serialVersionUID = 1L;
};
MediaTracker tracker = new MediaTracker(mmy);
tracker.addImage(image, 0);
tracker.waitForID(0);
if (tracker.isErrorID(0))
thrownew IllegalArgumentException();
}
publicstatic BufferedImage createBufferedImage(Image image)
throws InterruptedException, IllegalArgumentException {
loadImage(image);
int w = image.getWidth(null);
int h = image.getHeight(null);
ColorModel cm = getColorModel(image);
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage bi = gc.createCompatibleImage(w, h, cm.getTransparency());
Graphics2D g = bi.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bi;
}
publicstatic BufferedImage readImage(InputStream is) {
BufferedImage image = null;
try {
image = ImageIO.read(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return image;
}
publicstatic BufferedImage readImage(byte[] imageByte) {
ByteArrayInputStream s = new ByteArrayInputStream(imageByte);
BufferedImage image = readImage(s);
return image;
}
publicstaticvoid encodeGIF(BufferedImage image, OutputStream out)
throws IOException {
Gif89Encoder encoder = new Gif89Encoder(image);
encoder.encode(out);
}
/**
*
* @param bi
* @param type
* @param out
*/
publicstaticvoid printImage(BufferedImage bi, String type,
OutputStream out) {
try {
if (type.equals(TYPE_GIF))
encodeGIF(bi, out);
else
ImageIO.write(bi, type, out);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Get image type from byte[]
*
* @param textObj
* image byte[]
* @return String image type
*/
publicstatic String getImageType(byte[] textObj) {
String type = TYPE_NOT_AVAILABLE;
ByteArrayInputStream s = null;
MemoryCacheImageInputStream mcis = null;
try {
s = new ByteArrayInputStream(textObj);
mcis = new MemoryCacheImageInputStream(s);
Iterator itr = ImageIO.getImageReaders(mcis);
while (itr.hasNext()) {
ImageReader reader = (ImageReader) itr.next();
if (reader instanceof GIFImageReader) {
type = TYPE_GIF;
} elseif (reader instanceof JPEGImageReader) {
type = TYPE_JPEG;
} elseif (reader instanceof PNGImageReader) {
type = TYPE_PNG;
} elseif (reader instanceof BMPImageReader) {
type = TYPE_BMP;
}
reader.dispose();
}
} finally {
if (s != null) {
try {
s.close();
} catch (IOException ioe) {
if (_log.isWarnEnabled()) {
_log.warn(ioe);
}
}
}
if (mcis != null) {
try {
mcis.close();
} catch (IOException ioe) {
if (_log.isWarnEnabled()) {
_log.warn(ioe);
}
}
}
}
if (_log.isDebugEnabled()) {
_log.debug("Detected type " + type);
}
return type;
}
privatestatic Log _log = LogFactory.getLog(ImageUtil.class);
}
注意:對gif格式的圖片進行處理的時候,需要另外一下jar包:gif89.jar,因為gif格式的圖片不能使用ImageIO進行輸出。
如需將圖片存放到資料庫中,只需要修改紅色部分,將圖片以blob格式保存到資料庫中,顯示時以byte[]格式讀出,使用ImageUtil.printImage()進行輸出。