使用Servlet+html简单实现文件的上传与下载
前言
JavaWeb在发展中不断衍生出更加强大,成熟,好用的框架,部分技术已经过时,学习研究它变得意义不是很大,所以笔者仅了解学习JavaWeb中的Servlet服务端技术,学习使用其实现上传和下载文件,仅以此篇博客记录,欢迎读者指正。一 使用Servlet实现文件的下载
Servlet的下载相较于上传是较为容易实现的,首先,为了方便我们可以创建一个Meavn项目,然后配置pom.xml导入所需要的依赖以及web.xml实现Servlet的配置,编码后最后配置相应的Tomcat,具体步骤可以去其它博客中了解.
实现文件下载之前我们需要先想好如何实现文件的下载?
1.获取文件的下载路径
2.找到需要下载的文件(对应的文件名)
3.需要浏览器能够支持我们下载文件(环境)
4.开始下载文件(将文件转化成输入流)
5.将对应的输入流传入缓冲区
6.将缓冲区中的数据转为输出流
7.写入到文件中,实现下载
具体实现源码如下:
package com.hang;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
//文件下载(注解形式或配置文件中装配)
//@WebServlet(name = "com.hang.FileServlet", urlPatterns = {"/down"})
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取文件的下载路径
String filePath="D:\\myProject\\servlet\\servlet-03\\src\\main\\resources\\icon.png";
//2.获取下载的文件名
String fileName=filePath.substring(filePath.lastIndexOf("\\")+1);
System.out.println("文件下载路径:"+filePath);
//3.设置浏览器能够支持我们下载我们所需要的东西
resp.setHeader("Content-Disposition","attachment;filename="+fileName);
//4.获取下载文件的输入流
FileInputStream in=new FileInputStream(filePath);
//5.创建缓冲区
int len=0;
byte[] buffer=new byte[1024];
//6.获取OutputStream对象
ServletOutputStream sos=resp.getOutputStream();
//7.将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区的流输出到客户端
while ((len=in.read(buffer))>0){
//当缓冲区中还有流时,不断读取并写入
sos.write(buffer,0,len);
}
//关闭流
in.close();
sos.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
配置好Tomcat服务器后运行,结果如下:
控制台结果及项目结构:
其实使用Servlet实现文件的下载并不难理解,也比较容易实现。
二 使用Servlet实现文件的上传
使用Servlet实现文件上传有两种常见的方式,一种是使用Apache开源库类实现文件上传(commons.fileupload-x.jar和common.io-x.jar),另一种是使用Parts接口实现文件上传;这里我采用Parts接口来实现文件的上传~
使用Parts接口实现多文件的上传
要实现文件上传,首先要明白什么是文件上传?可以说它是和文件下载完全相反的过程。通过上述例子,我们可以知道,文件下载是将服务器上的数据下载到客户端的过程,而文件上传就是将客户端的文件数据上传到服务端的过程!
如何实现文件上传呢?我一开始想到的方法是也使用流的方法,将文件转换成流输入到请求中,然后上网看看其它的demo,哇,完全不是我所想的,可以使用part.write(savePath+"\\"+fileName)直接将文件写入服务器,具体实现步骤如下:
1.在web.xml中配置好相应的Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<servlet>
<servlet-name>FileDownload</servlet-name>
<servlet-class>com.hang.FileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileDownload</servlet-name>
<url-pattern>/down</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FileUpload</servlet-name>
<servlet-class>com.hang.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileUpload</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
</web-app>
2.在项目中创建一个文件夹store存储上传的文件
3.编写前端页面(上传文件的页面)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>upload</title>
</head>
<body>
<form name="uploadForm" method="post" enctype="multipart/form-data" action="upload">
<table>
<tr>
<td><div align="right">username:</div></td>
<td><input type="text" name="username" size="30"/></td>
</tr>
<tr>
<td><div align="right">Upload file1:</div></td>
<td><input type="file" name="file1" size="30"/></td>
</tr>
<tr>
<td><div align="right">Upload file2:</div></td>
<td><input type="file" name="file2" size="30"/></td>
</tr>
<tr>
<td><input type="submit" name="submit" value="upload"></td>
<td><input type="reset" name="reset" value="reset"></td>
</tr>
</table>
</form>
</body>
</html>
4.编写上传文件的Servlet
package com.hang;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
//使用该注解配置servlet的映射
//@WebServlet(name = "UploadServlet",urlPatterns = "/upload")
//使用该注解以支持文件上传
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理
resp.setContentType("text/plain;charset=utf-8");
req.setCharacterEncoding("utf-8");
//保存文件的路径
String savePath="D:\\myProject\\servlet\\servlet-03\\store";
PrintWriter out=resp.getWriter();
Collection<Part> parts=req.getParts();
//获取正文表单数据的每个部分
for(Part part:parts){
String header=part.getHeader("Content-Disposition");
//在Tomcat服务端显示每个子部分的信息
System.out.println("---------Part----------");
System.out.println("type:"+part.getContentType());
System.out.println("size:"+part.getSize());
System.out.println("name:"+part.getName());
System.out.println("header:"+header);
//若为表单中的文本域,则显示文本域中的名字和取值
if(part.getContentType()==null){
String name=part.getName();
String value=req.getParameter(name);
out.println(name+":"+value+"\r\n");
}else{
//若为表单中的file1或file2文件域,那么进行文件上传
//1.获取上传的文件名
String fileName=getFileName(header);
System.out.println(header);
//2.将文件写到指定路径(为什么写不进去)
// part.write(savePath+ File.pathSeparator+fileName);
part.write(savePath+"\\"+fileName);
out.println(fileName+"is saved");
out.println("The size of "+fileName+" is "+part.getSize()+"byte. \r\n");
}
out.flush();
out.close();
}
}
public String getFileName(String header) {
//若一个part的请求头header是:form-data;name="file1";filename="FromClient.rar",那么FromClient.rar就是这个的文件名
String fileName=header.substring(header.lastIndexOf("=")+2,header.length()-1);
return fileName;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
}
5.运行,项目结构及效果如下
运行成功后,访问对应的html网页,注意是upload.html而不是upload,否则会报服务器500错误
6.踩坑总结及经验教训
- 遇到页面乱码或者下载的文件乱码,设置请求和相应的类型为"utf-8"即可解决
- 遇到500—服务器内部错误,应该是访问的路径错了,若访问的不是页面,请求和响应内容都为空,自然是服务器内部错误了
- 遇到404—客户端错误,html表单中的action=/upload,导致无法跳转到UploadServlet,页面丢失进而导致客户端错误!解决方法是将action=/upload改成 action=upload,与UploadServlet映射的路径一致
文件无法上传及请求头为空的问题,这个问题困扰了我很久,我是这样查看问题并尝试性去解决的:
①使用浏览器的检查功能,检查请求头的内容数据
当时的请求头也是和这个极为类似的,可以看出请求头并没有出问题,但是为什么在日志中会报下面的错误:
org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException: the request doesn’t contain a multipart/form-data or multipart/mixed stream, content type header is null
②打印输出header
心细的盆友可以看到,我在源代码中穿插了一句上传文件时查看header请求头的语句,事实证明请求头正常
③文件的保存路径问题:既然文件信息和请求头都正常,那么只有可能是保存的文件路径或者写文件时出现问题了,我将文件的保存路径改成绝对路径,再修改写文件时的操作,后成功上传文件,Nice~