一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 全面分析Java文件上傳

全面分析Java文件上傳

2021-04-02 15:49Java3y Java教程

本片文章給大家詳細(xì)分析了Java文件上傳的相關(guān)知識(shí)點(diǎn),以及相關(guān)代碼做了詳細(xì)分析,有興趣的朋友學(xué)習(xí)下。

什么是文件上傳?

文件上傳就是把用戶的信息保存起來。

為什么需要文件上傳?

在用戶注冊(cè)的時(shí)候,可能需要用戶提交照片。那么這張照片就應(yīng)該要進(jìn)行保存。

上傳組件(工具) 為什么我們要使用上傳工具?

為啥我們需要上傳組件呢?當(dāng)我們要獲取客戶端的數(shù)據(jù),我們一般是通過getparameter()方法來獲取的。

上傳文件數(shù)據(jù)是經(jīng)過mime協(xié)議進(jìn)行分割的,表單進(jìn)行了二進(jìn)制封裝。也就是說:getparameter()無法獲取得到上傳文件的數(shù)據(jù)。

我們首先來看看文件上傳http是怎么把數(shù)據(jù)帶過去的

jsp頁(yè)面,表單一定要指定enctype:multipart/form-data

?
1
2
3
4
5
6
<form action="${pagecontext.request.contextpath }/servlet/uploadservlet1" enctype="multipart/form-data" method="post">
    上傳用戶:<input type="text" name="username"><br/>
    上傳文件1:<input type="file" name="file1"><br/>
    上傳文件2:<input type="file" name="file2"><br/>
    <input type="submit" value="提交">
  </form>

http抓包

全面分析Java文件上傳

嘗試在servlet上使用getparameter()獲取數(shù)據(jù)

?
1
2
string ss = request.getparameter("username");
system.out.println(ss);

直接使用getparameter是獲取不到數(shù)據(jù)的。

全面分析Java文件上傳

那么我們要怎么辦呢????request對(duì)象提供了servletinputstream流給我們讀取數(shù)據(jù)

我們?cè)囍x取下文件

?
1
2
3
4
5
6
7
8
servletinputstream inputstream = request.getinputstream();
 
    byte[] bytes = new byte[1024];
    int len = 0;
 
    while ((len = inputstream.read(bytes)) > 0) {
      system.out.println(new string(bytes, 0, len));
    }

在jsp頁(yè)面多增添一個(gè)input控件

?
1
<input type="text" name="password">

我上傳的文本文件內(nèi)容就是111111,讀取效果如下:

全面分析Java文件上傳

現(xiàn)在我們能夠讀取上傳文件的數(shù)據(jù)了,但是現(xiàn)在問題又來了:怎么把文件上傳個(gè)數(shù)據(jù)和普通傳送給服務(wù)器的數(shù)據(jù)分割開來呢???上面在圖上我們已經(jīng)看到了,他們是混合在一起的。

按我們平常的做法是很難分割開來的,所以我們需要上傳組件

上傳組件有兩種 fileupload【操作比較復(fù)雜】 samrtupload【操作比較簡(jiǎn)單】 fileupload

要使用fileupload組件,就需要導(dǎo)入兩個(gè)jar包

