导入相关支持jar包:commons-fileupload.jar,commons-io.jar

对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。因为我是用的maven管理项目,所以要在pom文件中配置(每个人的jar包位置根据实际情况定)
XML代码
    <dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency> <dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>

实现文件上传

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

upload.jsp
<%--
Created by IntelliJ IDEA.
User: Eric Lan
Date: 2019/2/16
Time: 10:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/Servlet/UploadhandleServlrt" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"> <br/>
上传文件1:<input type="file" name="file1" id="file1"><br/>
上传文件2:<input type="file" name="file2" id="file2"><br/>
<input type="submit" value="上传">
</form>
</body>
</html>
message.jsp
<%--
Created by IntelliJ IDEA.
User: Eric Lan
Date: 2019/2/16
Time: 10:30
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>消息提示</title>
</head>
<body>
${message}
</body>
</html>

处理文件上传的Servlet

package com.demo;

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; import java.io.InputStream; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.UUID; /**
* describe:
*
* @author Eric Lan
* @date 2019/02/16/10:34
*/
public class UploadHandleServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
//上传时生成的临时文件保存目录
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File tempfile = new File(tempPath);
if (!tempfile.exists() && !tempfile.isDirectory()) {
System.out.println(savePath + "目录不存在,需要创建!");
//创建临时目录
tempfile.mkdir();
}
//消息提示
String message = "";
try {
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
factory.setSizeThreshold(1024 * 100);
//设置上传时生成的临时文件的保存目录
factory.setRepository(tempfile);
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件上传进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long l, long l1, int i) {
System.out.println("文件大小为:" + l1 + ",当前已处理:" + l);
}
});
//解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
//3、判断提交上来的数据是否是上传表单的数据
if (!ServletFileUpload.isMultipartContent(req)) {
//按照传统方式获取数据
return;
}
//设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
upload.setFileSizeMax(1024 * 1024);
//设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
upload.setSizeMax(1024 * 1024 * 10);
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(req);
for (FileItem item : list) {
//如果fileitem中封装的是普通输入项的数据
if (item.isFormField()) {
String name = item.getFieldName();
//解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
System.out.println(name + " = " + value);
} else {
//如果fileitem中封装的是上传文件
//得到上传的文件名称
String filename = item.getName();
System.out.println(filename);
if (filename == null || filename.trim().equals("")) {
continue;
}
filename = filename.substring(filename.lastIndexOf("\\") + 1);
//得到上传文件的扩展名,如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
String fileTye = filename.substring(filename.lastIndexOf(".") + 1);
System.out.println("上传文件的拓展名是: " + fileTye);
//获取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) {
message = "单个文件超出最大值!!!";
e.printStackTrace();
req.setAttribute("message", message);
req.getRequestDispatcher("/message.jsp").forward(req, resp);
return;
} catch (FileUploadBase.SizeLimitExceededException e) {
message = "上传文件的总的大小超出限制的最大值!!!";
e.printStackTrace();
req.setAttribute("message", message);
req.getRequestDispatcher("/message.jsp").forward(req, resp);
return;
} catch (Exception e) {
message = "文件上传失败!";
e.printStackTrace();
}
req.setAttribute("message", message);
req.getRequestDispatcher("/message.jsp").forward(req, resp); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
} /**
* 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
* @param filename
* @return
*/
private String makeFileName(String filename) {
return UUID.randomUUID().toString() + "_" + filename;
} /**
* 为防止一个目录下面出现太多文件,要使用hash算法打散存储
* @param filename
* @param filePath
* @return
*/
private String makePath(String filename, String filePath) {
int hashcode = filename.hashCode();
int dir1 = hashcode & 0xf;
int dir2 = (hashcode&0xf0) >> 4;
String dir = filePath + "\\" + dir1 + "\\" + dir2;
File file = new File(dir);
if (!file.exists()) {
file.mkdirs();
}
return dir;
}
}

文件上传细节

1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。
4、要限制上传文件的最大值。
5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

在Web.xml文件中配置UploadHandleServlet

   <servlet>
<servlet-name>UploadhandleServlrt</servlet-name>
<servlet-class>com.demo.UploadHandleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadhandleServlrt</servlet-name>
<url-pattern>/Servlet/UploadhandleServlrt</url-pattern>
</servlet-mapping>

