您的位置:首页 > 编程语言 > Java开发

java文件上传与下载

2016-12-11 23:22 302 查看
今天我们来看一下java web中的文件上传与下载

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