文件的上传和下载
1. What is 文件上传? what is 文件下载? 文件上传:用户通过浏览器向服务器提交文件,并由服务器保存 文件下载:用户通过浏览器从服务器上得到一些文件数据,并在浏览器端保存 2. Why use 文件上传? Why use 文件下载? web应用功能需要 3. How 实现文件上传? ** 实现文件上传的流程 1、在jsp页面添加form表单: (1) (2) 必须把 form 的 enctype 属性设为 multipart/form-data,
enctype 属性取值:
application/x-www-form-urlencoded:表单 enctype 属性的默认值。这种编码方案使用有限的字符集,当使用了非字母和数字时,必须用”%HH”代替(H 代表十六进制数字)。对于大容量的二进制数据或包含非 ASCII 字符的文本来说,这种编码不能满足要求。
multipart/form-data:form 设定了enctype=“multipart/form-data”属性后,表示表单以二进制传输数据 。在浏览器在上传文件时,将把文件数据附带在 http 请求消息体中,并使用 MIME 协议对上传文件进行描述,以方便接收方对上传数据进行解析和处理。
(3) 表单提交的方式要是 post(get的请求体有大小限制,而post无大小限制) 注意:enctype=“multipart/form-data”的表单在servlet中不能再像以往那样通过 request.getParameter()那样得到请求中的参数数据(数据格式不对),另有取值的方式 2、为了方便用户处理上传数据,Apache 提供了一个用来处理表单文件上传的开源组件: Commons-fileupload 和Commons-io ,Commons-fileupload 组件从 1.1 版本开始依赖 commons-io
其主要的接口和类有三个:
1.ServletFileUpload 负责处理上传的文件数据,并将每部分的数据封装成一到 FileItem 对象中。
isMultipartContent(HttpServletRequest request) 判断上传表单是否为 multipart/form-data
parseRequest(HttpServletRequest request) :得到请求所有表单项的数据对象,返回一 个List 2.DiskFileItemFactory 是创建 FileItem 对象的工厂,在这个工厂类中可以配置内存缓冲区大小和存放临时文件的目录。 setSizeThreshold(int sizeThreshold,File repository ) 设置内存缓冲区的大小,默认值为 10k 当上传文件大于缓冲区大小时,fileupload 组件将使用临时文件缓存上传文件 setRepository(File repository) 指定临时文件目录,默认值为 System.getProperty(\"java.io.tmpdir\") 3.FileItem :代表一个表单项数据,可以获得表单项的数据,可以判断是否为普通表单项 isFormField():为true,为普通表单项;为false,为file表单项 getFieldName() 获取的是普通表单项的表单项名。 getString(encod) 获取的是普通表单项的表单项值。 getName() 获取的是上传文件的简单文件名(有些浏览器(ie)会返回文件的全路径名,所有在此处最好加以判断) 3. 基本的原理为: FileUpload组件将页面提交的所有元素(普通form表单域,如text和文件域file)都看作一样的FileItem,这样上传页面提交的 request请求也就是一个FileItem的有序组合,FileUpload组件可以解析该request,并返回一个一个的FileItem。而对每一个FileItem,FileUpload组件可以判断出它是普通form表单域还是文件file域,从而根据不同的类型,采取不同的操作--如果是表单域,就读出其值,如果是文件域,就保存文件到服务器硬盘上或者内存中。 4、fileuplpad 组件的具体工作流程 (1)客户端将数据封装在 request 对象中 (2)服务器端获取到 request 对象,并判断enctype的属性是否为 multipart/form-data,为true则继续进行文件上传的工作 ServletFileUpload.isMultipartContent(request) (3)创建FileItem的工厂 DiskFileItemFactory ,并在此处设置缓冲区大小和超出 缓存时,存放临时文件的文件夹 DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(1024*10) factory.setRepository(tempFile); 以上的设置也可写成这般: DiskFileItemFactory factory = new DiskFileItemFactory(1024*20, tempFile) (4)创建解析器ServletFileUpLoad,将解析器工厂放入解析器构造函数中。 ServletFileUpload fileUpload = new ServletFileUpload(factory); 设置响应头的编码格式 fileUpload.setHeaderEncoding(\"utf-8\"); 限制单个文件的大小 fileUpload.setFileSizeMax(1024*80); 限制文件的总大小 fileUpload.setSizeMax(1024*1024); (5)用解析器对 request 进行解析,得到的是List List if(item.isFormField()) (7)如果是普通表单项,通过 getFieldName 获取表单项名,getString 获得表单 项值。 True 获得普通表单项的名字哦 String fieldName = item.getFieldName(); 获得普通表单项的属性值,可以设置解码的格式 String value = item.getString(\"utf-8\"); (8)如果 isFormField 返回 false 那么是用户要上传的数据,可以通过 getInputStream 获取上传文件的数据。 False String fieldName = item.getFieldName(); String fileName = item.getName(); //由于有些浏览器输出的是全路径,故需加判断 if(fileName!=null && fileName.contains(\"\\\\\")) { fileName = fileName.substring(fileName.lastIndexOf(\"\\\\\")+1); } //保存上传的文件 InputStream is = item.getInputStream(); (9)把上传的数据保存在服务端(uploadDirFile为保存在服务端的文件夹路径(自 己设置),fileName为保存的文件名) OutputStream os = new FileOutputStream(new File(uploadDirFile, fileName)); byte[] buffer = new byte[1024]; int len = -1; while((len=is.read(buffer))>0) { os.write(buffer, 0, len); } os.close(); is.close(); //删除可能生成的临时文件 item.delete(); How 实现文件下载? 有两种方式 ① 将文件资源直接放在WebContent的路径下(不放入WEB-INF中),在页面直接提供可供访问的链接:WebContent/download/china.jpg 问题: 1.像图片和txt等浏览器可以直接打开的文件,浏览器会自动打开而不是主动提供下载;当然,向doc和压缩文件等浏览器不能直接打开的文件,浏览器提供下载功能 2.太暴露了,不安全,有时需要有一定的权限才能下载,但这样没有办法控制 ② 通过servlet提供下载,我们可以对下载进行控制,资源文件存放在WEB-INF中 china.jpg 其中fileName是下载文件的文件名,china.jpg,是页面请求时传过来的参数 String filename = request.getParameter(\"filename\"); response.setHeader(\"Content-Type\ response.setHeader(\"Content-Disposition\ 2.获得资源文件的位置,读取文件数据 String downloadDir = getServletContext().getRealPath(\"/WEB-INF/download\"); InputStream is = new FileInputStream(new File(downloadDir,fileName)); 3.把读取的数据写入浏览器端 OutputStream os = response.getOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len=is.read(buffer))>0){ os.write(buffer, 0, len); } os.close(); is.close(); 文件上传的UploadServlet源程序: 关联的jar包: commons-io-2.0.jarcommons-fileupload-1.2.1.jar package jin.fileuplad; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import javax.servlet.ServletException; 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.FileUploadBase.FileSizeLimitExceededException; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class RegistJinServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //判断是否为带文件的请求,form表单的enctype=multipart/form-data boolean flag = ServletFileUpload.isMultipartContent(request); if(flag){ File tempFile = new File(\"F:\\\emp\"); if(!tempFile.exists()){ tempFile.mkdirs(); } DiskFileItemFactory factory = new DiskFileItemFactory(1024*10,tempFile); //设置缓冲区大小,若文件超出此值则将其临时存放在temp中 //factory.setSizeThreshold(1024*10); //设置临时存放的位置 //factory.setRepository(tempFile); ServletFileUpload fileUpload = new ServletFileUpload(factory); //设置上传的单个文件的最大字节数为40k fileUpload.setFileSizeMax(1024*40); response.setContentType(\"text/html;charset=utf-8\"); try { List protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } 文件上传的jsp页面:upload.jsp 文件下载的DownloadServlet源程序 package jin; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DownloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = request.getParameter(\"filename\"); response.setHeader(\"Content-Type\ response.setHeader(\"Content-Disposition\ //资源文件存放在此文件夹下 String downloadDir = getServletContext().getRealPath(\"/WEB-INF/download\"); InputStream is = new FileInputStream(new File(downloadDir+\"/\"+fileName)); OutputStream os = response.getOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len=is.read(buffer))>0){ os.write(buffer, 0, len); } os.close(); is.close(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } 文件下载的jsp页面:download.jsp 因篇幅问题不能全部显示,请点此查看更多更全内容
通过servlet提供下载不需要别的jar包,相比文件的上传较为简单 1.在响应头中加入两条响应信息 Content-Type: application/x-msdownload Content-Disposition: attachment;filename=fileName下载列表
1.jpg
2.jpg
3.jpg