欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

文件的上传和下载

程序员文章站 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文件的下载

文件下载最直接的方法就是把文件直接放到服务器的目录中,用户直接访问该文件就可以直接下载。

下载文件的关键点:

  1. 服务器以一个流的形式将文件发送给浏览器。

  2. 发送流的同时还需要设置几个响应头,来告诉浏览器下载的信息。

  3. 接下来需要以输入流的形式读入硬盘上的文件

  4. 通过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);
	}

}

注:注意乱码解决时,代码放置的位置。