java文件上传与下载
2016-12-11 23:22
302 查看
今天我们来看一下java web中的文件上传与下载
1.首先我们给出一个上传文件的界面,一个jsp页面。
注意,这里需要加上enctype=”multipart/form-data”,告诉服务器,我们将表单数据以二进制数据的方式传递给你。所以这时服务器用request.getParameter(“name”);是无法得到值得。此时的数据都是以byte来传递的。
Form的enctype属性为编码,他有下列几个常用值:
application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。
multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分,这个一般文件上传时用。
text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
2.我们还需要有个处理文件上传的Servlet.
3.我们再写一个jsp页面,来告诉用户是否上传成功。
以上就是一个最基本的文件上传操作的展示了。但是这里还有很多问题没有考虑进去。上传文件有一下几点需要特别注意
**1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。
4、要限制上传文件的最大值。
5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。**
下面给出改进后的代码:
1.下面来看一下文件下载:
1.首先我们给出一个上传文件的界面,一个jsp页面。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%-- application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。 multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分,这个一般文件上传时用。 text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。 --%> <form action="UpLoadHandler"enctype="multipart/form-data" method="post"> <input type="text" name="username"><br> <input type="password" name="password"><br> <input type="file" name="file1"><br> <input type="file" name="file2"><br> <input type="submit" value="提交"> </form> </body> </html>
注意,这里需要加上enctype=”multipart/form-data”,告诉服务器,我们将表单数据以二进制数据的方式传递给你。所以这时服务器用request.getParameter(“name”);是无法得到值得。此时的数据都是以byte来传递的。
Form的enctype属性为编码,他有下列几个常用值:
application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。
multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分,这个一般文件上传时用。
text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
2.我们还需要有个处理文件上传的Servlet.
package wangcc.upload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; 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; @WebServlet("/UpLoadHandler") public class UpLoadHandler extends HttpServlet { /** * Constructor of the object. */ public UpLoadHandler() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to * post. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String savepath = this.getServletContext().getRealPath( "/WEB-INF/upload"); System.out.println("存储路径为:" + savepath); File file = new File(savepath); if (!file.exists() && !file.isDirectory()) { // 创建此抽象路径名指定的目录 // mkdirs()创建此抽象路径名指定的目录,包括所有必须但不存在的父目录 file.mkdir(); } String message = ""; try { // 1. 创建一个工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 2.创建一个文件解析器 ServletFileUpload upload = new ServletFileUpload(factory); // 解决文件名中文乱码问题 upload.setHeaderEncoding("UTF-8"); // 3. 判断是否为为表单传递方法 if (!ServletFileUpload.isMultipartContent(request)) { return; } // 4.使用ServletFileUpload解析器解析上传数据 /** * 会把表单的每个数据当做一个FileItem * 是以流的方式上传,所以这个时候我们无法通过request.getParameter(""); 来获取数据 */ List<FileItem> list = upload.parseRequest(request); for (FileItem item : list) { // 首先判断这是否为表单普通数据 if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString("UTF-8"); System.out.println("name:" + name + "value:" + value); } else { String filename = item.getName(); System.out.println("文件路径全名:" + filename); // 处理字符串,我们要对字符串filename进行处理,因为不同的浏览器返回的路径不一定相同 // 目录层可能不一样,所以在这里我们只需要获得文件名即可 if (filename == null || filename.trim().equals("")) { continue; } filename = filename .substring(filename.lastIndexOf("\\") + 1); String realPath = savepath + "\\" + filename; InputStream in = item.getInputStream(); FileOutputStream out = new FileOutputStream(realPath); int len = 0; byte[] buffer = new byte[1024]; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } in.close(); out.close(); message = "上传文件成功"; } } } catch (Exception e) { message = "上传文件失败"; // TODO: handle exception } request.setAttribute("message", message); request.getRequestDispatcher("/message.jsp").forward(request, response); } /** * Initialization of the servlet. <br> * * @throws ServletException * if an error occurs */ public void init() throws ServletException { // Put your code here } }
3.我们再写一个jsp页面,来告诉用户是否上传成功。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> ${message} </body> </html>
以上就是一个最基本的文件上传操作的展示了。但是这里还有很多问题没有考虑进去。上传文件有一下几点需要特别注意
**1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。
4、要限制上传文件的最大值。
5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。**
下面给出改进后的代码:
package wangcc.upload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID; 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.FileUploadBase; import org.apache.commons.fileupload.ProgressListener; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * @ClassName: NewUpLoadHandler * @Description: TODO(这里用一句话描述这个类的作用) * @author wangcc * @date 2016年12月11日 下午8:47:20 1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。 * * 2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。 * * 3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。 * * 4、要限制上传文件的最大值。 * * 5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。 * */ @WebServlet("/NewUpLoadHandler") public class NewUpLoadHandler extends HttpServlet { /** * Constructor of the object. */ public NewUpLoadHandler() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to * post. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String savePath = this.getServletContext().getRealPath( "/WEB-INF/newUpload"); String tempPath = this.getServletContext().getRealPath("WEB-INF/temp"); String message = ""; File temp = new File(tempPath); if (!temp.exists() && !temp.isDirectory()) { temp.mkdir(); } try { DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。 factory.setSizeThreshold(1024 * 100);// //设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB // 指定临时目录 factory.setRepository(temp); ServletFileUpload newUpload = new ServletFileUpload(factory); // 监听上传文件进度, // thinking:是否可以通过ajax异步传输技术使得用户可以在页面中得到文件上传进度。 newUpload.setProgressListener(new ProgressListener() { @Override public void update(long pBytesReaded, long PContentLength, int arg2) { // TODO Auto-generated method stub System.out.println("文件大小:" + PContentLength + ",当前已处理:" + pBytesReaded); } }); newUpload.setHeaderEncoding("UTF-8"); // 判断是否是传统方式传输: /** * 也就是说:判断是否是<form * action="UpLoadHandler"enctype="multipart/form-data" * method="post"> 而不是<form action="UpLoadHandler"method="post">的传统方式 */ if (!ServletFileUpload.isMultipartContent(request)) { return; } // 设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB newUpload.setFileSizeMax(1024 * 1024); // 设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB newUpload.setFileSizeMax(1024 * 1024 * 10); List<FileItem> list = newUpload.parseRequest(request); for (FileItem item : list) { if (item.isFormField()) { String name = item.getName(); String value = item.getString("UTF-8"); System.out.println(name + " " + value); } else { String filename = item.getName(); filename = filename .substring(filename.lastIndexOf("\\") + 1); // 可以获得文件的后缀扩展名,可以通过获取这个来限制上传文件的类型 String fileExtName = filename.substring(filename .lastIndexOf(".") + 1); System.out.println("上传的文件的扩展名是:" + fileExtName); filename = makeFileName(filename); String realparentpath = makePath(filename, savePath); String realPath = realparentpath + "\\" + filename; InputStream in = item.getInputStream(); FileOutputStream out = new FileOutputStream(realPath); int len = 0; byte[] buffer = new byte[1024]; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } in.close(); out.close(); message = "上传文件成功"; } } } catch (FileUploadBase.FileSizeLimitExceededException e) { e.printStackTrace(); message = "抱歉,上传失败,单个文件太大"; } catch (FileUploadBase.SizeLimitExceededException e) { e.printStackTrace(); message = "抱歉,上传失败,文件总量太大"; } catch (Exception e) { message = "上传失败"; // TODO: handle exception } request.setAttribute("message", message); request.getRequestDispatcher("/message.jsp").forward(request, response); } private String makeFileName(String filename) { return UUID.randomUUID().toString() + "_" + filename; } private String makePath(String filename, String savePath) { int hashcode = filename.hashCode(); // 0x代表这个数字是16进制 /** * 0xf f:15 1111 0xf0 11110000 & 运算符 均为1时才为1 */ int dir1 = hashcode & 0xf;// 得到的值在0-15 // >>右移运算符,移出的部分将被抛弃 int dir2 = (hashcode & 0xf0) >> 4;// 得到的值在0-15之间 /** * 其实上面两行的代码得到的值得差别便是: 一个用hashcode的低八位中的高四位来与0xf来进行与操作 * 一个用hashcode的低八位中的低四位来与0xf来进行与操作 */ String dir = savePath + "\\" + dir1 + "\\" + dir2; File file = new File(dir); if (!file.exists()) { file.mkdirs(); } return dir; } /** * Initialization of the servlet. <br> * * @throws ServletException * if an error occurs */ public void init() throws ServletException { // Put your code here } }
1.下面来看一下文件下载:
package wangcc.download; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/ListFileServlet") public class ListFileServlet extends HttpServlet { /** * Constructor of the object. */ public ListFileServlet() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to * post. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 通常在开发中我们通过查找数据库来获取文件路径以及文件路径名 Map<String, String> map = new HashMap<String, String>(); String savePath = this.getServletContext().getRealPath( "/WEB-INF/upload"); map.put("QQ图片20160925162552.png", savePath + "\\:QQ图片20160925162552.png"); map.put("1.png", savePath + "\\:1.png"); request.setAttribute("filelist", map); request.getRequestDispatcher("/list.jsp").forward(request, response); } /** * Initialization of the servlet. <br> * * @throws ServletException * if an error occurs */ public void init() throws ServletException { // Put your code here } }
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'list.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> This is my JSP page. <br> <c:forEach items="${filelist}" var="myfile"> <c:url var="downurl" value="/DownLoadHandler" > <c:param name="filepath" value="${myfile.value}"></c:param> </c:url><c:out value="${myfile.key}"></c:out><a href="${downurl }">下载</a><br> </c:forEach> </body> </html>
package wangcc.download; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/DownLoadHandler") public class DownLoadHandler extends HttpServlet { /** * Constructor of the object. */ public DownLoadHandler() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to * post. * * @param request * the request send by the client to the server * @param response * the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 得到文件路径名 String filepath = request.getParameter("filepath");// 设置给用户(浏览器)呈现的文件的文件名 String filename = filepath.substring(filepath.lastIndexOf(":") + 1); response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); /** * 直接用filename="+ filename会出现中文乱码 * 需要用URLEncoder.encode(filepath,"UTF-8");来防止中文乱码的产生 * * URLEncoder HTML 格式编码的实用工具类。该类包含了将 String 转换为 * application/x-www-form-urlencoded MIME 格式的静态方法。 encode(String s, * String enc) 使用指定的编码机制将字符串转换为 application/x-www-form-urlencoded * 格式。该方法使用提供的编码机制获取不安全字符的字节。 */ // 得到这个文件,然后通过response将文件响应到浏览器 :response.getOutputStream; File file = new File(filepath); if (!file.exists()) { request.setAttribute("message", "该资源已被删除"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } FileInputStream in = new FileInputStream(file); OutputStream out = response.getOutputStream(); int len = 0; byte[] buffer = new byte[1024]; while ((len = in.read()) != -1) { out.write(buffer, 0, len); } in.close(); } /** * Initialization of the servlet. <br> * * @throws ServletException * if an error occurs */ public void init() throws ServletException { // Put your code here } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Debian 7.x 安装Oracle JAVA
- springmvc实现url路由功能
- spring boot 配置 druid/** * 配置druid * Created by adam on 4/11/16. */ @Configuration public class D
- api接口rsa加密
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解