commons-io commons-fileupload 開發(fā)步驟 創(chuàng)建解析器工廠對(duì)象【diskfileitemfactory】通過解析器工廠創(chuàng)建解析器【servletfileupload】調(diào)用解析器方法解析request對(duì)象,得到所有上傳的內(nèi)容【list】遍歷list,判斷每個(gè)對(duì)象是否是上傳文件 如果是普通表單字段,得到字段名和字段值如果是上傳文件,調(diào)用inputsteam方法得到輸入流,讀取上傳的數(shù)據(jù) 快速入門

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
try{
    
      //1.得到解析器工廠
      diskfileitemfactory factory = new diskfileitemfactory();
      
      //2.得到解析器
      servletfileupload upload = new servletfileupload(factory);
      
      //3.判斷上傳表單的類型
      if(!upload.ismultipartcontent(request)){
        //上傳表單為普通表單,則按照傳統(tǒng)方式獲取數(shù)據(jù)即可
        return;
      }
      
      //為上傳表單,則調(diào)用解析器解析上傳數(shù)據(jù)
      list<fileitem> list = upload.parserequest(request); //fileitem
      
      //遍歷list,得到用于封裝第一個(gè)上傳輸入項(xiàng)數(shù)據(jù)fileitem對(duì)象
      for(fileitem item : list){
        
        if(item.isformfield()){
          //得到的是普通輸入項(xiàng)
          string name = item.getfieldname(); //得到輸入項(xiàng)的名稱
          string value = item.getstring();
          system.out.println(name + "=" + value);
        }else{
          //得到上傳輸入項(xiàng)
          string filename = item.getname(); //得到上傳文件名 c:\documents and settings\thinkpad\桌面\1.txt
          filename = filename.substring(filename.lastindexof("\\")+1);
          inputstream in = item.getinputstream();  //得到上傳數(shù)據(jù)
          int len = 0;
          byte buffer[]= new byte[1024];
          
          
          string savepath = this.getservletcontext().getrealpath("/upload");
          fileoutputstream out = new fileoutputstream(savepath + "\\" + filename); //向upload目錄中寫入文件
          while((len=in.read(buffer))>0){
            out.write(buffer, 0, len);
          }
          
          in.close();
          out.close();
        }
      }
    
    }catch (exception e) {
      e.printstacktrace();
    }

測(cè)試 普通的字段和上傳的文件都能讀取得到了!

全面分析Java文件上傳

smartupload

要使用smartupload組件,就需要導(dǎo)入smartupload.jar開發(fā)包

快速入門

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//實(shí)例化組件
    smartupload smartupload = new smartupload();
 
    //初始化上傳操作
    smartupload.initialize(this.getservletconfig(), request, response);
 
 
    try {
 
      //上傳準(zhǔn)備
      smartupload.upload();
 
      //對(duì)于普通數(shù)據(jù),單純到request對(duì)象是無法獲取得到提交參數(shù)的。也是需要依賴smartupload
      string password = smartupload.getrequest().getparameter("password");
      system.out.println(password);
 
      //上傳到uploadfile文件夾中
      smartupload.save("uploadfile");
 
 
    } catch (smartuploadexception e) {
      e.printstacktrace();
    }

測(cè)試

同樣地,我們可以上傳文件到uploadfile文件夾中。代碼量也的確減少很多!

也能夠獲取普通字段的參數(shù)

全面分析Java文件上傳

上傳文件名的中文亂碼和上傳數(shù)據(jù)的中文亂碼 我把文件名改成中文,就亂碼了:

全面分析Java文件上傳

表單提交過來的中文數(shù)據(jù)也亂碼了。

全面分析Java文件上傳

上面已經(jīng)說了,上傳文件的數(shù)據(jù)的表單進(jìn)行了二進(jìn)制封裝,所以使用request對(duì)數(shù)據(jù)編碼編碼,對(duì)于表單提交過來的數(shù)據(jù)是不奏效的!

fileupload解決亂碼

使用fileupload解決亂碼問題是十分簡(jiǎn)單的

解決中文文件名亂碼,得到解析器以后,就直接設(shè)置解析器的編碼為utf-8就行了!

?
1
2
//設(shè)置upload的編碼
fileupload.setheaderencoding("utf-8");

解決表單數(shù)據(jù)亂碼,在獲取表單值的時(shí)候,按照utf-8編碼來獲取

?
1
string value = fileitem.getstring("utf-8");

效果:

全面分析Java文件上傳

smartupload解決亂碼

這個(gè)組件解決亂碼問題有點(diǎn)麻煩,在網(wǎng)上找了各種辦法也沒找到簡(jiǎn)單的......

所以,如果數(shù)據(jù)不涉及到中文就使用smartupload組件,涉及到中文數(shù)據(jù)就使用fileupload組件吧!

多個(gè)文件上傳,動(dòng)態(tài)添加上傳控件

假設(shè)我現(xiàn)在有多個(gè)文件要上傳,而且要上傳的個(gè)數(shù)是不確定的。那么我們要怎么辦呢???

我們不可能列出很多很多個(gè)上傳文件的控件在頁(yè)面上,這樣不美觀。如果用戶用不到那么多個(gè)控件,也浪費(fèi)呀。

所以,我們想要?jiǎng)討B(tài)地增添上傳文件的控件,如果用戶還想要上傳文件,只需要?jiǎng)討B(tài)地生成控件出來即可!

分析

