1、文件上傳的原理分析
1、文件上傳的必要前提:
a、提供form表單,method必須是post
b、form表單的enctype必須是multipart/form-data
c、提供input type="file"類的上傳輸入域
2、enctype屬性
作用:告知服務器請求正文的MIME類型(請求消息頭:Content-Type作用是一致的)
可選值:
application/x-www-form-urlencoded(默認):
正文:name=admin&password=123;
服務器獲取數據:String name = request.getParameter("name");
multipart/form-data:
服務器獲取數據:request.getParameter(String)方法獲取指定的表單字段字符內容,但文件上傳表單已經不再是字符內容,而是字節內容,所以失效。
文件上傳:解析請求正文的每部分的內容
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
|
<body> <form enctype= "multipart/form-data" action= "${pageContext.request.contextPath }/servlet/uploadServlet2" method= "post" > <input type= "text" name= "name" /><br/> <input type= "file" name= "photo" /><br/> <input type= "submit" value= "上傳" /><br/> </form> </body> public class UploadServlet1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 由于表單中提交數據的方式改為multipart/form-data,所以request.getParameter("name")失效 * String name = request.getParameter("name"); String photo = request.getParameter("photo"); System.out.println(name); System.out.println(photo);*/ InputStream is = request.getInputStream(); int len = 0 ; byte [] b = new byte [ 1024 ]; while ((len=is.read(b))!=- 1 ){ System.out.println( new String(b, 0 ,len)); } is.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
2、借助第三方的上傳組件實現文件上傳
1、fileupload概述
fileupload是由apache的commons組件提供的上傳組件。它最主要的工作就是幫我們解析request.getInputStream()
導入commons-fileupload相關jar包:
commons-fileupload.jar 核心包
commons-io.jar 依賴包
2、fileupload的核心類:
DiskFileItemFactory、ServletFileUpload、FileItem
a、解析原理
3、fileupload簡單應用
使用fileupload組件的步驟如下:
1、創建工廠類DiskFileItemFactory對象:
1
|
DiskFileItemFactory factory = new DiskFileItemFactory(); |
2、使用工廠創建解析器對象:
1
|
ServletFileUpload fileUpload = new ServletFileUpload(factory); |
3、使用解析器來解析request對象:
1
|
List<FileItem> list = fileUpload.parseRequest(request) |
FileItem對象對應一個表單項(表單字段)。可以是文件字段或普通字段
boolean isFormField():判斷當前表單字段是否為普通文本字段,如果返回false,說明是文件字段
String getFieldName():獲取字段名稱,例如:<input type="text" name="username" /> 返回的是username
String getString():獲取字段的內容,如果是文件字段,那么獲取的是文件內容,當然上傳的文件必須是文本文件
String getName():獲取文件字段的文件名稱(a.txt)
String getContentType():獲取上傳的文件的MIME類型,例如:text/plain
int getSize():獲取上傳文件的大小
InputStream getInputStream():獲取上傳文件對應的輸入流
void write(File):把上傳的文件保存到指定文件中
delete()
3、文件上傳時需要考慮的幾個問題(經驗分享)
1、保證服務器的安全
把保存上傳文件的目錄放在用戶直接訪問不到的地方
2、避免文件被覆蓋
讓文件名唯一即可
3、避免同一個文件夾中的文件過多
方案一:按照日期進行打散存儲目錄
方案二:用文件名的hashcode計算打散的存儲目錄:二級目錄
4、限制文件的大小:web方式不適合上傳大的文件
單個文件大小:
1
|
ServletFileUpload.setFileSizeMax(字節) |
總文件大小:(多文件上傳)
1
|
ServletFileUpload.setSizeMax(字節) |
5、上傳字段用戶沒有上傳的問題:
通過判斷文件名是否為空即可
6、臨時文件的問題:
DiskFileItemFactory:
作用:產生FileItem對象
內部有一個緩存,緩存大小默認是10kb,如果上傳的文件超過10kb,用磁盤作為緩存。
存放緩存文件的目錄在哪里?默認是系統的臨時目錄。
如果自己用IO流實現的文件上傳,要在流關閉后,清理臨時文件。
FileItem.delete();
4、
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
public class UploadServlet2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // request.setCharacterEncoding("UTF-8"); // 要執行文件上傳的操作 // 判斷表單是否支持文件上傳。即:enctype="multipart/form-data" boolean isMultipartContent = ServletFileUpload .isMultipartContent(request); if (!isMultipartContent) { throw new RuntimeException( "your form is not multipart/form-data" ); } // 創建一個DiskFileItemfactory工廠類 DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setRepository( new File( "f:\\" )); // 指定臨時文件的存儲目錄 // 創建一個ServletFileUpload核心對象 ServletFileUpload sfu = new ServletFileUpload(factory); // 解決上傳表單項亂碼問題 sfu.setHeaderEncoding( "UTF-8" ); // 限制上傳文件的大小 // 解析request對象,并得到一個表單項的集合 try { // sfu.setFileSizeMax(1024*1024*3);//表示3M大小 // sfu.setSizeMax(1024*1024*6); List<FileItem> fileItems = sfu.parseRequest(request); // 遍歷表單項數據 for (FileItem fileitem : fileItems) { if (fileitem.isFormField()) { // 普通表單項 processFormField(fileitem); } else { // 上傳表單項 processUploadField(fileitem); } } } catch (FileUploadBase.FileSizeLimitExceededException e) { // throw new RuntimeException("文件過在,不能超過3M"); System.out.println( "文件過在,不能超過3M" ); } catch (FileUploadBase.SizeLimitExceededException e) { System.out.println( "總文件大小不能超過6M" ); } catch (FileUploadException e) { e.printStackTrace(); } } private void processUploadField(FileItem fileitem) { try { // 得到文件輸入流 InputStream is = fileitem.getInputStream(); // 創建一個文件存盤的目錄 String directoryRealPath = this .getServletContext().getRealPath( "/WEB-INF/upload" ); File storeDirectory = new File(directoryRealPath); // 即代表文件又代表目錄 if (!storeDirectory.exists()) { storeDirectory.mkdirs(); // 創建一個指定的目錄 } // 得到上傳的名子 String filename = fileitem.getName(); // 文件項中的值 F:\圖片素材\小清新\43.jpg 或者 // 43.jpg if (filename != null ) { // filename = // filename.substring(filename.lastIndexOf(File.separator)+1); filename = FilenameUtils.getName(filename); // 效果同上 } // 解決文件同名的問題 filename = UUID.randomUUID() + "_" + filename; // 目錄打散 // String childDirectory = makeChildDirectory(storeDirectory); // // 2015-10-19 String childDirectory = makeChildDirectory(storeDirectory, filename); // a/b // 上傳文件,自動刪除臨時文件 fileitem.write( new File(storeDirectory, childDirectory + File.separator + filename)); fileitem.delete(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } // 上傳表單項 private void processUploadField1(FileItem fileitem) { try { // 得到文件輸入流 InputStream is = fileitem.getInputStream(); // 創建一個文件存盤的目錄 String directoryRealPath = this .getServletContext().getRealPath( "/WEB-INF/upload" ); File storeDirectory = new File(directoryRealPath); // 即代表文件又代表目錄 if (!storeDirectory.exists()) { storeDirectory.mkdirs(); // 創建一個指定的目錄 } // 得到上傳的名子 String filename = fileitem.getName(); // 文件項中的值 F:\圖片素材\小清新\43.jpg 或者 // 43.jpg // 處理文件名 /* * 解決此問題: F:\\apache-tomcat-7.0.52\\webapps\\day18_00_upload\\upload\\F:\\圖片素材\\小清新\\41.jpg */ if (filename != null) { // filename = // filename.substring(filename.lastIndexOf(File.separator)+1); filename = FilenameUtils.getName(filename);// 效果同上 } // 解決文件同名的問題 filename = UUID.randomUUID() + "_" + filename; // 目錄打散 // String childDirectory = makeChildDirectory(storeDirectory); // // 2015-10-19 String childDirectory = makeChildDirectory(storeDirectory, filename); // 2015-10-19 // 在storeDirectory下,創建完整目錄下的文件 File file = new File(storeDirectory, childDirectory + File.separator + filename); // 絕對目錄/日期目錄/文件名 // 通過文件輸出流將上傳的文件保存到磁盤 FileOutputStream fos = new FileOutputStream(file); int len = 0; byte[] b = new byte[1024]; while ((len = is.read(b)) != -1) { fos.write(b, 0, len); } fos.close(); is.close(); fileitem.delete(); } catch (IOException e) { e.printStackTrace(); } } // 目錄打散 private String makeChildDirectory(File storeDirectory, String filename) { int hashcode = filename.hashCode();// 返回字符轉換的32位hashcode碼 System.out.println(hashcode); String code = Integer.toHexString(hashcode); // 把hashcode轉換為16進制的字符 // abdsaf2131safsd System.out.println(code); String childDirectory = code.charAt(0) + File.separator + code.charAt(1); // a/b // 創建指定目錄 File file = new File(storeDirectory, childDirectory); if (!file.exists()) { file.mkdirs(); } return childDirectory; } // 按日期打散 /* * private String makeChildDirectory(File storeDirectory) { * * SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd"); String * dateDirectory = sdf.format(new Date()); //只管創建目錄 File file = new * File(storeDirectory,dateDirectory); if(!file.exists()){ file.mkdirs(); } * * return dateDirectory; } */ // 普通表單項 private void processFormField(FileItem fileitem) { try { String fieldname = fileitem.getFieldName(); // 字段名 String fieldvalue = fileitem.getString( "UTF-8" ); // 字段值 //fieldvalue = new String(fieldvalue.getBytes("iso-8859-1"),"utf-8"); System.out.println(fieldname + "=" + fieldvalue); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
5、動態添加多個文件上傳 jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<script type= "text/javascript" > function addFile(){ //得到div容器 var div1 = document.getElementById( "div1" ); div1.innerHTML += "<div><input type='file' name='photo' /><input type='button' value='刪除' onclick='delFile(this)'/><br /></div>" ; } function delFile(input){ //使用input對象的爺爺刪除他的爸爸 input.parentNode.parentNode.removeChild(input.parentNode); } </script> <body> <form enctype= "multipart/form-data" action= "${pageContext.request.contextPath }/servlet/uploadServlet2" method= "post" > <input type= "text" name= "name" /><br /> <div id= "div1" > <div> <input type= "file" name= "photo" /><input type= "button" value= "添加" onclick= "addFile()" /><br /> </div> </div> <input type= "submit" value= "上傳" /><br /> </form> </body> |
6、下載文件
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
|
public class DownloadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //設置一個要下載的文件 String filename = "銷售榜單.csv" ; //設置文件名的編碼 if (request.getHeader( "user-agent" ).toLowerCase().contains( "msie" )){ filename = URLEncoder.encode(filename, "UTF-8" ); //將不安全的文件名改為UTF-8格式 } else { filename = new String(filename.getBytes( "UTF-8" ), "iso-8859-1" ); //火狐瀏覽器 } //告知瀏覽器要下載文件 response.setHeader( "content-disposition" , "attachment;filename=" +filename); //response.setHeader("content-type", "image/jpeg"); response.setContentType( this .getServletContext().getMimeType(filename)); //根據文件名自動獲得文件類型 response.setCharacterEncoding( "UTF-8" ); //告知服務器使用什么編碼 //創建一個文件輸出流 PrintWriter out = response.getWriter(); out.write( "電視機,20\n" ); out.write( "洗衣機,10\n" ); out.write( "冰箱,8\n" ); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
以上所述是小編給大家介紹的JavaWeb 文件的上傳和下載功能簡單實現代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!