- 一、文件上传
- 1.1 准备工作
- 1.1.1 创建一个web项目
- 1.1.2 准备jar包
- 1.1.3 使用类介绍
- 1.1.4 常用方法
- 1.2 实现
- 1.2.1 上传页面
- 1.2.2 成功页面
- 1.2.3 上传代码
- 1.2.4 自定义方法
- 二、文件下载
- 2.1 步骤
- 2.2 代码实现
- 三、上传下载互动
- 3.1 思路
学习视频来自于:秦疆(遇见狂神说)Bilibili地址
他的自学网站:kuangstudy
我们缺乏的不是知识,而是学而不厌的态度
一、文件上传 1.1 准备工作 1.1.1 创建一个web项目
使用开发工具创建一个maven管理的web项目
1.1.2 准备jar包fileupload:jar包
commons-io:依赖jar包
1.1.3 使用类介绍commons-fileupload commons-fileupload 1.4 commons-io commons-io 2.11.0
文件上传的注意事项
- 为保证服务器安全,上传的文件存放在一个外界无法直接访问的目录下面,比如WEB-INF目录下。
- 为了防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名:使用时间戳/UUID/MD5等手段实现。
- 要限制上传文件的最大值:因为服务器上硬盘资源很贵,不能让用户随意的使用。
- 限制文件上传类型:在收到上传文件名时,判断后缀名是否合法。
ServletFileUpload类
负责处理上传的文件数据,并将表单中的每个输入项都封装为一个FileItem对象,使用其parseRequest(HttpServletRequest) 方法可以将表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回,使用该方法处理上传文件简单易用。
但是ServletFileUpload对象解析请求时需要DIskFileItemFactory对象,我们在解析工作前构造好DIskFileItemFactory,通过ServletFileUpload构造器或setFileItemFactory()方法设置ServletFileUpload对象中fileItemFactory属性。
FileItem类
在HTML页面input标签必须有name
表单如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为multipart/form-data
通过FileItem提交的数据封装成的对象,便于操作。
1.1.4 常用方法// ServletFileUpload类
// 判断上传的文件是普通表单还是带文件表单
ServletFileUpload.isMultipartContent(req);
// FileItem类
//isFormField方法用于判断FileItem类对象封装的数据是一个普通文本表单
//还是一个文件表单,如果是普通表单字段则返回true,否则返回false
boolean isFormField();//即:只要是上传的文件,返回的就是false
//getFieldName方法用于返回表单标签name字段的值。
String getFieldName();//获取这个input的name属性值
//getString方法用于将FileItem对象中保存的数据流内容以一个字符串返回
String getString();//用字符串存储文件的数据流
//getName方法用于获得文件上传字段中的文件名
String getName();
//以流的形式返回上传文件的数据内容。
InputStream getInputStream()
//delete方法用来清空FileItem类对象中存放的主体内容
//如果主体内容被保存在临时文件中,delete方法将删除该临时文件。
void delete();
1.2 实现
1.2.1 上传页面
环境配置建后,先测试页面跳转后台没问题,在开始写上传。
1.2.2 成功页面<%=request.getAttribute("msg")%>
上传成功
1.2.3 上传代码
上传不使用doGet,方法都放在doPost里面。
// 接收中文
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// 判断上传的文件是普通表单还是带文件表单
if (ServletFileUpload.isMultipartContent(req)) {
// 创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问到
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()) {
uploadFile.mkdir();//没有这个目录就创建这个目录
}
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File tmpFile = new File(tmpPath);
if (!tmpFile.exists()) {
tmpFile.mkdir();//没有这个目录就创建这个目录
}
// 处理上传文件,需要通过流来获取,可以使用request.getInputstream();但是原生十分麻烦
// 建议使用apache文件上传组件来实现,common-fileupload,它需要commons-is组件
// 创建DiskFileItemFactory对象,处理文件路径或大小限制
DiskFileItemFactory factory = this.getDiskFileItemFactory(tmpFile);
ServletFileUpload upload = this.getServletFileUpload(factory);
String msg = this.uploadParasRequest(upload, req, uploadPath);
req.setAttribute("msg", msg);
req.getRequestDispatcher("success.jsp").forward(req, resp);
} else {
return;//终止方法,不是带文件的表单
}
1.2.4 自定义方法
// 获取磁盘对象
private DiskFileItemFactory getDiskFileItemFactory(File file) {
// 1.创建DiskFileItemFactory对象,获取磁盘对象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(1024 * 1024, file);
return diskFileItemFactory;
}
//2、创建ServletFileUpload对象,获取上传文件的解析对象
private ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
// 监听文件上传速度
servletFileUpload.setProgressListener(new ProgressListener() {
//
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("百分比:" + pContentLength + "已上传:" + pBytesRead + "字段编号:" + pItems);
}
});
return servletFileUpload;
}
//3、正式解析表单中上传的文件,并将其存储在服务器上指定的位置
private String uploadParasRequest(ServletFileUpload upload, HttpServletRequest req, String uploadPath) {
ServletRequestContext context = new ServletRequestContext(req);
String msg = "";
try {
// 使用文件解析对象parseRequest,将表单中每一个input标签封装成FileItem对象
// parseRequest(HttpServletRequest) 方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回
List fileItems = upload.parseRequest(context);
for (FileItem fileItem : fileItems) {
// 遍历,找到表单中每一个文件对应的上传数据
if (fileItem.isFormField()) {
// 判断中数据不是文件
String name = fileItem.getFieldName();// 获取非文件的name属性
String value = fileItem.getString("utf-8");// 获取非文件的value属性
System.out.println(name + ":" + value);
} else {// 是文件
//===============1、处理文件:获取文上传的文件的文件名+文件类型===============
String uploadFileName = fileItem.getName();//获取这个文件的名字
if (uploadFileName.trim().equals("") || uploadFileName == null) {
//如果文件上传的名字为空
continue;// 跳过本次循环
}
// 获取上传文件名字,格式
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
System.out.println("名字:" + fileName + "格式:" + fileExtName);
//=====================2、处理文件存放地址:/WEB-INF/upload + 文件上传时生成的唯一的UUID===============
//可以使用UUID(可以唯一识别的通用码),保证文件名唯一;UUID.randomUUID(),随机生成一个唯一的识别通用码;
String uuidPath = UUID.randomUUID().toString();
String realPath = uploadPath + "/" + uuidPath;
File realPathFile = new File(realPath);
//给每个文件创建一个对应的文件夹
if (!realPathFile.exists()) {
realPathFile.mkdir();
}
//============================3、文件传输:配合工具类fileName+文件IO操作就可以实现文件存储在服务器上============================
InputStream in = null;
in = fileItem.getInputStream();
FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
// 刷新、释放流
fos.flush();
in.close();
fos.close();
msg = "上传成功";
fileItem.delete();// 上传成功,清空临时文件
}
}
} catch (FileUploadException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return msg;
}
二、文件下载
在HttpServletResponse中已经写过,这里就在重复一遍。
2.1 步骤- 要获取下载文件的路径
- 下载的文件名是啥?
- 设置想办法让浏览器能够支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获取OutputStream对象
- 将FileOutputStream流写入到bufer缓冲区
- 使用OutputStream将缓冲区中的数据输出到客户端!
// 指定浏览器字符集编码
response.setContentType("text/html;charset=UTF-8");
//1. 要获取下载文件的路径(路径中空格被替换成%20)
String path = this.getServletContext().getClassLoader().getResource("别错过(DJ阿卓版) - 程佳佳.flac").getPath();
//MIME格式解码器(将%20变成空格)
path = URLDecoder.decode(path, "UTF-8");
File file = new File(path);
System.out.println("文件路径:" + file);
//2. 获取下载文件名称,去掉中间包含的空格(MIME格式编码器会将空格变成+)
String name = path.substring(path.lastIndexOf("/") + 1).replace(" ", "");
System.out.println("文件名:" + name);
//3. 设置想办法让浏览器能够支持下载我们需要的东西
// MIME格式编码器解决浏览器中文乱码
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(name, "UTF-8"));
//4. 获取下载文件的输入流
FileInputStream fis = new FileInputStream(file);
//5. 创建缓冲区
int len = 0;
byte[] bufer = new byte[1024];
//6. 获取OutputStream对象
ServletOutputStream out = response.getOutputStream();
//7. 将FileOutputStream流写入到bufer缓冲区
while ((len = fis.read(bufer)) > 0) {
//8. 使用OutputStream将缓冲区中的数据输出到客户端!
out.write(bufer, 0, len);
}
//9.释放资源
fis.close();
out.close();
三、上传下载互动
3.1 思路
- jsp页面上传文件,servlet对文件保存,文件名、文件路径存入数据库。
- 点击jsp页面查询已保存文件,servlet查询数据库中保存的文件名、文件路径,jsp页面展示文件名,文件路径隐藏展示type=“hidden”。
- 点击文件名,数据发送servlet调用下载文件。



