JSP中文件的上传与下载示例

本文详细介绍了文件上传的基本原理,包括表单设置、请求正文结构等,并演示了使用commons-fileupload组件实现文件上传的过程。此外,还探讨了文件上传过程中需要注意的安全问题及解决方案,并给出了完整的示例代码。最后,文章还介绍了如何实现文件下载功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://www.2cto.com/kf/201406/312486.html

一、文件上传的原理

1、文件上传的前提:
a、form表单的method必须是post
b、form表单的enctype必须是multipart/form-data(决定了POST请求方式,请求正文的数据类型)
注意:当表单的enctype是multipart/form-data,传统的获取请求参数的方法失效。

请求正文:(MIME协议进行描述的,正文是多部分组成的)
-----------------------------7dd32c39803b2
Content-Disposition: form-data; name="username"

wzhting
-----------------------------7dd32c39803b2
Content-Disposition: form-data; name="f1"; filename="C:\Documents and Settings\wzhting\妗岄潰\a.txt"
Content-Type: text/plain

aaaaaaaaaaaaaaaaaa
-----------------------------7dd32c39803b2
Content-Disposition: form-data; name="f2"; filename="C:\Documents and Settings\wzhting\妗岄潰\b.txt"
Content-Type: text/plain

bbbbbbbbbbbbbbbbbbb
-----------------------------7dd32c39803b2--


c、form中提供input的type是file类型的文件上传域

二、利用第三方 组件 实现文件上传
1、commons-fileupload组件:
jar:commons-fileupload.jar commons-io.jar
2、核心类或接口
DiskFileItemFactory:设置环境
public void setSizeThreshold(int?sizeThreshold) :设置缓冲区大小。默认是10Kb。
当上传的文件超出了缓冲区大小,fileupload组件将使用临时文件缓存上传文件
public void setRepository(java.io.File repository):设置临时文件的存放目录。默认是 系统 的临时文件存放目录。

ServletFileUpload:核心上传类(主要作用:解析请求的正文内容)
boolean isMultipartContent(HttpServletRequest?request):判断用户的表单的enctype是否是multipart/form-data类型的。
List parseRequest(HttpServletRequest request):解析请求正文中的内容
setFileSizeMax(4*1024*1024);//设置单个上传文件的大小
upload.setSizeMax(6*1024*1024);//设置总文件大小
FileItem:代表表单中的一个输入域。
boolean isFormField():是否是普通字段
String getFieldName:获取普通字段的字段名
String getString():获取普通字段的值

InputStream getInputStream():获取上传字段的输入流
String getName():获取上传的文件名

三、文件上传中要注意的9个问题
1、如何保证服务器的安全
把保存上传文件的目录放到WEB-INF目录中。
2、中文乱码问题
2.1普通字段的中文请求参数
String value = FileItem.getString("UTF-8");
2.2上传的文件名是中文
解决办法:request.setCharacterEncoding("UTF-8");
3、重名文件被覆盖的问题
System.currentMillions()+"_"+a.txt(乐观)

UUID+"_"+a.txt:保证文件名唯一
4、分目录存储上传的文件
方式一:当前日期建立一个文件夹,当前上传的文件都放到此文件夹中。
方式二:利用文件名的hash码打散目录来存储。
int hashCode = fileName.hashCode();

1001 1010 1101 0010 1101 1100 1101 1010
hashCode&0xf; 0000 0000 0000 0000 0000 0000 0000 1111 &
---------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1010 取hashCode的后4位
0000~1111:整数0~15共16个

1001 1010 1101 0010 1101 1100 1101 1010
(hashCode&0xf0) 0000 0000 0000 0000 0000 0000 1111 0000 &
--------------------------------------------
0000 0000 0000 0000 0000 0000 1101 0000 >>4
--------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1101
0000~1111:整数0~15共16个
5、限制用户上传的文件类型
通过判断文件的扩展名来限制是不可取的。
通过判断其Mime类型才靠谱。FileItem.getContentType();
6、如何限制用户上传文件的大小
6.1单个文件大小限制。超出了大小友好提示
抓异常进行提示:org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException
6.2总文件大小限制。超出了大小友好提示
抓异常进行提示:org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException
7、临时文件的问题
commons-fileupload组件不会删除超出缓存的临时文件。

