文件的上传和下载
程序员文章站
2022-04-30 21:10:13
...
文件的上传和下载
1.1文件的上传
文件上传主要分成两个步骤:
- 用户在页面中选择要上传的文件,然后将请求提交到Servlet
- Servlet收到请求,解析用户上传的文件,然后将文件存储到服务器
1.2准备工作
表单:
- 表单的method属性必须为post
- 表单的enctype属性必须为multipart/form-data
- 上传文件的控件是input,type属性为file
导包:
- commons-fileupload.jar
- commons-io.jar
例如:
①创建一个form表单
<form action="/*指定一个servlet*/" method="post" enctype="multipart/form-data">
<input type="file" name="file" /><br /><br />
<input type="submit" value="上传" />
</form>
②编写Servlet
页面的表单控件创建好以后,选中文件点击上传按钮请求将会提交到指定的Servlet来处理。
- 注:这里不能像之前的servlet那样,通过request.getParameter()来获取请求参数了,当enctype="multipart/form-data"时,再使用request.getParameter()获取得到的内容为空,因为浏览器发送请求的方式已经改变。既然以前的方法不能使用了,这里我们必须要引入一个新的工具来解析请求中的参数和文件,这个工具就是commons-fileupload。
1.3commons-fileupload
commons-fileupload是Apache开发的一款专门用来处理上传的工具,它的作用就是可以从request对象中解析出,用户发送的请求参数和上传文件的流。
1.4核心类
- DiskFileItemFactory:工厂类,用于创建ServletFileUpload,设置缓存等,该类一般直接使用构造器直接创建实例
方法:
(1)public void setSizeThreshold(int sizeThreshold) //用于设置缓存文件的大小(默认值为10kb)
(2)public void setRepository(File repository) //用于设置缓存文件位置2.
- ServletFileUpload:该类用于解析request对象从而获取用户发送的请求参数(包括普通参数和文件参数), 该类需要调用有参构造器创建实例,构造器中需要一个DiskFileItemFactory作为参数。
方法:
(1)public List<FileItem> parseRequest(HttpServletRequest request)//解析request对象,获取请求参数,返回的是一个List,List中保存的是一个FileItem对象,一个对象代表一个请求参数。
(2)public void setFileSizeMax(long fileSizeMax)//设置单个文件的大小限制,单位为B如果上传文件超出限制,会在parseRequest()抛出异常:FileSizeLimitExceededException
(3)public void setSizeMax(long sizeMax)//限制请求内容的总大小,单位为B,如果上传文件超出限制,会在parseRequest()抛出异常:SizeLimitExceededException
- FileItem:该类用于封装用户发送的参数和文件,也就是用户发送来的信息将会被封装成一个FileItem对象,我们通过该对象获取请求参数或上传文件的信息。该类不用我们手动创建,由ServletFileItem解析request后返回。
(1)String getFieldName() //获取表单项的名字,也就是input当中的name属性的值。
(2)String getName() //获取上传的文件名,普通的请求参数为null。
(3)String getString(String encoding); //获取内容。若为文件,将文件的流转换为字符串,若为请求参数,则获取请求参数的value。encoding参数需要指定一个字符集。
(4)boolean isFormField() //判断当前的FileItem封装的是普通请求参数,还是一个文件。如果为普通参数返回:true,如果为文件参数返回:false。
(5)String getContentType() //获取上传文件的MIME类型
(6)long getSize() //获取内容的大小
1.5文件上传的例子
一、创建一个表单
<form action="FileUploadServlet2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="ufile"><br>
<input type="submit" value="上传">
</form>
二、创建FileUploadServlet2
public class FileUploadServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
// 创建ServletFileUpload的工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
// 创建解析器,ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
// 获取文件上传路径,upload的真实路径
String realPath = this.getServletContext().getRealPath("/upload");
// 设置单个文件的上传大小限制为:2k
upload.setFileSizeMax(1024 * 2);
try {
// 通过解析器,将request解析为List<FileItem>
List<FileItem> list = upload.parseRequest(request);
//遍历集合
for (FileItem fileItem : list) {
//判断当前的FileItem封装的是普通请求参数,还是一个文件。如果为普通参数返回:true,如果为文件参数返回:false。
if (fileItem.isFormField() == false) {
// 获取文件名
String fileName = fileItem.getName();
if (fileName != null && !"".equals(fileName)) {
// 使用UUID拼接用户名
String uuid = UUID.randomUUID().toString().replace("-", "");
// 上传
File file = new File(realPath + "/" + uuid + fileName);
fileItem.write(file);
response.getWriter().write("upload success!");
}
}
}
} catch (FileSizeLimitExceededException e) {
// e.printStackTrace();
writer.write("上传单个文件过大,单个文件不能超过2k");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
2.1文件的下载
文件下载最直接的方法就是把文件直接放到服务器的目录中,用户直接访问该文件就可以直接下载。
下载文件的关键点:
-
服务器以一个流的形式将文件发送给浏览器。
-
发送流的同时还需要设置几个响应头,来告诉浏览器下载的信息。
-
接下来需要以输入流的形式读入硬盘上的文件
-
通过response获取一个输出流,并将文件(输入流)通过该流发送给浏览器
2.2文件下载的模板
以下步骤都是在同一个Servlet的doGet()方法中编写的,所下载的文件是放在WEB-INF下mp3文件夹中的文件。
①获取文件的流
//获取真实路径
String realPath = getServletContext().getRealPath("/WEB-INF/mp3/中国话.mp3");
//获取文件的File对象
File file = new File(realPath);
//获取文件的输入流
FileInputStream is = new FileInputStream(file);
②获取头文件
//获取文件的MIME信息
String contentType = getServletContext().getMimeType(realPath);
//设置下载文件的名字
String filename = "zhongguohua.mp3";
//创建Content-Disposition信息
String disposition = "attachment; filename="+ filename ;
//获取文件长度
long size = file.length();
③设置头信息
//设置Content-Type
response.setContentType(contentType);
//设置Content-Disposition
response.setHeader("Content-Disposition", disposition);
//设置文件长度
response.setContentLength((int)size);
④发送文件
//通过response获取输出流,用于向浏览器输出内容
ServletOutputStream out = response.getOutputStream();
//将文件输入流通过输出流输出
byte[] b = new byte[1024];
int len = 0;
while((len=is.read(b))> 0){
out.write(b, 0, len);
}
//最后不要忘记关闭输入流,输出流由Tomcat自己处理,我们不用手动关闭
is.close();
2.3例子
<body>
<h2>资源库</h2>
<a href="${pageContext.request.contextPath }/DownLoadServlet2?fName=st.jpg">st.jpg</a>
<a href="${pageContext.request.contextPath }/DownLoadServlet2?fName=OSI.pptx">OSI.pptx</a>
<a href="${pageContext.request.contextPath }/DownLoadServlet2?fName=坚持.mp4">坚持.mp4</a>
</body>
public class DownLoadServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
GET请求乱码问题解决:修改服务器中service.xml中的<Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
*/
// post请求在Servlet中解码,默认的字符集是ISO-8859-1,不支持中文,我们需要修改Servlet的字符集为UTF-8.
request.setCharacterEncoding("UTF-8");
//将服务器编码与浏览器解码设置为UTF-8
response.setContentType("text/html;charset=UTF-8");
//取fName值
String fileName = request.getParameter("fName");
System.out.println("fileName:"+fileName);
//获取fName的真实路径
String realPath = this.getServletContext().getRealPath("/download/"+fileName);
System.out.println("realPath:"+realPath);
//设置浏览器响应体文件类型
String mimeType = request.getServletContext().getMimeType(fileName);
response.setContentType(mimeType);
//获取客户端信息
String header = request.getHeader("User-Agent");
//解决文件名中文乱码问题
if(header != null && header.contains("Firefox")) {
//火狐浏览器乱码的解决方法
fileName = "=?utf-8?B?"+new BASE64Encoder().encode(fileName.getBytes("utf-8"))+"?=";
}else {
//其他浏览器解决乱码问题
fileName = URLEncoder.encode(fileName, "UTF-8");
}
//设置浏览器响应体内容格式,为附件格式。(告诉浏览器,文件为附件,别打开,下载。)
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
//创建输入流的文件(路径+文件名)
File file = new File(realPath);
//创建输入流
FileInputStream fis = new FileInputStream(file);
//创建输出流
ServletOutputStream sos = response.getOutputStream();
//实现边读边写(文件下载)
byte[] b = new byte[1024];
int len = 0;
while((len = fis.read(b))>0) {
sos.write(b, 0, len);
}
sos.close();
fis.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
注:注意乱码解决时,代码放置的位置。