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 文件的上传和下载功能简单实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!