1.文件的上传介绍
1.要有一个form标签,method=post请求
2.form标签的encType属性值必须为multipart/form-data值(以多段(每一个表单项一个数据项)的形式进行拼接,然后以二进制流的形式发给服务器)
3.在form标签中使用input type=file添加上传的文件
4.编写服务器代码(Servlet程序)接收,处理上传的数据
我们创建一个软件包,命名为com.bjpowernode,在该包下创建一个UploadServlet.java,代码如下:
package com.bjpowernode;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("文件上传过来了");
}
@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
System.out.println("文件上传过来了");
}
}
创建一个upload.jsp,代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/Maven5/uploadServlet" method="post" encType="multipart/form-data">
用户名:<input type="text" name="username" /><br>
头像:<input type="file" name="photo"/><br>
<input type="submit" value="上传">
</form>
</body>
</html>
结果如下:
查看Http协议,结果如下:
我们修改UploadServlet.java,代码如下:
package com.bjpowernode;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
System.out.println("文件上传过来了");
//因为是以二进制流传输,所有接收不到
System.out.println(request.getParameter("username"));
System.out.println(request.getParameter("photo"));
ServletInputStream inputStream=request.getInputStream();
//创建缓冲区
byte[]buffer=new byte[1024000];
int read=inputStream.read(buffer);
System.out.println(new String(buffer,0,read));
}
@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
System.out.println("文件上传过来了");
}
}
结果如下:
2.commos-fileupload.jar常用API介绍说明
我们使用Tomcat10时,导入的是jakatra包,但是因为历史的原因,commons-fileupload与jakatra不兼容,所以后边我改用Tomcat8来继续接下去的内容
先在pom.xml添加commons-fileupload和commons-io依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>Maven6</name>
<groupId>com.bjpowernode</groupId>
<artifactId>Maven6</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.7</version>
<configuration>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>8888</port>
<maxIdleTime>30000</maxIdleTime>
</connector>
</connectors>
<webAppSourceDirectory>${project.build.directory}/${pom.artifactId}-${pom.version}</webAppSourceDirectory>
<contextPath>/</contextPath>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
常用的类:
ServletFileUpload类:用于解析上传的数据
判断当前上传的数据格式是否是多段的格式
boolean ServletFileUpload.isMultiportContent(HttpServletRequest request);
解析上传的数据
public List<FileItem>parseRequest(HttpServletRequest request);
判断当前这个表单项是否是普通的表单项。true表示上传的是表单项;false表示上传的是文件类型
boolean FileItem.isFormFileld();
获取表单项的name属性值
String FileItem.getFileName();
获取当前表单项的值
String FileItem.getString();
获取上传的文件名
String FileItem.getName();
将上传的文件写到参数file所指向的磁盘位置
void FileItem.write(file);
我们修改UploadServlet.java,代码如下:
package com.bjpowernode;
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.List;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
//System.out.println("post");
//1.先判断上传的数据是否多段数据(只有多段数据才是文件上传的)
if(ServletFileUpload.isMultipartContent(request)){
//创建FileItemFactory工厂实现类
FileItemFactory fileItemFactory=new DiskFileItemFactory();
//创建用于解析上传数据的工具类ServletFileUpload类
ServletFileUpload servletFileUpload=new ServletFileUpload(fileItemFactory);
try {
//解析上传的数据,得到每一个表单项FileItem
List<FileItem> list = servletFileUpload.parseRequest(request);
//循环判断,每一个表单项是普通类型还是上传的文件
for(FileItem fileItem:list){
if(fileItem.isFormField()){
//普通表单项
System.out.println("表单项的name属性值:"+fileItem.getFieldName());
//参数UTF-8,解决乱码问题
System.out.println("表单项的value属性值:"+fileItem.getString("UTF-8"));
}
else{
//上传的文件
System.out.println("表单项的name属性值:"+fileItem.getFieldName());
System.out.println("上传的文件名:"+fileItem.getName());
fileItem.write(new File("E:\\"+fileItem.getName()));
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
运行结果如下:
提交后,在控制台结果如下:
我们打开E盘,看见上传的文件
3.文件的下载
步骤如下:
1.获取要下载的文件名
2.读取要下载的文件内容
3.把下载的文件内容回传给客户端
4.在回传前,通过响应头告诉客户端返回的数据类型
5.还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
我们创建一个Down.java,代码如下:
package com.bjpowernode;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.fileupload.*;
import org.apache.commons.io.*;
public class Download extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
//1.获取要下载的文件名
String downloadFileName="2.jpg";
//2.读取要下载的文件内容(通过ServletContext对象可以读取)
ServletContext servletContext=getServletContext();
//获取要下载的文件类型
String mimeType=servletContext.getMimeType("/file/"+downloadFileName);
System.out.println("下载的文件类型"+mimeType);
//4.在回传前,通过响应头告诉客户端返回的数据类型
response.setContentType(mimeType);
//5.还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
//Content-Disposition响应头,表示受到的数据怎么处理
//attachment表示附件,表示下载使用
//filename表示指定下载的文件名
response.setHeader("Content-Disposition","attachment;filename="+downloadFileName);
//斜杆被服务器解析表示为http://ip:port/工程名/ 映射到代码的webapp目录
InputStream resourceAsStream=servletContext.getResourceAsStream("/file/"+downloadFileName);
//获取响应的输出流
OutputStream outputStream=response.getOutputStream();
//读取输入流中全部的数据,复制给输出流,回传给客户端
//3.把下载的文件内容回传给客户端IOUtils.copy(resourceAsStream,outputStream);
}
}
添加web.xml配置,然后在webapp目录下创建一个file目录,在file目录下有2.jpg图片
结果如下:
显示的图片如下:
如果我们传输要下载的文件名含有中文字符,如果使用的是谷歌浏览器或IE浏览器,需要修改代码,修改代码如下:
//URL编码是把汉字转换成xx%xx的格式
response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode("中国.jpg","UTF-8"));
如果是火狐浏览器,因为火狐浏览器支持的是Base64编码,故上述方法无效。我们先创建一个Test.java来展示该解码方式,代码如下:
public static void main(String[]args)throws Exception{
String content="这是需要Base64编码的内容";
//创建一个Base64编码器
BASE64Encoder base64Encoder=new BASE64Encoder();
//执行Base64编码操作
String encodedString=base64Encoder.encode(content.getBytes("UTF-8"));
System.out.println(encodedString);
//创建Base64解码器
BASE64Decoder base64Decoder=new BASE64Decoder();
//解码操作
byte[] bytes=base64Decoder.decodeBuffer(encodedString);
String str=new String(bytes,"UTF-8");
System.out.println(str);
}
回归主题,对于火狐浏览器,想要下载文件名带有中文的文件,需要修改代码如下:
response.setHeader("Content-Disposition","attachment;filename==?UTF-8?B?"+new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8"))+"?=");
根据浏览器动态切换要修改的代码
if(request.getHeader("User-Agent").contains("Firefox")){
//如果是火狐浏览器使用Base64编码
response.setHeader("Content-Disposition","attachment;filename==?UTF-8?B?"+new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8"))+"?=");
}else{
//URL编码是把汉字转换成xx%xx的格式
response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode("中国.jpg","UTF-8"));
}