Servlet系列学习笔记14 --- Servlet文件上传和下载(一)

39 篇文章 0 订阅

目录

一、文件上传

       1.1 JSP页面

       1.2 Servlet处理类

       1.3 最终效果

二、文件下载

       2.1 JSP页面

       2.2 Servlet下载业务类

       2.3 最终效果图


一、文件上传

文件上传的细节

  文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的

  1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

  2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

  3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。

  4、要限制上传文件的最大值

  5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

1.1 JSP页面

       当客户端向服务器上传文件时,客户端发送的HTTP请求正文采用"multipart/form-data"数据类型,它表示复杂的包括多个子部分的复合表单。例如下面的代码所示

<form action="UploadDemo" method="post" enctype="multipart/form-data">
    姓名:<input type="text" name="name"/><br/>
    性别:<input type="text" name="sex"/><br/>
    <input type="file" name="picture" size="30" value="上传图片"/><br/>
    <input type="file" name="vedio" value="上传文本"/><br/>
    <input type="submit" value="确定上传"/>
</form>

1.2 Servlet处理类

       不管HTTP请求正文为何种数据类型,Servlet容器都会把HTTP请求包装成HttpServletRequest对象,但是解析过程将会是一项非常麻烦的事情。所以,我们可以利用Apache开源的两个jar包来实现文件的上传和下载, 它们的jar包如下图所示

       (1)fileupload包:负责实现上传文件的软件包

       (2)io包:负责输入输出的软件包

       FileItemFactory是创建FileItem对象的工厂,DiskFileItemFactory类和DiskFileItem类分别实现了FileItemFactory接口和FileItem接口。

       DiskFileItem类表示基于硬盘的FileItem,DiskFileItem类能够把客户端上传的文件数据保存到硬盘上,DiskFileItemFactory则是创建DiskFileItem对象的工厂。

       下面的程序代码创建了DiskFileItemFactory对象,然后设置了硬盘写数据时所用的缓冲区大小,以及所使用的临时目录。为了提高向硬盘写数据的效率,尤其是在写大容量的时候会使用缓存,以及向临时目录存放一些数据。

//1、创建一个基于硬盘的FileItem工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、设置向硬盘写数据时所用缓冲区的大小,此处为5K
factory.setSizeThreshold(5*1024);
//3、设置上传时生成的临时文件的保存目录
factory.setRepository(new File(存放目录路径));

       ServletFileUpload类为文件上传处理器,它域FileItemFactory关联。通过该类的setSizeMax()方法可以用来设置允许上传文件的大小。

 //4、创建文件上传处理器
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8"); 	//设置上传文件的编码方式为UTF-8
//5、设置运行上传文件的最大尺寸,此处为2M
upload.setSizeMax(2*1024*1024);

       ServletFileUpload类的parseRequest(HttpServletRequest request)方法能够解析Request对象中的复合表单数据,返回一组FileItem对象的List集合

//6、获取包含文件对象的请求参数的List集合
List items = upload.parseRequest(request);

       在得到了FileItem对象的List集合之后,通过遍历该集合里面的所有对象,通过该对象的类型是普通表单类型还是上传文件类型,从而执行不同的方法。

