JavaWeb实现文件上传下载功能实例解析

http://www.jb51.net/article/70543.htm

JavaWeb实现文件上传下载功能实例解析

作者:孤傲苍狼 字体:[增加 减小] 类型:转载 时间:2015-08-04 我要评论

这篇文章主要介绍了JavaWeb中的文件上传和下载功能的实现,在Web应用系统开发中,文件上传和下载功能是非常常用的功能,需要的朋友可以参考下
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。

  对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

一、开发环境搭建

  创建一个FileUploadAndDownLoad项目,加入Apache的commons-fileupload文件上传组件的相关Jar包,如下图所示:

  

二、实现文件上传

2.1、文件上传页面和消息提示页面

upload.jsp页面的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language= "java" pageEncoding= "UTF-8" %>
 
   文件上传
 
  
 
  
"${pageContext.request.contextPath}/servlet/UploadHandleServlet" enctype= "multipart/form-data" method= "post" >
     上传用户: "text" name= "username" >
     上传文件1: "file" name= "file1" >
     上传文件2: "file" name= "file2" >
     "submit" value= "提交" >
  
 

message.jsp的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
<%@ page language= "java" pageEncoding= "UTF-8" %>
 
   消息提示
 
  
 
     ${message}
 

2.2、处理文件上传的Servlet

UploadHandleServlet的代码如下:

?
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
package me.gacl.web.controller;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
 
public class UploadHandleServlet extends HttpServlet {
 
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = this .getServletContext().getRealPath( "/WEB-INF/upload" );
File file = new File(savePath);
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath+ "目录不存在,需要创建" );
//创建目录
file.mkdir();
}
//消息提示
String message = "" ;
try {
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解决上传文件名的中文乱码
upload.setHeaderEncoding( "UTF-8" );
//3、判断提交上来的数据是否是上传表单的数据
if (!ServletFileUpload.isMultipartContent(request)){
//按照传统方式获取数据
return ;
}
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List集合,每一个FileItem对应一个Form表单的输入项
List list = upload.parseRequest(request);
for (FileItem item : list){
//如果fileitem中封装的是普通输入项的数据
if (item.isFormField()){
String name = item.getFieldName();
//解决普通输入项的数据的中文乱码问题
String value = item.getString( "UTF-8" );
//value = new String(value.getBytes("iso8859-1"),"UTF-8");
System.out.println(name + "=" + value);
} else { //如果fileitem中封装的是上传文件
//得到上传的文件名称,
String filename = item.getName();
System.out.println(filename);
if (filename== null || filename.trim().equals( "" )){
continue ;
}
//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
//处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename = filename.substring(filename.lastIndexOf( "\\" )+ 1 );
//获取item中的上传文件的输入流
InputStream in = item.getInputStream();
//创建一个文件输出流
FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
//创建一个缓冲区
byte buffer[] = new byte [ 1024 ];
//判断输入流中的数据是否已经读完的标识
int len = 0 ;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while ((len=in.read(buffer))> 0 ){
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
out.write(buffer, 0 , len);
}
//关闭输入流
in.close();
//关闭输出流
out.close();
//删除处理文件上传时生成的临时文件
item.delete();
message = "文件上传成功!" ;
}
}
} catch (Exception e) {
message= "文件上传失败!" ;
e.printStackTrace();
 
}
request.setAttribute( "message" ,message);
request.getRequestDispatcher( "/message.jsp" ).forward(request, response);
}
 
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
 
doGet(request, response);
}
}

在Web.xml文件中注册UploadHandleServlet

?
1
2
3
4
5
6
7
8
9
< servlet >
< servlet-name >UploadHandleServlet servlet-name >
< servlet-class >me.gacl.web.controller.UploadHandleServlet servlet-class >
servlet >
 
< servlet-mapping >
< servlet-name >UploadHandleServlet servlet-name >
< url-pattern >/servlet/UploadHandleServlet url-pattern >
servlet-mapping >

运行效果如下:

  

文件上传成功之后,上传的文件保存在了WEB-INF目录下的upload目录,如下图所示:

  

2.3、文件上传的细节

  上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的

  1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

  2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

  3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。

  4、要限制上传文件的最大值。

  5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

  针对上述提出的5点细节问题,我们来改进一下UploadHandleServlet,改进后的代码如下:


?
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package me.gacl.web.controller;
   
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.List;
  import java.util.UUID;
 
  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.FileUploadBase;
  import org.apache.commons.fileupload.ProgressListener;
  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  import org.apache.commons.fileupload.servlet.ServletFileUpload;
  
  /**
  * @ClassName: UploadHandleServlet
  * @Description: TODO(这里用一句话描述这个类的作用)
  * @author: 孤傲苍狼
  * @date: 2015-1-3 下午11:35:50
  *
  */
  public class UploadHandleServlet extends HttpServlet {
  
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
          //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
          String savePath = this .getServletContext().getRealPath( "/WEB-INF/upload" );
          //上传时生成的临时文件保存目录
          String tempPath = this .getServletContext().getRealPath( "/WEB-INF/temp" );
          File tmpFile = new File(tempPath);
          if (!tmpFile.exists()) {
            //创建临时目录
            tmpFile.mkdir();
          }
          
          //消息提示
          String message = "" ;
          try {
            //使用Apache文件上传组件处理文件上传步骤:
            //1、创建一个DiskFileItemFactory工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
            factory.setSizeThreshold( 1024 * 100 ); //设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
            //设置上传时生成的临时文件的保存目录
            factory.setRepository(tmpFile);
            //2、创建一个文件上传解析器
            ServletFileUpload upload = new ServletFileUpload(factory);
            //监听文件上传进度
            upload.setProgressListener( new ProgressListener(){
              public void update( long pBytesRead, long pContentLength, int arg2) {
                System.out.println( "文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
                /**
                 * 文件大小为:14608,当前已处理:4096
                  文件大小为:14608,当前已处理:7367
                  文件大小为:14608,当前已处理:11419
                  文件大小为:14608,当前已处理:14608
                 */
              }
            });
             //解决上传文件名的中文乱码
            upload.setHeaderEncoding( "UTF-8" );
            //3、判断提交上来的数据是否是上传表单的数据
            if (!ServletFileUpload.isMultipartContent(request)){
              //按照传统方式获取数据
              return ;
            }
            
            //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
            upload.setFileSizeMax( 1024 * 1024 );
            //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
            upload.setSizeMax( 1024 * 1024 * 10 );
            //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List集合,每一个FileItem对应一个Form表单的输入项
            List list = upload.parseRequest(request);
            for (FileItem item : list){
              //如果fileitem中封装的是普通输入项的数据
              if (item.isFormField()){
                String name = item.getFieldName();
                //解决普通输入项的数据的中文乱码问题
                String value = item.getString( "UTF-8" );
                //value = new String(value.getBytes("iso8859-1"),"UTF-8");
                System.out.println(name + "=" + value);
              } else { //如果fileitem中封装的是上传文件
                //得到上传的文件名称,
                String filename = item.getName();
                System.out.println(filename);
                if (filename== null || filename.trim().equals( "" )){
                  continue ;
                }
                //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
                //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
                filename = filename.substring(filename.lastIndexOf( "\\" )+ 1 );
                //得到上传文件的扩展名
                String fileExtName = filename.substring(filename.lastIndexOf( "." )+ 1 );
                //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
                System.out.println( "上传的文件的扩展名是:" +fileExtName);
                //获取item中的上传文件的输入流
                InputStream in = item.getInputStream();
                //得到文件保存的名称
                String saveFilename = makeFileName(filename);
                //得到文件的保存目录
                String realSavePath = makePath(saveFilename, savePath);
                //创建一个文件输出流
                FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);
               //创建一个缓冲区
                byte buffer[] = new byte [ 1024 ];
                //判断输入流中的数据是否已经读完的标识               int len = 0;
                //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
                while ((len=in.read(buffer))> 0 ){
                  //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
                  out.write(buffer, 0 , len);
                }
                //关闭输入流
                in.close();
                //关闭输出流
                out.close();               //删除处理文件上传时生成的临时文件               //item.delete();               message = "文件上传成功!";
              }
            }
          } catch (FileUploadBase.FileSizeLimitExceededException e) {
            e.printStackTrace();
            request.setAttribute( "message" , "单个文件超出最大值!!!" );
            request.getRequestDispatcher( "/message.jsp" ).forward(request, response);
            return ;
          } catch (FileUploadBase.SizeLimitExceededException e) {
            e.printStackTrace();
            request.setAttribute( "message" , "上传文件的总的大小超出限制的最大值!!!" );
            request.getRequestDispatcher( "/message.jsp" ).forward(request, response);
            return ;
          } catch (Exception e) {
            message= "文件上传失败!" ;
            e.printStackTrace();
          }
          request.setAttribute( "message" ,message);
          request.getRequestDispatcher( "/message.jsp" ).forward(request, response);
   

你可能感兴趣的:(java)