咱们要将Web应用系统中的文件资源提供给用户进行下载,首先咱们要有一个页面列出上传文件目录下的全部文件,当用户点击文件下载超连接时就进行下载操做,编写一个ListFileServlet,用于列出Web应用系统中全部下载文件
获取文件列表
package me.gacl.web.controller;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ListFileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取上传文件的目录
String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
//存储要下载的文件名
Map<String,String> fileNameMap = new HashMap<String,String>();
//递归遍历filepath目录下的全部文件和目录,将文件的文件名存储到map集合中
listfile(new File(uploadFilePath),fileNameMap);//File既能够表明一个文件也能够表明一个目录
//将Map集合发送到listfile.jsp页面进行显示
request.setAttribute("fileNameMap", fileNameMap);
request.getRequestDispatcher("/listfile.jsp").forward(request, response);
}
public void listfile(File file,Map<String,String> map){
//若是file表明的不是一个文件,而是一个目录
if(!file.isFile()){
//列出该目录下的全部文件和目录
File files[] = file.listFiles();
//遍历files[]数组
for(File f : files){
//递归
listfile(f,map);
}
}else{
/**html
处理文件名,上传后的文件是以uuid_文件名的形式去从新命名的,去除文件名的uuid部分
file.getName().indexOf("")检索字符串中第一次出现"_"字符的位置,若是文件名相似于:9349249849-88343-8344_阿_凡达.avi
那么file.getName().substring(file.getName().indexOf("")+1)处理以后就能够获得阿_凡达.avi部分
*/
String realName = file.getName().substring(file.getName().indexOf("")+1);
//file.getName()获得的是文件的原始名称,这个名称是惟一的,所以能够做为key,realName是处理事后的名称,有可能会重复
map.put(file.getName(), realName);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
ListFileServlet中listfile方法,listfile方法是用来列出目录下的全部文件的,listfile方法内部用到了递归,在实际开发当中,咱们确定会在数据库建立一张表,里面会存储上传的文件名以及文件的具体存放目录,咱们经过查询表就能够知道文件AxiTrader代理申请www.fx61.com/brokerlist/axitrader.html的具体存放目录,是不须要用到递归操做的,这个例子是由于没有使用数据库存储上传的文件名和文件的具体存放位置,而上传文件的存放位置又使用了散列算法打散存放,因此须要用到递归,在递归时,将获取到的文件名存放到从外面传递到listfile方法里面的Map集合当中,这样就能够保证全部的文件都存放在同一个Map集合当中。
配置
在Web.xml文件中配置ListFileServlet
<servlet>
<servlet-name>ListFileServlet</servlet-name>
<servlet-class>me.gacl.web.controller.ListFileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListFileServlet</servlet-name>
<url-pattern>/servlet/ListFileServlet</url-pattern>
</servlet-mapping>
下载页面
展现下载文件的listfile.jsp页面以下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML>
<html>
<head>
<title>下载文件显示页面</title>
</head>
<body>
<!-- 遍历Map集合 -->
<c:forEach var="me" items="${fileNameMap}">
<c:url value="/servlet/DownLoadServlet" var="downurl">
<c:param name="filename" value="${me.key}"></c:param>
</c:url>
${me.value}<a href="${downurl}">下载</a>
<br/>
</c:forEach>
</body>
</html>
实现文件下载
编写一个用于处理文件下载的Servlet,DownLoadServlet的代码以下:
public class DownLoadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获得要下载的文件名
String fileName = request.getParameter("filename"); //23239283-92489-阿凡达.avi
//上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
//经过文件名找出文件的所在目录
String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
//获得要下载的文件
File file = new File(path + "\" + 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(path + "\" + 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();
}
public String findFileSavePathByFileName(String filename,String saveRootPath){
int hashcode = filename.hashCode();
int dir1 = hashcode&0xf; //0--15
int dir2 = (hashcode&0xf0)>>4; //0-15
String dir = saveRootPath + "\" + dir1 + "\" + dir2; //upload\2\3 upload\3\5
File file = new File(dir);
if(!file.exists()){
//建立目录
file.mkdirs();
}
return dir;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
配置
<servlet>
<servlet-name>DownLoadServlet</servlet-name>
<servlet-class>me.gacl.web.controller.DownLoadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownLoadServlet</servlet-name>
<url-pattern>/servlet/DownLoadServlet</url-pattern>
</servlet-mapping>
1.html5支持的文件下载
很是简单代码以下:
<a download="下载文件.txt">下载文件</a>
这种方式不支持ie浏览器
2.须要后台支持的文件下载:
前端代码以下:
function getRootPath() {
//获取当前网址,如: http://localhost:8083/uimcardprj/share/meun.jsp
var curWwwPath = window.document.location.href;
//获取主机地址以后的目录,如: uimcardprj/share/meun.jsp
var pathName = window.document.location.pathname;
var pos = curWwwPath.indexOf(pathName);
//获取主机地址,如: http://localhost:8083
var localhostPaht = curWwwPath.substring(0, pos);
//获取带"/"的项目名,如:/uimcardprj
var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
return (localhostPaht + projectName);
}
function downloadExcel(fileName) {
fileName = encodeURI(fileName);
var url = getRootPath() + "/static/excel/" + fileName;
window.location.href = "data/downloadexcel?fileName=" + fileName + "&url=" + url;
}
此处须要传递下载文件的文件名称与文件的地址(为了不服务器路径问题,此处直接使用前端传递的url路径地址,这种方式也能够用来下载第三方网站上的文件资源),注意对于文件名称须要处理文件名称中的中文字符与特殊字符须要使用js方法encodeURI对文件名称编码
后台代码:
/**前端
/**html5
@Description: ie, chrom, firfox下处理文件名显示乱码
*/
public static String processFileName(HttpServletRequest request,
String fileNames) {
String codedfilename = null;
try {
String agent = request.getHeader("USER-AGENT");
if (null != agent && agent.indexOf("MSIE") > -1 || null != agent
&& agent.indexOf("Trident") > -1) {// ie
String name = java.net.URLEncoder.encode(fileNames, "UTF8").replaceAll("\+","%20");
codedfilename = name;
} else {// 火狐,chrome等java
codedfilename = new String(fileNames.getBytes("UTF-8"), "iso-8859-1"); }
} catch (Exception e) {
logger.error("文件名称编码出错", e);
}
return codedfilename;
}
下载文件代码须要注意的地方就只有文件名称的编码问题,其余代码很简单,须要特别注意URLEncoder.encode将空格转换为+,须要特殊处理转换为%20
3.下载后台实时生成的文件
简单的后台实时生成文件基本代码和步骤二一致,只是将从网络获取的文件改成从本机获取就好了
4.使用post方法下载文件
post方法下载文件主要能够经过两种方式解决
第一种将post提交到当前页面的隐藏iframe便可,但这种方式在ie和chmore中会有两种表现形式(一种直接在当前页面下载,一种会打开一个空白页下载)
var downLoadFile = function (options) {
var config = $.extend(true, {method: 'post'}, options);
var $iframe = $('<iframe id="down-file-iframe" />');
var $form = $('<form target="down-file-iframe" method="' + config.method + '" />');
$form.attr('action', config.url);
for (var key in config.data) {
var input = $("<input hidden>");
input.attr("name", key);
input.val(config.data[key]);
$form.append(input);
}
$iframe.append($form);
$(document.body).append($iframe);
$form[0].submit();
$iframe.remove();
}
//调用方法
downLoadFile({
url: '...', //请求的url
data: {
name:"",
size:"",
......
}//要发送的数据
});
使用以上方式便可使用post的方法下载文件
第二种方法很简单,能够先用post方式上传参数,将参数以缓存的形式存储在服务端并返回key给前端,再在post的回调方法中使用get方式传递key给后台下载文件
样例代码很简单,以下:
$.post("download",params, function (data) {
if (data.success) {
window.location.href = "download?generatorId=" + data.data;
} else {
alert(data.msg);
}
})web