要想在頁(yè)面上動(dòng)態(tài)地生成控件,無非就是使用javascript代碼。

那么我們要怎么做呢??

這樣子吧:當(dāng)用戶想要上傳文件的時(shí)候,就點(diǎn)擊按鈕,按鈕綁定事件,生成文件上傳的控件。

為了做得更加完善,每當(dāng)生成了文件上傳的控件,也提供一個(gè)刪除按鈕,刪除該控件!

我們應(yīng)該使用div裝載著我們要生成的控件和刪除按鈕,而用戶點(diǎn)擊刪除的時(shí)候,應(yīng)該是要把刪除按鈕和文件上傳控件都一起隱藏起來的。所以,最好就是使用嵌套div!

代碼 頁(yè)面代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<table>
  <tr>
    <td>上傳用戶:</td>
    <td><input type="text" name="username"></td>
  </tr>
  <tr>
    <td>添加上傳文件</td>
    <td><input type="button" value="添加上傳文件"> </td>
  </tr>
  <tr>
    <td>
      <div>
      </div>
    </td>
  </tr>
</table>

javascript代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script type="text/javascript">
    function adduploadfile() {
      //生成文件上傳控件
      var input = document.createelement("input");
      input.type = 'file';
      input.name = 'filename';
      //生成刪除按鈕
      var del = document.createelement("input");
      del.type = 'button';
      del.value = '刪除';
      //生成內(nèi)部的div
      var innerdiv = document.createelement("div");
      //將兩個(gè)控件綁定到內(nèi)部div上
      innerdiv.appendchild(input);
      innerdiv.appendchild(del);
      //得到外部div控件,并將內(nèi)部div綁定到外部div上
      var outterdiv = document.getelementbyid("file");
      outterdiv.appendchild(innerdiv);
      //為刪除按鈕綁定事件
      del.onclick = function dele() {
        //調(diào)用外界div的remove方法把內(nèi)部的div干掉
        this.parentnode.parentnode.removechild(this.parentnode);
      }
    }
  </script>

文件上傳細(xì)節(jié) 如果上傳文件的大小大于我們?cè)O(shè)定文件的大小,那么文件在上傳的時(shí)候會(huì)使用臨時(shí)文件保存上傳數(shù)據(jù)。在上傳完畢后,我們應(yīng)該刪除臨時(shí)文件上傳文件的位置是不能在web服務(wù)器管理之下的,否則可能造成安全問題【其他人有可能通過手段來修改上傳文件】如果上傳文件名相同,那么就會(huì)把原本的上傳文件覆蓋掉。我們要生成一個(gè)獨(dú)一無二的文件名。如果用戶量很大,上傳文件非常多。那么我們不應(yīng)該在一個(gè)目錄保存所有的上傳文件,這樣很可能造成磁盤奔潰了。所以我們要把上傳的文件打散到不同的目錄下。 分析

刪除臨時(shí)文件問題是非常簡(jiǎn)單的,只需要在所有的操作完畢之后,調(diào)用fileitem的delete()方法即可

讓上傳文件的位置不能在web服務(wù)器管理之下,我們把上傳文件的位置放到web-inf/目錄下即可!

文件名相同的問題,我們可以使用uuid+用戶上傳的文件名來作為我們保存上傳文件名。這樣的文件名就是獨(dú)一無二的了。

要將上傳的文件進(jìn)行打散,那么我們需要使用hashcode算法來進(jìn)行打散。

低四位生成一級(jí)目錄 5-8位生成二級(jí)目錄 代碼

下面我們寫一個(gè)比較完善的上傳文件代碼

用hashcode算法來打散保存的目錄

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private string makedirpath(string filename, string path) {
 
    //通過文件名來算出一級(jí)目錄和二級(jí)目錄
    int hashcode = filename.hashcode();
    int dir1 = hashcode & 0xf;
    int dir2 = (hashcode & 0xf0) >> 4;
 
    string dir = path + "\\" + dir1 + "\\" + dir2;
 
    //如果該目錄不存在,就創(chuàng)建目錄
    file file = new file(dir);
    if (!file.exists()) {
 
      file.mkdirs();
    }
    //返回全路徑
    return dir;
 
  }

生成獨(dú)一無二的文件名