FileItem.delete()方法删除临时文件。但一定要在关闭流之后。
8、多个文件上传时,没有上传内容的问题
if(fileName==null||"".equals(fileName.trim())){
continue;
}
9、上传进度检测
给ServletFileUpload注册一个进度监听器即可,把上传进度传递给页面去显示
//pBytesRead:当前以读取到的字节数
//pContentLength:文件的长度
//pItems:第几项
public void update(long pBytesRead, long pContentLength,
int pItems) {
System.out.println("已读取:"+pBytesRead+",文件大小:"+pContentLength+",第几项:"+pItems);

}

四:文件上传示例:

JSP代码:

1
2
3
4
5
6
<form action= "${pageContext.request.contextPath}/servlet/UploadServlet" method= "post" enctype= "multipart/form-data" >
         用户名:<input type= "text" name= "username" ><br>
         文件 1 :<input type= "file" name= "f1" ><br>
         文件 2 :<input type= "file" name= "f2" ><br>
         <input type= "submit" value= "保存" >
     </form>


servlet后台代码:

public class UploadServlet extends HttpServlet {
 
     public void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         request.setCharacterEncoding( "UTF-8" );
         response.setContentType( "text/html;charset=UTF-8" );
         PrintWriter pout = response.getWriter();
         try {
             // 得到存放上传文件的真实路径
             String storePath = getServletContext()
                     .getRealPath( "/WEB-INF/files" );
 
             // 设置环境
             DiskFileItemFactory factory = new DiskFileItemFactory();
             factory.setRepository( new File(getServletContext().getRealPath( "/temp" ))); //设置临时存放目录
             // 判断一下form是否是enctype=multipart/form-data类型的
             boolean isMultipart = ServletFileUpload.isMultipartContent(request);
             if (!isMultipart) {
                 System.out.println( "大傻鸟" );
                 return ;
             }
             // ServletFileUpload核心类
             ServletFileUpload upload = new ServletFileUpload(factory);
//          upload.setProgressListener(new ProgressListener() {
//              //pBytesRead:当前以读取到的字节数
//              //pContentLength:文件的长度
//              //pItems:第几项
//              public void update(long pBytesRead, long pContentLength,
//                      int pItems) {
//                  System.out.println("已读取:"+pBytesRead+",文件大小:"+pContentLength+",第几项:"+pItems);
//              }
//             
//          });
             upload.setFileSizeMax( 4 * 1024 * 1024 ); // 设置单个上传文件的大小
             upload.setSizeMax( 6 * 1024 * 1024 ); // 设置总文件大小
             // 解析
             List<fileitem> items = upload.parseRequest(request);
             for (FileItem item : items) {
                 if (item.isFormField()) {
                     // 普通字段
                     String fieldName = item.getFieldName();
                     String fieldValue = item.getString( "UTF-8" );
                     System.out.println(fieldName + "=" + fieldValue);
                 } else {
                     // 得到MIME类型
                     String mimeType = item.getContentType();
                     // 只允许上传图片
                      if (mimeType.startsWith( "image" )){
                         // 上传字段
                         InputStream in = item.getInputStream();
                         // 上传的文件名
                         String fileName = item.getName(); // C:\Documents and
                         if (fileName== null || "" .equals(fileName.trim())){
                             continue ;
                         }
                         // Settings\wzhting\妗岄潰\a.txt
                         // a.txt
                         fileName = fileName
                                 .substring(fileName.lastIndexOf( "\\" ) + 1 ); // a.txt
                         fileName = UUID.randomUUID() + "_" + fileName;
                         System.out.println(request.getRemoteAddr()+ "==============" +fileName);
                         // 构建输出流
                         // 打散存储目录
                         String newStorePath = makeStorePath(storePath, fileName); // 根据
                         // /WEB-INF/files和文件名,创建一个新的存储路径
                         // /WEB-INF/files/1/12
                         String storeFile = newStorePath + "\\" + fileName; // WEB-INF/files/1/2/sldfdslf.txt
     
                         OutputStream out = new FileOutputStream(storeFile);
     
                         byte b[] = new byte [ 1024 ];
                         int len = - 1 ;
                         while ((len = in.read(b)) != - 1 ) {
                             out.write(b, 0 , len);
                         }
                         out.close();
                         in.close();
                         item.delete(); //删除临时文件
                     }
                  }
             }
         } catch (org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException e) {
             // 单个文件超出大小时的异常
             pout.write( "单个文件大小不能超出4M" );
         } catch (org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e) {
             // 总文件超出大小时的异常
             pout.write( "总文件大小不能超出6M" );
         } catch (Exception e) {
             e.printStackTrace();
         }
 
     }
 
     // 根据 /WEB-INF/files和文件名,创建一个新的存储路径 /WEB-INF/files/1/12
     private String makeStorePath(String storePath, String fileName) {
         int hashCode = fileName.hashCode();
         int dir1 = hashCode & 0xf ; // 0000~1111:整数0~15共16个
         int dir2 = (hashCode & 0xf0 ) >> 4 ; // 0000~1111:整数0~15共16个
 
         String path = storePath + "\\" + dir1 + "\\" + dir2; // WEB-INF/files/1/12
         File file = new File(path);
         if (!file.exists())
             file.mkdirs();
 
         return path;
     }
 
     public void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
 
         doGet(request, response);
     }
 
}</fileitem>