文件下载

列出提供下载的文件资源

package com.demo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map; /**
* describe:
*
* @author Eric Lan
* @date 2019/02/16/16:27
*/
public class ListFileServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
Map<String, String> fileNameMap = new HashMap<String, String>();
listfile(new File(uploadFilePath), fileNameMap);
req.setAttribute("fileNameMap", fileNameMap);
req.getRequestDispatcher("/listfile.jsp").forward(req, resp);
} public void listfile(File file, Map<String, String> map) {
if (!file.isFile()) {
File files[] = file.listFiles();
for (File f : files) {
listfile(f, map);
}
} else {
String realName = file.getName().substring(file.getName().indexOf("_") + 1);
map.put(file.getName(), realName);
}
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
简单说一下ListFileServlet中listfile方法,listfile方法是用来列出目录下的所有文件的,listfile方法内部用到了递归,在实际开发当中,我们肯定会在数据库创建一张表,里面会存储上传的文件名以及文件的具体存放目录,我们通过查询表就可以知道文件的具体存放目录,是不需要用到递归操作的,这个例子是因为没有使用数据库存储上传的文件名和文件的具体存放位置,而上传文件的存放位置又使用了散列算法打散存放,所以需要用到递归,在递归时,将获取到的文件名存放到从外面传递到listfile方法里面的Map集合当中,这样就可以保证所有的文件都存放在同一个Map集合当中。

实现文件下载

package com.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* describe:
*
* @author Eric Lan
* @date 2019/02/16/17:05
*/ public class DownLoadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到要下载的文件名
String fileName = request.getParameter("filename");
fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
//上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
//通过文件名找出文件的所在目录
String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
//得到要下载的文件
File file = new File(path + "\\" + fileName);
//如果文件不存在
System.out.println(file);
if(!file.exists()){
request.setAttribute("message", "您要下载的资源已被删除!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
//处理文件名
String realname = fileName.substring(fileName.indexOf("_")+1);
//设置响应头,控制浏览器下载该文件
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
//读取要下载的文件,保存到文件输入流
FileInputStream in = new FileInputStream(path + "\\" + fileName);
//创建输出流
OutputStream out = response.getOutputStream();
//创建缓冲区
byte buffer[] = new byte[1024];
int len = 0;
//循环将输入流中的内容读取到缓冲区当中
while((len=in.read(buffer))>0){
//输出缓冲区的内容到浏览器,实现文件下载
out.write(buffer, 0, len);
}
//关闭文件输入流
in.close();
//关闭输出流
out.close();
} /**
* @Method: findFileSavePathByFileName
* @Description: 通过文件名和存储上传文件根目录找出要下载的文件的所在路径
* @param filename 要下载的文件名
* @param saveRootPath 上传文件保存的根目录,也就是/WEB-INF/upload目录
* @return 要下载的文件的存储目录
*/
public String findFileSavePathByFileName(String filename,String saveRootPath){
int hashcode = filename.hashCode();
int dir1 = hashcode&0xf; //0--15
int dir2 = (hashcode&0xf0)>>4; //0-15
String dir = saveRootPath + "\\" + dir1 + "\\" + dir2;
File file = new File(dir);
if(!file.exists()){
//创建目录
file.mkdirs();
}
return dir;
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

展示下载文件的listfile.jsp页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML>
<html>
<head>
<title>下载文件显示页面</title>
</head> <body>
<!-- 遍历Map集合 -->
<c:forEach var="me" items="${fileNameMap}">
<c:url value="/servlet/DownLoadServlet" var="downurl">
<c:param name="filename" value="${me.key}"></c:param>
</c:url>
${me.value}<a href="${downurl}">下载</a>
<br/>
</c:forEach>
</body>
</html>

注意Maven的pom.xml文件中需要导入的两个C标签需要的包!

    <dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency> <dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>

在Web.xml文件中配置ListFileServlet和DownLoadServlet

    <servlet>
<servlet-name>ListFileServlet</servlet-name>
<servlet-class>com.demo.ListFileServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>ListFileServlet</servlet-name>
<url-pattern>/servlet/ListFileServlet</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>DownLoadServlet</servlet-name>
<servlet-class>com.demo.DownLoadServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>DownLoadServlet</servlet-name>
<url-pattern>/servlet/DownLoadServlet</url-pattern>
</servlet-mapping>

至此,JavaWeb中的文件上传和下载功能的内容大概就这么多。

JavaWeb中的文件上传和下载功能的实现的更多相关文章

  1. javaWeb中,文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  2. javaWeb中的文件上传下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  3. JavaWeb学习总结——文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  4. javaWeb学习总结——文件上传、下载

    目录 1.文件上传环境搭建 2.文件上传代码实现 3.关于下载 @ 嘿,熊dei,你不得不知道在Web开发中,文件上传和下载功能是非常常用的功能,关于文件上传,浏览器上传[文件以流的形式传输]--&g ...

  5. 使用SpringMVC框架实现文件上传和下载功能

    使用SpringMVC框架实现文件上传和下载功能 (一)单个文件上传 ①配置文件上传解释器 <!—配置文件上传解释器 --> <mvc:annotation-driven>&l ...

  6. Java中的文件上传和下载

    文件上传原理: 早期的文件上传机制: 在TCP/IP中.最早出现的文件上传机制是FTP.他是将文件由客户端发送到服务器的标准机制. jsp中的文件上传机制: 在jsp编程中不能使用FTP的方法来上传文 ...

  7. python web中的文件上传与下载

    django 框架下 实现服务端的文件上传与下载: import jsonimport osimport uuid def attachment_upload(request): "&quo ...

  8. JavaWeb -- Struts1 多文件上传与下载 DownloadAction, DispatchAction

    1. 多文件上传与下载 上传下载jsp: <%@ page language="java" import="java.util.*" pageEncodi ...

  9. 4.struts2中的文件上传,下载

    Struts2中文件的上传下载,是借用commons里面的包实现文件的上传,需要导入两个jar commons-fileupload-1.2.2.jar commons-io-2.0.1.jar 实现 ...

随机推荐

  1. setTimeout(function(){}, 0);

    for (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 0); console.log(i); } 结果 ...

  2. HTML5——web存储 Web SQL 数据库 应用程序缓存 Web Workers 服务器发送事件 WebSocket

    web存储 比cookie更好的本地存储方式 localStorage - 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去除. sessionStorage - 用于临时保存同一窗口( ...

  3. 【ABAP系列】SAP ABAP 关于BAPI的EXTENSIONIN 一点解释

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 关于BAPI的 ...

  4. 安装Git并关联

    下载git 打开git bash 生成key将 key绑定到帐号 输入命令 ssh-keygen -t rsa -C 'LoginName' 根据命令生成的地址找到对应文件复制密钥 打开github登 ...

  5. 简述在Vue脚手架中,组件以及父子组件(非父子组件)之间的传值

    1.组件的定义 组成: template:包裹HTML模板片段(反映了数据与最终呈现给用户视图之间的映射关系) 只支持单个template标签: 支持lang配置多种模板语法: script:配置Vu ...

  6. [Web 前端] 028 jQuery 事件

    目录 jQuery 的事件 1. 事件绑定 1.1 事件的获取 1.2 基本绑定 1.3 动态绑定 2. 事件触发 2.1 触发的写法 2.2 常用的鼠标事件 3. 事件冒泡和默认行为 3.1 事件冒 ...

  7. 银河麒麟v4.0.2 安装gscloud的简单过程

    1. 本来想用 tar包安装 redis 结果总是报错, 提示需要make test 但是我已经make test 了 所以还是使用 apt-get来安装. 2. 方式 apt-get update ...

  8. MySQL插入emoji表情报错 SQLException: Incorrect string value 的两种解决方案

    摘抄自:https://blog.csdn.net/dmw412724/article/details/81119325 原因:mysql的UTF-8只支持三个字节的存储,而一般字符是三个字节,但是e ...

  9. 断开ssh链接在后台继续运行命令

    转载:http://blog.csdn.net/v1v1wang/article/details/6855552 对于linux运维,我们都是使用ssh登录到服务器,如果我们运行的任务需要很长时间或不 ...

  10. navicat和Pycharm的连接

    要安装好Mysql,并且实现了Mysql和Navicat的连接: 2.连接界面如下:点击连接,然后点击MySQL就可以看到如下界面 3. 然后就出现新建连接的设置,连接名自己起,用户名和密码和在MyS ...