?
1
2
3
4
5
6
private string makefilename(string filename) {
 
    //使用下劃線把uuid和文件名分割開來,后面可能會(huì)解析文件名的。
    return uuid.randomuuid().tostring() + "_"+ filename;
 
  }

上傳的代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//創(chuàng)建工廠
    diskfileitemfactory factory = new diskfileitemfactory();
 
    //通過工廠創(chuàng)建解析器
    servletfileupload fileupload = new servletfileupload(factory);
 
    //設(shè)置upload的編碼
    fileupload.setheaderencoding("utf-8");
 
    //判斷上傳表單的類型
    if(!fileupload.ismultipartcontent(request)){
      //上傳表單為普通表單,則按照傳統(tǒng)方式獲取數(shù)據(jù)即可
      return;
    }
 
    try {
 
      //解析request對(duì)象,得到list【裝載著上傳的全部?jī)?nèi)容】
      list<fileitem> list = fileupload.parserequest(request);
 
      //遍歷list,判斷裝載的內(nèi)容是普通字段還是上傳文件
      for (fileitem fileitem : list) {
 
        //如果是普通輸入項(xiàng)
        if (fileitem.isformfield()) {
 
          //得到輸入項(xiàng)的名稱和值
          string name = fileitem.getfieldname();
          string value = fileitem.getstring("utf-8");
 
          system.out.println(name + " = " + value);
        } else {
 
          //如果是上傳文件
 
          //得到上傳名稱【包括路徑名】
          string filename = fileitem.getname();
 
          //截取文件名
          filename = filename.substring(filename.lastindexof("\\") + 1);
 
          //生成獨(dú)一無二的文件名
          filename = makefilename(filename);
 
          inputstream inputstream = fileitem.getinputstream();
 
          //得到項(xiàng)目的路徑,把上傳文件寫到項(xiàng)目中
          string path = this.getservletcontext().getrealpath("/web-inf/uploadfile");
 
          //得到分散后的目錄路徑
          string realpath = makedirpath(filename, path);
 
          fileoutputstream outputstream = new fileoutputstream(realpath + "\\" + filename);
 
          byte[] bytes = new byte[1024];
          int len = 0;
          while ((len = inputstream.read(bytes)) > 0) {
            outputstream.write(bytes, 0, len);
          }
 
          inputstream.close();
          outputstream.close();
 
          //刪除臨時(shí)文件的數(shù)據(jù)
          fileitem.delete();
 
        }
      }
 
    } catch (fileuploadexception e) {
      e.printstacktrace();
    }

效果: 成功把目錄打散,文件名也是獨(dú)一無二的了。

全面分析Java文件上傳

列出上傳目錄下的文件,提供下載

在講解respose對(duì)象的時(shí)候已經(jīng)講解過文件下載了。這次我們就直接寫一個(gè)小案例來鞏固文件下載把。

上傳目錄下的文件有3個(gè)

全面分析Java文件上傳

分析

首先,要把目錄下的文件都列出來。由于后面要根據(jù)文件名對(duì)文件進(jìn)行下載,所以我們用一個(gè)map集合來保存所有的文件

下載文件部分也很簡(jiǎn)單,根據(jù)文件名和上傳文件位置找到對(duì)應(yīng)的文件,對(duì)其進(jìn)行讀寫,然后修改消息頭實(shí)現(xiàn)下載就好了。

得到裝載上傳文件的路徑,通過遞歸把所有的文件都查找出來(判斷是否是文件就是遞歸出口),裝載到map集合中將map集合傳到前臺(tái)做展示用戶點(diǎn)擊下載的時(shí)候,再根據(jù)原名來獲取絕對(duì)路徑如果該資源是存在的,就允許用戶下載 代碼 將存放在web-inf/目錄下的文件全部放在map集合中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
    //得到上傳文件的目錄
    string filepath = this.getservletcontext().getrealpath("/web-inf/uploadfile");
    map map = new hashmap();
    //使用遞歸來得到所有的文件,并添加到map集合中
    getallfiles(new file(filepath), map);
    request.setattribute("map", map);
    request.getrequestdispatcher("/listfile.jsp").forward(request, response);
  }
  private void getallfiles(file filepath, map map) {
    //如果不是文件,那么它就是文件夾
    if (!filepath.isfile()) {
 
      //列出文件夾下所有的文件(可能是文件,可能是文件夾)
      file[] files = filepath.listfiles();
      for (file file : files) {
 
        //得到的文件(或者是文件夾)再對(duì)其進(jìn)行判斷
        getallfiles(file, map);
      }
    } else {
      //進(jìn)入到else語句了,肯定是文件了
 
      //得到文件名
      string filename = filepath.getname().substring(filepath.getname().lastindexof("_") + 1);
 
      //我們將文件全名作為key,文件名作為value保存在map集合中
      map.put(filepath.getname(), filename);
 
    }
 
  }

