文件的上传和下载
一、文件的上传
实现步骤
写一个可以发送请求的jsp等前端资源页面
-
前端jsp中form标签中记得设置enctype,并且post请求(get有长度限制)
代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
enctype就是encodetype就是编码类型的意思。
multipart/form-data是指表单数据有多部分构成,既有文本数据,又有文件等二进制数据的意思。
默认情况下是application/x-www-form-urlencoded
-
配置对应servlet
代码:
public class UpLoadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("文件上传过来了啊");
ServletInputStream is = req.getInputStream();
byte[] buffer = new byte[1024000];
int read = is.read(buffer);
// read返回的是读取流的长度
// 将inputStream中的流数据加载入byte数组buffer中
System.out.println(new String(buffer,0,read));
}
}
关于上传的Http协议的介绍
使用文件解析的相关依赖
apache下的commons-fileupload.jar
导入jar包
使用jar包提供的方法即可
-
具体方法和类
类:
ServletFileUpload类,用于解析上传的数据
FileItem类,表示每一个表单项
方法:
boolean ServletUpload.isMultipartContent(HttpServletRequest req) 判断当前数据格式是否是多段数据的格式
等等.....直接截图
图1
图2
修改后的Servlet
使用步骤:
判断是否多段数据的格式(是否为multipart / form-data)
创建FileItemFactory工厂实现类
创建解析上传数据的工具类ServletFileUpload
使用工具类ServletFileUpload方法parseRequest(request)
代码实现:
package com.GeekRose.controller;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.List;
/**
* @author Joker_Dong
* @date 2021-10-9 12:54
*/
public class UpLoadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("文件上传过来了啊");
// ServletInputStream is = req.getInputStream();
// byte[] buffer = new byte[1024000];
// int read = is.read(buffer);
// read返回的是读取流的长度
// 将inputStream中的流数据加载入byte数组buffer中
if (ServletFileUpload.isMultipartContent(req)){
// 是多段数据(含文件)
// 创建FileItemFactory工厂实现类
FileItemFactory itemFactory = new DiskFileItemFactory();
// 创建用于上传解析上传数据的工具类
ServletFileUpload upload = new ServletFileUpload(itemFactory);
// 解析上传的数据 获得解析后的表单项
try {
List list = upload.parseRequest(req);
// 遍历表单项
for (FileItem fileItem : list) {
// 先判读是否是普通的表单项
if (fileItem.isFormField()){
// 普通表单项
System.out.println("表单项的name: " + fileItem.getFieldName());
// 获取value值的时候需要设置字符集
System.out.println("表单项的value: "+ fileItem.getString("UTF-8"));
}else {
// 二进制文件
System.out.println("表单项的name: " + fileItem.getFieldName());
System.out.println("上传文件的name: "+ fileItem.getName());
// 写入磁盘
fileItem.write(new File("D:\\czbk\\java io\\" + fileItem.getName()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
二、文件的下载
实现步骤
获取文件名
读取要下载的文件的内容
回传给客户端
通过响应头,告诉客户端回传的数据类型
通过响应头,告诉客户端这是用来下载的(要不直接显示了)
代码实现
package com.GeekRose.controller;
import org.apache.commons.io.IOUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Joker_Dong
* @date 2021-10-9 15:34
*/
public class DowmLoadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("-----doGet------");
// 1.获取文件名
String fileName = "abc.text";
// 2.读取文件内容
ServletContext servletContext = getServletContext();
InputStream inputStream = servletContext.getResourceAsStream("/image/" + fileName);
// byte[] buffer = new byte[1024000];
// int read = inputStream.read(buffer);
// System.out.println(new String(buffer,0,read));
// 4.告诉客户端回传的数据类型
// 先获取要下载的文件类型
String mimeType = servletContext.getMimeType("/image/" + fileName);
System.out.println("要下载的文件类型: "+mimeType);
// 后通过响应头告诉客户端文件类型
resp.setContentType(mimeType);
// 5.告诉客户端回传的数据是用来下载的
resp.setHeader("Content-Disposition","attachment; filename="+fileName);
// 获取响应的输出流
ServletOutputStream outputStream = resp.getOutputStream();
// 3.把下载的内容回传给客户端
// 读取输入流中的数据 复制给输出流
IOUtils.copy(inputStream,outputStream);
}
}
MIME:数据类型的字符串描述符
效果图:
记录:一直报错服务器500 空指针
原因:下载的图片太大了,不能使用get来下载
通过POST下载图片(数据流长度没有限制了)
/download
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.获取文件名
// String filename = "kristen.jpg";
String filename = req.getParameter("filename");
System.out.println(filename);
// 2.读取文件
ServletContext servletContext = getServletContext();
// 读取文件
InputStream inputStream = servletContext.getResourceAsStream("/image/" + filename);
// 4.通过请求头 告诉浏览器回传数据的类型
String mimeType = servletContext.getMimeType("/image/" + filename);
resp.setContentType(mimeType);
// 5.通过请求头 告诉浏览器这个数据是用来下载的
resp.setHeader("Content-Disposition","attachment; filename="+filename);
// 3.回传数据
IOUtils.copy(inputStream,resp.getOutputStream());
}
download.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
下载文件
三、细节
编码问题
当我们使用传输的请求头信息中文件名设置为中文时,会出现乱码或不显示问题,因为http协议不支持中文,这里我们需要手动转换字符集
resp.setHeader("Content-Disposition","attachment; filename=女神.jpg");
效果图:
当我们手动转换字符集后:
resp.setHeader("Content-Disposition","attachment; filename="+ URLEncoder.encode("女神.jpg","UTF-8"));
效果图:
将中文转换成16进制 %xxx%xxx的形式
方案二:
IE和Google用的URL编码,火狐使用的是BASE64编码,使用BASE64的编码和解码操作。
代码:
public class Base64Test {
public static void main(String[] args) throws IOException {
String content = "这是需要Base64编码的内容";
// 1.创建编码器
BASE64Encoder base64Encoder = new BASE64Encoder();
// 2.编码操作
String encode = base64Encoder.encode(content.getBytes("UTF-8"));
System.out.println(encode);
// 3.创建解码器
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(encode);
System.out.println(new String(bytes));
}
}
显示结果:
6L+Z5piv6ZyA6KaBQmFzZTY057yW56CB55qE5YaF5a65
这是需要Base64编码的内容
使用Base64解决火狐浏览器的中文乱码问题
如果是火狐使用Base64 不是火狐使用URL编码
如何判断当前的浏览器名称?
通过请求头信息中的User-Agent字段是否含有Firefox
if (req.getHeader("User-Agent").contains("Firefox")){
resp.setHeader("Content-Disposition","attachment; filename==?UTF-8?B?"+ new BASE64Encoder().encode("女神.jpg".getBytes("UTF-8")) +"?=");
}else {
resp.setHeader("Content-Disposition","attachment; filename="+ URLEncoder.encode("女神.jpg","UTF-8"));
}
在判断过后,所有浏览器就都可以解决中文乱码问题(IE、Google、Firefox)