-----------------------------------------------------

五:文件下载

1.显示上述存储所有的照片信息:

?
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
//显示所有上传的文件,封装到域对象中,交给jsp去显示
public class ShowAllFilesServlet extends HttpServlet {
 
     public void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         Map<string, string= "" > map = new HashMap<string, string= "" >(); //key:UUID文件名;value:老文件名
         //得到存储文件的根目录
         String storePath = getServletContext().getRealPath( "/WEB-INF/files" );
         //递归遍历其中文件
         File file = new File(storePath);
         treeWalk(file,map);
         //交给JSP去显示:如何封装数据.用Map封装。key:UUID文件名;value:老文件名
         request.setAttribute( "map" , map);
         request.getRequestDispatcher( "/listFiles.jsp" ).forward(request, response);
     }
     //遍历/WEB-INF/files所有文件,把文件名放到map中
     private void treeWalk(File file, Map<string, string= "" > map) {
         if (file.isFile()){
             //是文件
             String uuidName = file.getName(); //  UUID_a_a.txt//真实文件名
             String oldName = uuidName.substring(uuidName.indexOf( "_" )+ 1 );
             map.put(uuidName, oldName);
         } else {
             //是一个目录
             File[] fs = file.listFiles();
             for (File f:fs){
                 treeWalk(f,map);
             }
         }
     }
 
     public void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
 
         doGet(request, response);
     }
 
}</string,></string,></string,>
2.显示所有文件listFiles.jsp页面中的内容:
?
1
2
3
4
5
6
7
<h1>本站有以下好图片</h1>
<c:foreach items= "${map}" var= "me" >
     <c:url value= "/servlet/DownloadServlet" var= "url" >
         <c:param name= "filename" value= "${me.key}" ></c:param>
     </c:url>
     ${me.value}  下载<br>
</c:foreach>
3.文件下载DownloadServlet:

?
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
public class DownloadServlet extends HttpServlet {
 
     public void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         response.setContentType( "text/html;charset=UTF-8" );
         OutputStream out = response.getOutputStream();
         
         String filename = request.getParameter( "filename" ); //get请求方式
         filename = new String(filename.getBytes( "ISO-8859-1" ), "UTF-8" ); //中文编码
         
         //截取老文件名
         String oldFileName = filename.split( "_" )[ 1 ];
         //得到存储路径
         String storePath = getServletContext().getRealPath( "/WEB-INF/files" );
         //得到文件的全部路径
         String filePath = makeStorePath(storePath, filename)+ "\\" +filename;
         
         //判断文件是否存在
         File file = new File(filePath);
         if (!file.exists()){
             out.write( "对比起!你要下载的文件可能已经不存在了" .getBytes( "UTF-8" ));
             return ;
         }
         
         InputStream in = new FileInputStream(file);
         //通知客户端以下载的方式打开
         response.setHeader( "Content-Disposition" , "attachment;filename=" +URLEncoder.encode(oldFileName, "UTF-8" ));
         
         byte [] b = new byte [ 1024 ];
         int len = - 1 ;
         while ((len=in.read(b))!=- 1 ){
             out.write(b, 0 , len);
         }
         in.close();
         out.write( "下载成功" .getBytes( "UTF-8" ));
     }
 
     public void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
 
         doGet(request, response);
     }
     private String makeStorePath(String storePath, String fileName) {
         int hashCode = fileName.hashCode();
         int dir1 = hashCode & 0xf ; // 0000~1111:整数0~15共16个
         int dir2 = (hashCode & 0xf0 ) >> 4 ; // 0000~1111:整数0~15共16个
 
         String path = storePath + "\\" + dir1 + "\\" + dir2; // WEB-INF/files/1/12
         File file = new File(path);
         if (!file.exists())
             file.mkdirs();
 
         return path;
     }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值