一、文件上传需要注意的事情
1、必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
2、必须把form的enctype属值设为multipart/form-data.设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
二、传统的方式获取表单提交的数据
1 public void doGet(HttpServletRequest request, HttpServletResponse response)
2 throws ServletException, IOException {
3 String name = request.getParameter("username");
4
5 /* //null 当enctype="multipart/form-data" 不能用传统的方式获取数据
6 System.out.println(name);
7 */
8
9 InputStream in = request.getInputStream();
10 int len = 0;
11 byte buffer[] = new byte[1024];
12 while((len=in.read(buffer))>0){
13 System.out.println(new String(buffer,0,len));
14 }
15
16 /*------WebKitFormBoundary6hYLK68ivBSHvVww
17 Content-Disposition: form-data; name="username"
18
19 name
20 ------WebKitFormBoundary6hYLK68ivBSHvVww
21 Content-Disposition: form-data; name="file1"; filename="aa.txt"
22 Content-Type: text/plain
23
24 bbbbbb
25 ------WebKitFormBoundary6hYLK68ivBSHvVww
26 Content-Disposition: form-data; name="file2"; filename="bb.txt"
27 Content-Type: text/plain
28
29 bbbb
30 ------WebKitFormBoundary6hYLK68ivBSHvVww--*/
31
32 //由此可见, 当enctype="multipart/form-data" 用传统的方式无法解析
33 }
34
35 public void doPost(HttpServletRequest request, HttpServletResponse response)
36 throws ServletException, IOException {
37 doGet(request, response);
38 }
39
40 }
三、Commons-fileupload组件实现文件上传
fileupload工作流程图:
Commons-fileupload依赖的jar包:Commons-fileupload和commons-io
1 //处理上传数据
2 public class UploadServlet1 extends HttpServlet {
3
4 public void doGet(HttpServletRequest request, HttpServletResponse response)
5 throws ServletException, IOException {
6 try{
7 //创建工厂对象
8 DiskFileItemFactory factory = new DiskFileItemFactory();
9 ServletFileUpload upload = new ServletFileUpload(factory);
10 //解析
11 List<FileItem>list = upload.parseRequest(request);
12 for(FileItem item : list){
13 if(item.isFormField()){//普通输入项
14 String inputName = item.getFieldName();
15 String inputValue = item.getString();
16 System.out.println(inputName+"="+inputValue);
17 }else{
18 //代表item封装的是上传文件
19 String fileName = item.getName().substring(item.getName().lastIndexOf("\")+1);
20 InputStream in = item.getInputStream();
21 FileOutputStream out = new FileOutputStream("d:\"+fileName);
22 int len = 0;
23 byte buffer[] = new byte[1024];
24 while((len=in.read(buffer))>0){
25 out.write(buffer,0, len);
26 }
27 in.close();
28 out.close();
29 }
30 }
31
32 }catch(Exception e){
33 throw new RuntimeException();
34 }
35 }
36
37
38 public void doPost(HttpServletRequest request, HttpServletResponse response)
39 throws ServletException, IOException {
40 doGet(request, response);
41 }
42
43 }
四、文件上传需要注意的问题
1、上传文件的中文乱码
解决上传文件的乱码
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
解决普通输入项的乱码(注意,表单类型为multipart/form-data的时候,设置request的编码是无效的)
String inputValue = item.getString("UTF-8");或
String inputValue = item.getString();
inputValue = new String(inputValue.getBytes("iso8859-1"), "UTF-8");
2、处理表单时先判断表单的类型
1 if(!upload.isMultipartContent(request)){//表单不是multipart/form-data类型按传统方式获取数据
2 String username = request.getParameter("username");
3 return;
4 }
3、设置解析器缓冲区的大小,以及临时文件的删除
//创建工厂对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置缓冲区大小
factory.setSizeThreshold(1024*1024);
//设置临时目录
factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
临时文件的删除:在程序中处理完上传文件后,一定要记得调用item.delete()方法,以删除临时文件,而且是在流关闭后再删除
in.close();
out.close();
//删除临时文件目录
item.delete();
4、在做上传系统时,千万要注意上传文件的保存目录,这个上传文件的保存目录绝对不能让外界直接访问到。应该放在WEB-INF目录下
5、限制上传文件的类型
List types = Arrays.asList("jpg","gif","avi","txt");
String ext = filename.substring(filename.lastIndexOf(".")+1);
if(!types.contains(ext)){
request.setAttribute("message", "本系统不支持" + ext + "这种类型");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
6、限制上传文件的大小
upload.setFileSizeMax(1024*1024*5);
调用解析器的setFileSizeMax(1024*1024*5);就可以限制上传文件的大小,如果上传文件超出限制,则解析器会抛FileUploadBase.FileSizeLimitExceededException异常,程序员通过是否抓到这个异常,进而就可以给用户友好提示。
7、判断空的上传输入项
String fileName = item.getName().substring(item.getName().lastIndexOf("\")+1);
if(fileName==null || fileName.trim().equals("")){
continue;
}
8、为避免上传文件的覆盖,程序在保存上传文件时,要为每一个文件生成一个唯一的文件名
public static String generateFileName(String fileName){
return UUID.randomUUID()+"_"+fileName;
}
9、为避免在一个文件夹下面保存超过1000个文件,影响文件访问性能,程序应该把上传文件打散后存储。
1 public String generateSavePath(String path,String filename){
2 int hashcode = filename.hashCode(); //121221
3 int dir1 = hashcode&15;
4 int dir2 = (hashcode>>4)&0xf;
5
6 String savepath = path + File.separator + dir1 + File.separator + dir2;
7 File file = new File(savepath);
8 if(!file.exists()){
9 file.mkdirs();
10 }
11 return savepath;
12 }
10、监听上传进度
1 ServletFileUpload upload = new ServletFileUpload(factory);
2 upload.setProgressListener(new ProgressListener(){
3 public void update(long pBytesRead, long pContentLength, int pItems) {
4 System.out.println("当前已解析:" + pBytesRead);
5 }
6 });
1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.util.Arrays;
6 import java.util.List;
7 import java.util.UUID;
8
9 import javax.servlet.ServletException;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13
14 import org.apache.commons.fileupload.FileItem;
15 import org.apache.commons.fileupload.FileUploadBase;
16 import org.apache.commons.fileupload.ProgressListener;
17 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
18 import org.apache.commons.fileupload.servlet.ServletFileUpload;
19
20 public class UploadServlet extends HttpServlet {
21
22 public void doGet(HttpServletRequest request, HttpServletResponse response)
23 throws ServletException, IOException {
24
25 List types = Arrays.asList("jpg","gif","avi","txt");
26
27 try{
28 DiskFileItemFactory factory = new DiskFileItemFactory(); //10k
29 factory.setSizeThreshold(1024*1024);
30 factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
31
32 ServletFileUpload upload = new ServletFileUpload(factory);
33 upload.setProgressListener(new ProgressListener(){
34 public void update(long pBytesRead, long pContentLength, int pItems) {
35 System.out.println("当前已解析:" + pBytesRead);
36 }
37 });
38
39 upload.setFileSizeMax(1024*1024*5);
40 if(!upload.isMultipartContent(request)){
41 //按照传统方式获取表单数据
42 request.getParameter("username");
43 return;
44 }
45 upload.setHeaderEncoding("UTF-8");
46 List<FileItem> list = upload.parseRequest(request);
47
48 for(FileItem item : list){
49 if(item.isFormField()){
50 //为普通输入项
51 String inputName = item.getFieldName();
52 String inputValue = item.getString("UTF-8");
53 //inputValue = new String(inputValue.getBytes("iso8859-1"),"UTF-8");
54 System.out.println(inputName + "=" + inputValue);
55 }else{
56 String filename = item.getName().substring(item.getName().lastIndexOf("\")+1); //""
57 if(filename==null || filename.trim().equals("")){
58 continue;
59 }
60
61 /*String ext = filename.substring(filename.lastIndexOf(".")+1);
62 if(!types.contains(ext)){
63 request.setAttribute("message", "本系统不支持" + ext + "这种类型");
64 request.getRequestDispatcher("/message.jsp").forward(request, response);
65 return;
66 }*/
67 InputStream in = item.getInputStream();
68 int len = 0;
69 byte buffer[] = new byte[1024];
70 String saveFileName = generateFileName(filename);
71 String savepath = generateSavePath(this.getServletContext().getRealPath("/WEB-INF/upload"),saveFileName);
72 FileOutputStream out = new FileOutputStream(savepath + File.separator + saveFileName);
73 while((len=in.read(buffer))>0){
74 out.write(buffer, 0, len);
75 }
76 in.close();
77 out.close();
78 item.delete(); //删除临时文件
79 }
80 }
81 }catch (FileUploadBase.FileSizeLimitExceededException e) {
82 request.setAttribute("message", "文件大小不能超过5m");
83 request.getRequestDispatcher("/message.jsp").forward(request, response);
84 return;
85 }catch (Exception e) {
86 throw new RuntimeException(e);
87 }
88 request.setAttribute("message", "上传成功!!");
89 request.getRequestDispatcher("/message.jsp").forward(request, response);
90 }
91
92 //
93 public String generateSavePath(String path,String filename){
94 int hashcode = filename.hashCode(); //121221
95 int dir1 = hashcode&15;
96 int dir2 = (hashcode>>4)&0xf;
97
98 String savepath = path + File.separator + dir1 + File.separator + dir2;
99 File file = new File(savepath);
100 if(!file.exists()){
101 file.mkdirs();
102 }
103 return savepath;
104 }
105
106 public String generateFileName(String filename){
107 //83434-83u483-934934
108 return UUID.randomUUID().toString() + "_" + filename;
109 }
110
111 public void doPost(HttpServletRequest request, HttpServletResponse response)
112 throws ServletException, IOException {
113 doGet(request, response);
114 }
115
116 }
三、在web页面动态添加输入项
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2
3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4 <html>
5 <head>
6 <title>My JSP 'upload2.jsp' starting page</title>
7 </head>
8
9 <script type="text/javascript">
10 function addfile(){
11 var files = document.getElementById("files");
12
13 var input = document.createElement("input");
14 input.type='file';
15 input.name='file';
16
17 var btn = document.createElement("input");
18 btn.type = 'button';
19 btn.value = '删除';
20 btn.onclick = function del(){
21 this.parentNode.parentNode.removeChild(this.parentNode);
22 }
23
24 var div = document.createElement("div");
25 div.appendChild(input);
26 div.appendChild(btn);
27
28 files.appendChild(div);
29 }
30
31 </script>
32
33 <body>
34
35 <form action="/day18/servlet/UploadServlet3" enctype="multipart/form-data" method="post">
36
37 <table>
38 <tr>
39 <td>上传用户</td>
40 <td>
41 <input type="text" name="username">
42 </td>
43 </tr>
44
45 <tr>
46 <td>上传文件</td>
47 <td>
48 <input type="button" value="添加上传文件" onclick="addfile()">
49 </td>
50 </tr>
51
52 <tr>
53 <td></td>
54 <td>
55 <div id="files"></div>
56 </td>
57 </tr>
58
59 <tr>
60 <td></td>
61 <td>
62 <input type="submit" value="上传">
63 </td>
64 </tr>
65
66 </table>
67 </form>
68
69
70 </body>
71 </html>