在jsp頁(yè)面中顯示可以下載的文件

?
1
2
3
4
5
6
7
8
<c:foreach items="${map}" var="me">
 
  <c:url var="url" value="/downfileservlet">
    <c:param name="filename" value="${me.key}"></c:param>
  </c:url>
  ${me.value}<a href="${url}" rel="external nofollow" >下載!</a><br>
 
</c:foreach>

實(shí)現(xiàn)下載的servlet

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
 
    //得到文件的全名
    string filename = request.getparameter("filename");
 
    //如果是中文數(shù)據(jù),需要轉(zhuǎn)碼。
    filename = new string(filename.getbytes("iso8859-1"), "utf-8");
 
    //得到保存文件的位置
    string path = this.getservletcontext().getrealpath("/web-inf/uploadfile");
 
    //文件是通過文件名進(jìn)行hashcode打散保存的,通過文件名拿到文件絕對(duì)路徑
    string filerealpath = makefilepath(filename, path);
    system.out.println(filerealpath);
 
    //判斷文件是否存在
    file file = new file(filerealpath);
    if (!file.exists()) {
      request.setattribute("message", "您要下載的資源不存在了!");
      request.getrequestdispatcher("/message.jsp").forward(request, response);
      return ;
    }
    //存在
    //讀取該文件并把數(shù)據(jù)寫給瀏覽器
    fileinputstream inputstream = new fileinputstream(filerealpath);
    byte[] bytes = new byte[1024];
    int len = 0;
    while ((len = inputstream.read(bytes)) > 0) {
      response.getoutputstream().write(bytes, 0, len);
    }
    inputstream.close();
    //設(shè)置消息頭,告訴瀏覽器,這是下載的文件
    string name = filename.substring(filename.lastindexof("_") + 1);
    response.setheader("content-disposition","attachment;filename=" + urlencoder.encode(name, "utf-8"));
 
  }
  private string makefilepath(string filename, string path) {
    int hashcode = filename.hashcode();
    int dir1 = hashcode & 0xf;
    int dir2 = (hashcode & 0xf0) >> 4;
    string dir = path + "\\" + dir1 + "\\" + dir2 +"\\"+ filename;
    return dir;
  }

效果

全面分析Java文件上傳

如果文章有錯(cuò)的地方歡迎指正,大家互相交流。感謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:https://www.cnblogs.com/Java3y/p/8428591.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 201天天爱天天做 | 我与么公激情性完整视频 | 精品高潮呻吟99AV无码视频 | 欧美精品黑人巨大在线播放 | 欧美一级特黄特色大片 | 大学生按摩黄a级中文片 | 国产99视频精品免费视频7 | 日本在线色 | 高清视频免费 | 亚洲国产成人久久99精品 | 2020年国产精品午夜福利在线观看 | 欧美一级乱妇老太婆特黄 | 国产精品一区二区在线观看完整版 | 九色PORNY蝌蚪视频首页 | a级亚洲片精品久久久久久久 | 美女毛片老太婆bbb80岁 | 亚洲激情欧美 | 青青青青青国产费线在线观看 | 欧美在线播放一区二区 | 亚洲欧美另类综合 | 亚洲欧美在线观看首页 | ssni-497新任美脚女教师 | 国模大胆一区二区三区 | 亚洲嫩模吧粉嫩粉嫩冒白浆 | 男同志与动人物zozotv | 亚洲视频1区 | 91看片淫黄大片在看 | 天天操天天射天天色 | 男生和老师一起差差差 | 成人国产精品视频 | 色菇凉天天综合网 | 欧美大美bbb和大白屁股 | m3u8久久国产精品影院 | 女女性恋爱视频入口 | 日比免费视频 | 99久久精品免费观看区一 | 女人又色又爽又黄 | 国产成人一区二区三区影院免费 | 99久视频 | 久久黄色录像 | 9999热视频 |