简介
文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件上传功能。common-fileupload组件是apache的一个开源项目之一,可以从http://jakarta.apache.org/commons/fileupload/下载。用该组件可实现一次上传一个或多个文件,并可限制文件大小。
开发环境
创建一个javaweb项目,加入common-fileupload组件(commons-fileupload-1.3.1.jar,commons-io-2.4.jar)
完整的项目路径如下:
需要下载4个jar包
文件上传
文件上传界面:file.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"><br/>
上传文件1:<input type="file" name="file1"><br/>
上传文件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
消息提示界面:message.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>消息提示</title>
</head>
<body>
${message}
</body>
</html>
web.xml文件
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>upload.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
<servlet>
java文件:UploadServlet.java
package 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.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 UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = request.getSession().getServletContext().getRealPath("");
savePath =savePath.substring(0,savePath.indexOf(".metadata"))+"Store\\WebContent\\upload";
System.out.println("上传到目录"+savePath);
File file = new File(savePath);
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath+"目录不存在,需要创建");
//创建目录
file.mkdir();
}
//消息提示
String message = "";
try{
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
//3、判断提交上来的数据是否是上传表单的数据
if(!ServletFileUpload.isMultipartContent(request)){
//按照传统方式获取数据
return;
}
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(request);
for(FileItem item : list){
//如果fileitem中封装的是普通输入项的数据
if(item.isFormField()){
String name = item.getFieldName();
//解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
//value = new String(value.getBytes("iso8859-1"),"UTF-8");
System.out.println(name + "=" + value);
}else{//如果fileitem中封装的是上传文件
//得到上传的文件名称,
String filename = item.getName();
System.out.println(filename);
if(filename==null || filename.trim().equals("")){
continue;
}
//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
//处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename = filename.substring(filename.lastIndexOf("\\")+1);
//获取item中的上传文件的输入流
InputStream in = item.getInputStream();
//创建一个文件输出流
FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
//创建一个缓冲区
byte buffer[] = new byte[1024];
//判断输入流中的数据是否已经读完的标识
int len = 0;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while((len=in.read(buffer))>0){
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
out.write(buffer, 0, len);
}
//关闭输入流
in.close();
//关闭输出流
out.close();
//删除处理文件上传时生成的临时文件
item.delete();
message = "文件上传成功!";
}
}
}catch (Exception e) {
message= "文件上传失败!";
e.printStackTrace();
}
request.setAttribute("message",message);
request.getRequestDispatcher("jsp/message.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doGet(request, response);
}
}
效果如下:
下载文件
下载界面文件:listFile.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style>
table{
font-family: verdana,arial,sans-serif;
font-size:11px;
color:#333333;
border-width: 1px;
border-color: #666666;
border-collapse: collapse;
}
th {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #dedede;
}
td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #f8f8f8;
}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>下载文件显示页面</title>
</head>
<body>
<!-- 遍历Map集合 -->
<table style="border:1px solid #F00">
<tr>
<th >文件名</th>
<th >操作</th>
</tr>
<!--jstl标签库中的<c:url>和<c:param>标签,前者将产生一个URL地址,后者为这个地址添加一个filename文件名的参数。 生成诸如:/Store/download?filename=S68DSS.png 的路径-->
<c:forEach var="me" items="${fileNameMap}">
<c:url value="/download" var="downurl">
<c:param name="filename" value="${me.key}"></c:param>
</c:url>
<tr>
<td>${me.value}</td>
<td><a href="${downurl}">下载</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
web.xml 添加配置
<servlet>
<servlet-name>ListFileServlet</servlet-name>
<servlet-class>upload.ListFileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListFileServlet</servlet-name>
<url-pattern>/listFile</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>upload.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/download</url-pattern>
</servlet-mapping>
文件列表数据返回java文件:ListFileServlet .java
package upload;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ListFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取上传文件的目录
String savePath = request.getSession().getServletContext().getRealPath("");
String uploadFilePath =savePath.substring(0,savePath.indexOf(".metadata"))+"Store\\WebContent\\upload";
// 存储要下载的文件名
Map<String, String> fileNameMap = new HashMap<String, String>();
// 递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中
listFile(new File(uploadFilePath), fileNameMap);// File既可以代表一个文件也可以代表一个目录
// 将Map集合发送到listfile.jsp页面进行显示
for (String key : fileNameMap.keySet()) {
System.out.println("Key = " + key);
}
//遍历map中的值
for (String value : fileNameMap.values()) {
System.out.println("Value = " + value);
}
request.setAttribute("fileNameMap", fileNameMap);
request.getRequestDispatcher("jsp/listFile.jsp").forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
/**
* 递归遍历指定目录下的所有文件
* @param file
* @param map
*/
public void listFile(File file, Map<String, String> map) {
if(file == null) return;
// 如果file代表的不是一个文件,而是一个目录
if (!file.isFile()) {
// 列出该目录下的所有文件和目录
File files[] = file.listFiles();
if(files == null) return;
// 遍历files[]数组
for (File f : files) {
// 递归
listFile(f, map);
}
} else {
String realName = file.getName().substring(file.getName().indexOf("_") + 1);
// file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复
map.put(file.getName(), realName);
}
}
}
文件下载java类:DownloadServlet.java
package upload;
import javax.servlet.http.HttpServlet;
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("请求。。。url");
// 得到要下载的文件名
String fileName = request.getParameter("filename"); // 2323928392489-美人鱼.avi
fileName = new String(fileName.getBytes("iso8859-1"), "UTF-8");
// 上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
String savePath = request.getSession().getServletContext().getRealPath("");
String fileSaveRootPath =savePath.substring(0,savePath.indexOf(".metadata"))+"Store\\WebContent\\upload";
// 得到要下载的文件
File file = new File(fileSaveRootPath + "\\" + fileName);
// 如果文件不存在
if (!file.exists()) {
request.setAttribute("message", "您要下载的资源已被删除!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
// 处理文件名
String realname = fileName.substring(fileName.indexOf("_") + 1);
// 设置响应头,控制浏览器下载该文件
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
// 读取要下载的文件,保存到文件输入流
FileInputStream in = new FileInputStream(fileSaveRootPath + "\\" + fileName);
// 创建输出流
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();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
效果如下:
需注意的细节
1.提交request请求消息体带有的参数含有中文数据时,需要对其进行URL编码
2.对URL进行编码的,不能直接取出其值,需要进行iso8859-1解码,在用指定的编码方式编码
3.需要设置response head的content-disposition头,值为attachment;filename=文件名
4.设置content-type值为application/x-msdownload
5.解析文件时需要通过文件名来获取其存储路径
Servlet中获取路径问题
/**
* Servlet中获取路径
* @author hp
*
*/
public class HandlePath extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("1. request.getContextPath()="+request.getContextPath());
System.out.println("2. request.getLocalAddr() ="+request.getLocalAddr());
System.out.println("3. request.getRequestURL() ="+request.getRequestURL());
System.out.println("4. request.getRequestURI() ="+request.getRequestURI());
System.out.println("5. request.getServletPath()="+request.getServletPath());
System.out.println("6. request.getRealPath('') ="+request.getRealPath(""));
System.out.println("7. System.getProperty('user.dir')="+System.getProperty("user.dir"));
System.out.println("8. getServletContext().getContextPath()="+getServletContext().getContextPath());
System.out.println("9. getServletContext().getRealPath('/')="+getServletContext().getRealPath("/"));
System.out.println("10.getClass().getClassLoader().getResource('/').getPath()="+getClass().getClassLoader().getResource("/").getPath());
}
}
通过eclipse的AddAndRemove发布项目:结果