一、文件上传的原理

    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、怎样保证server的安全

        把保存上传文件的文件夹放到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代码:

<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);
} }

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

五:文件下载

1.显示上述存储全部的照片信息:

//显示全部上传的文件。封装到域对象中,交给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);
} }

2.显示全部文件listFiles.jsp页面中的内容:

<body>
<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}  <a href="${url}">下载</a><br/>
</c:forEach>
</body>

3.文件下载DownloadServlet:

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);
//通知client下面载的方式打开
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;
}
}

JSP中文件的上传于下载演示样例的更多相关文章

  1. JavaWeb中文件的上传和下载

    JavaWeb中文件的上传和下载 转自: JavaWeb学习总结(五十)——文件上传和下载 - 孤傲苍狼 - 博客园https://www.cnblogs.com/xdp-gacl/p/4200090 ...

  2. iOS开发中文件的上传和下载功能的基本实现-备用

    感谢大神分享 这篇文章主要介绍了iOS开发中文件的上传和下载功能的基本实现,并且下载方面讲到了大文件的多线程断点下载,需要的朋友可以参考下 文件的上传 说明:文件上传使用的时POST请求,通常把要上传 ...

  3. Java中文件的上传与下载

    文件的上传与下载主要用到两种方法: 1.方法一:commons-fileupload.jar  commons-io.jar apache的commons-fileupload实现文件上传,下载 [u ...

  4. 009 spring boot中文件的上传与下载

    一:任务 1.任务 文件的上传 文件的下载 二:文件的上传 1.新建一个对象 FileInfo.java package com.cao.dto; public class FileInfo { pr ...

  5. Struts中文件的上传与下载

    前面学到的用组件去上传 前台: 1.post表单提交 2.表单类型 multipart/form-data 3.intput type=file 后台: Apach提供的FileUpload组件 核心 ...

  6. Struts2中文件的上传与下载

    文件上传 1.jsp页面 <s:form action="fileAction" namespace="/file" method="POST& ...

  7. docker容器中文件的上传与下载

    原文地址:传送门 1.上传文件 docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH [OPTIONS]:保持源目标中的链接,例: docker cp ...

  8. Jsp/Servlet文件的上传和下载

    文件上传的入门 文件上传的步骤:       总结实现思路: 1.创建核心上传类ServletFileUpload,这个时候需要一个工厂类 2.创建磁盘工厂类对象DiskFileItemFactory ...

  9. 文件的上传和下载--SpringMVC

    文件的上传和下载是项目开发中最常用的功能,例如图片的上传和下载.邮件附件的上传和下载等. 接下来,将对Spring MVC环境中文件的上传和下载进行详细的讲解. 一.文件上传 多数文件上传都是通过表单 ...

随机推荐

  1. Day1下午解题报告

    预计分数:0+30+30=60 实际分数:0+30+40=70 T1水题(water) 贪心,按长度排序, 对于第一幅牌里面的,在第二个里面,找一个长度小于,高度最接近的牌 进行覆盖. 考场上的我离正 ...

  2. 用console.log分析Vue源码

    前言 本文通过console.log的一些特性,结合vue.js的源码,通过一个简单的例子,让你了解Vue的各个过程的变化. 控制台输出的效果图 请用chrome查看,并打开控制台看效果 演示地址 准 ...

  3. wget 指令学习之递归抓取文档技巧

    在线上阅读文档的时候,有没有想将它抓取到本地,以备没有网的时候阅读只需? 先上指令: $ wget --user-agent="Mozilla/5.0 (X11; Linux x86_64) ...

  4. 洛谷 P3371 【模板】单源最短路径

    P3371 [模板]单源最短路径 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出 ...

  5. 让checkbox不选中

    今天在做项目的时候.遇到一个问题.须要把选中的checkbox置空,即将选中的checkbox不选中. 最后,发现一个方法非常好使,特此记录. $("input[type='checkbox ...

  6. HDU 3487(Play with Chain-Splay)[template:Splay]

    Play with Chain Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. 数据结构基础(3)---C语言实现单链表

    #include<stdio.h> #include<malloc.h> #include<stdbool.h> /** **链表节点的定义 */ typedef ...

  8. 【剑指Offer面试题】九度OJ1384:二维数组中的查找

    下决心AC全部剑指offer面试题. 九度OJ面试题地址:http://ac.jobdu.com/hhtproblems.php 书籍:何海涛--<剑指Offer:名企面试官精讲典型编程题> ...

  9. mk-编译信息的意义

    今天第一次看Android.mk文件,内容如下 # Copyright 2007-2008 The Android Open Source Project 2 3 LOCAL_PATH:= $(cal ...

  10. 在Qt Creator的项目中添加头文件和库

    在Qt Creator中的工程中,工程通过.pro文件管理. 额外需要连接的连接库unix:LIBS += -L your_lib_path -lyour_libwin32:LIBS += your_ ...