Servlet Java Web开发(7)上传下载
上传
先看一个例子:
有两个表单项,对应form的代码
<form action="<c:url value='/Upload1Servlet'/>" method="post" enctype="multipart/form-data"> 用户名;<input type="text" name="username"/><br/> 照 片:<input type="file" name="zhaoPian"/><br/> <input type="submit" value="上传"/> </form>
注意方法post,enctype和type="file"
下面这个上传协议内容说明了简单文本的上传。
POST /day22_1/Upload1Servlet HTTP/1.1 Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */* Referer: http://pc-201706241553:8080/day22_1/form1.jsp Accept-Language: zh-CN User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/7.0) Content-Type: multipart/form-data; boundary=---------------------------7e22e5382051c UA-CPU: AMD64 Accept-Encoding: gzip, deflate Host: pc-201706241553:8080 Content-Length: 469 Connection: Keep-Alive Cache-Control: no-cache Cookie: JSESSIONID=474036FE3AE8CF0AE6DF94DD1F566561 -----------------------------7e22e5382051c Content-Disposition: form-data; name="username" helloworld -----------------------------7e22e5382051c Content-Disposition: form-data; name="zhaoPian"; filename="myfilename.txt" Content-Type: text/plain The content of the file. the legion has returned. and the king has returned. The lord of the rings shall never exist. That is the end of the sentence.... //End.. -----------------------------7e22e5382051c-- HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/html;charset=utf-8 Content-Length: 0 Date: Mon, 06 Aug 2018 00:44:56 GMT
说明:在请求头之后,连续两个0X0D,0X0A,然后
-----------------------------7e22e5382051c
将上传可以分为两个部分,也即是用户界面中的2个表单项
1.文本框中 username的内容
2.文件相关内容,文件名,文件类型,文件内容
Servlet对上传文件的处理
1.打印上传的文本
request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); ServletInputStream in = request.getInputStream(); String s = IOUtils.toString(in);//该方法使用了commons-io.jar System.out.println(s);
2.使用commons-fileupload.jar
关键API:
获取ServletFileUpload :ServletFileUpload sfu=new ServletFileUpload(new DiskFileItemFactory());
获取表单项列表List<FileItem> mylist=sfu.parseRequest(request);
其中mylist.get(0)是上面所述的普通表单项,username,
FileItem fil2=mylist.get(1)就是文件表单项,对于上传的文件,可以getContentType,getSize,getName,
最关键,保存文件,新建一个File f=new File("C;/xx.txt");
使用FileItem 的write方法保存,fil2.write(f);
request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload sfu = new ServletFileUpload(factory); try { List<FileItem> fileItemList = sfu.parseRequest(request); FileItem fi1 = fileItemList.get(0); FileItem fi2 = fileItemList.get(1); System.out.println("普通表单项演示:" + fi1.getFieldName() + "=" + fi1.getString("UTF-8")); System.out.println("文件表单项演示:"); System.out.println("Content-Type: " + fi2.getContentType()); System.out.println("size: " + fi2.getSize()); System.out.println("filename: " + fi2.getName()); File destFile = new File("c:/baibing.jpg"); fi2.write(destFile); } catch (FileUploadException e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); }
3.相关细节。
a,文件保存到WEB-INF目录下,比如uploads文件夹。
b.防止乱码request.setCharacterEncoding("utf-8");
c.限制上传文件大小
//在sfu.parseRequest(request);之前调用 sfu.setFileSizeMax(100 * 1024);//限制单个文件大小为100K sfu.setSizeMax(1024 * 1024);//限制整个表单大小为1M
如果上传文件超过size,抛出异常。FileUploadException
d.上传超大文件
此时不使用c中设置文件大小,为了防止内存被撑爆,应该设置缓存,一边读一边往硬盘里写。
DiskFileItemFactory的一个构造函数可以实现该功能,参数1为缓存大小,参数2为临时文件目录。
DiskFileItemFactory factory = new DiskFileItemFactory(20*1024, new File("F:/f/temp"));
下载
下载关键API
//指定文件名 String filename1="G:/myfile.mp4"; //使用commons-io IOUtils.copy(new FileInputStream(filename1), resp.getOutputStream());
让浏览器弹出下载框,指定文件名。
可使用
response.addHeader("content-disposition", "attachment;filename=" + filename);
一个完整的例子
public class Download1Servlet extends HttpServlet { @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String filename = "C:/流光飞舞.mp3"; // 为了使下载框中显示中文文件名称不出乱码! // String framename = new String("流光%飞舞.mp3".getBytes("GBK"), "ISO-8859-1"); String framename = filenameEncoding("流光%飞舞.mp3", req); String contentType = this.getServletContext() .getMimeType(filename);//通过文件名称获取MIME类型 String contentDisposition = "attachment;filename=" + framename; // 一个流 FileInputStream input = new FileInputStream(filename); //设置头 resp.setHeader("Content-Type", contentType); resp.setHeader("Content-Disposition", contentDisposition); // 获取绑定了响应端的流 ServletOutputStream output = resp.getOutputStream(); IOUtils.copy(input, output);//把输入流中的数据写入到输出流中。 input.close(); } // 用来对下载的文件名称进行编码的! public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException { String agent = request.getHeader("User-Agent"); //获取浏览器 if (agent.contains("Firefox")) { BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; } else if(agent.contains("MSIE")) { filename = URLEncoder.encode(filename, "utf-8"); } else { filename = URLEncoder.encode(filename, "utf-8"); } return filename; } }