Iterator iter = items.iterator();
while(iter.hasNext()){
   FileItem item = (FileItem)iter.next();
   if(item.isFormField()){
      //处理普通表单域
   }else{
      //处理上传文件域
   }
}

       最终的成品程序如下所示

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadDemo extends HttpServlet {
	private String savePath; // 文件存放路径
	private File file;	//存放目录
	PrintWriter out; // 响应输出对象
	public void init() throws ServletException {
		//设置或获取文件保存的 目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
		savePath = getServletContext().getRealPath("/WEB-INF/upload");
		System.out.println(savePath);
        //获取该文件夹对象
		file = new File(savePath);
        //判断文件 存储目录是否存在,如果不存在就创建一个
        if (!file.exists() && !file.isDirectory()) {
            System.out.println(savePath+"目录不存在,需要创建");
            //创建目录
            file.mkdir();
        }
	}
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		out = response.getWriter();
		try{
			//使用Apache文件上传组件处理文件上传步骤:
	        //1、创建一个基于硬盘的FileItem工厂
	        DiskFileItemFactory factory = new DiskFileItemFactory();
	        //2、设置向硬盘写数据时所用缓冲区的大小,此处为5K
	        factory.setSizeThreshold(5*1024);
	        //3、设置上传时生成的临时文件的保存目录
	        factory.setRepository(file);
	        
	        //4、创建文件上传处理器
	        ServletFileUpload upload = new ServletFileUpload(factory);
	        upload.setHeaderEncoding("UTF-8"); 	//设置上传文件的编码方式为UTF-8
	        //5、设置运行上传文件的最大尺寸,此处为2M
	        upload.setSizeMax(2*1024*1024);
	        
	        //6、获取包含文件对象的请求参数的List集合
	        List items = upload.parseRequest(request);
	        
	        Iterator iter = items.iterator();
	        while(iter.hasNext()){
	        	FileItem item = (FileItem)iter.next();
	        	if(item.isFormField()){
	        		//处理普通表单域
	        		FormField(item);
	        	}else{
	        		//处理上传文件域
	        		UploadFile(item);
	        	}
	        }
	        
	        upload.setHeaderEncoding("UTF-8"); 

		}catch(Exception ex){
			ex.printStackTrace();
		}
	}
	private void FormField(FileItem item) throws Exception{
		String name = new String(item.getFieldName().getBytes("ISO8859-1"),"UTF-8");;  //获取参数名
		String value = new String(item.getString().getBytes("ISO8859-1"),"UTF-8");  //获取普通参数值
		out.print("<h3>获取参数 "+name+" : "+value+"</h3>");
	}
	private void UploadFile(FileItem item) throws Exception{
		String  fileName = item.getName();	//获取包含路径在内的文件名
		int index = fileName.lastIndexOf("\\");  //获取最后一个斜杠的索引
		//截取文件路径的字符串,截取文件名
		fileName = fileName.substring(index+1, fileName.length());
		long fileSize = item.getSize(); //获取文件大小
		if(fileName.equals("") && fileSize == 0){
			out.print("<h3>上传的文件不符合格式</h3>");
			return;
		}
		File uploadFile = new File(savePath+"/"+fileName);
		item.write(uploadFile);  //将上传的文件写入(保存)到本地硬盘的指定路径中
		out.print("<h3>成功保存文件:"+fileName+", 该文件大小为:"+fileSize+"byte</h3>");
	}
}

1.3 最终效果

 

二、文件下载

       在实际开发中,所有下载文件的信息都会存放在数据库当中,例如文件名、存放目录等,通过查询文件表就能获取文件的文件名和存放目录。在本示例中,我省去了这一步,直接在页面中指定下载文件名和存放目录。

2.1 JSP页面

<!DOCTYPE HTML>
<html>
  <head>
    <title>下载文件显示页面</title>
  </head>
  
  <body>
    wenben3.txt<a href="/06-Upload/DownloadDemo?filename=wenben3.txt">下载</a>
    wenben4.txt<a href="/06-Upload/DownloadDemo?filename=wenben4.txt">下载</a>
    wenben2.txt<a href="/06-Upload/DownloadDemo?filename=wenben2.txt">下载</a>
    wenben1.txt<a href="/06-Upload/DownloadDemo?filename=wenben1.txt">下载</a>
  </body>
</html>

2.2 Servlet下载业务类

public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    //获取想要下载的文件名
    String fileName = request.getParameter("filename");
    //将文件名进行转码,防止出现中文乱码
    fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
    //设置文件所在路径(context对象的getRealPath方法能够获得Web应用的所在目录)
    //getRealPath方法能够获得项目的运行目录,通过给定字符串能够获得包含给定虚拟路径的绝对路径
    String path = this.getServletContext().getRealPath("/WEB-INF/upload")+"/"+fileName;
    System.out.println(path);
    //创建File对象,通过指定路径获取想要下载的文件
    File file = new File(path);
    //如果文件不存在
    if(!file.exists()){
        request.setAttribute("message", "该资源不存在!");
        request.getRequestDispatcher("/message.jsp").forward(request, response);
        return;
    }
    //设置响应正文的MIME类型,控制浏览器下载该文件
    response.setHeader("content-disposition", "attachment;filename=" + fileName);
    //读取要下载的文件,保存到文件输入流
    FileInputStream in = new FileInputStream(path);
    //创建输出流
    OutputStream out = response.getOutputStream();
    //创建缓冲区
    byte buffer[] = new byte[1024];
    int len = 0;
    //循环将输入流中的内容读取到缓冲区当中
    while((len=in.read(buffer))>0){
        //输出缓冲区的内容到浏览器,实现文件下载
        out.write(buffer, 0, len);
    }
    in.close();  //关闭文件输入流
    out.close(); //关闭输出流
}

2.3 最终效果图

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值