import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.jmimemagic.Magic; import net.sf.jmimemagic.MagicException; import net.sf.jmimemagic.MagicMatch; import net.sf.jmimemagic.MagicMatchNotFoundException; import net.sf.jmimemagic.MagicParseException; import org.apache.log4j.Logger; import com.sun.xml.internal.fastinfoset.stax.events.Util; public class DownloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected static final Logger logger=Logger.getLogger(DownloadServlet.class); private String enc = "utf-8"; private String fileRoot = ""; private int bufferSize=2048; /** * 初始化 enc,fileRoot */ public void init(ServletConfig config) throws ServletException { // TODO Auto-generated method stub String tempStr=config.getInitParameter("enc"); if(!Util.isEmptyString(tempStr)){ enc=tempStr; } tempStr=config.getInitParameter("fileRoot"); if(!Util.isEmptyString(tempStr)){ fileRoot=tempStr; } tempStr=config.getInitParameter("bufferSize"); if(!Util.isEmptyString(tempStr)){ bufferSize=Integer.parseInt(tempStr); } } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(enc); response.setContentType("text/html;charset="+enc); //获取 请求的参数 String filePath=request.getParameter("path"); String fileName=request.getParameter("filename"); if(!Util.isEmptyString(filePath)){ if(Util.isEmptyString(fileRoot)){ fileRoot=request.getSession().getServletContext().getRealPath("/"); } //获取文件的 绝对路径 String absPath=fileRoot+filePath; //获取 文件名 if(Util.isEmptyString(fileName)){ fileName=getFileName(absPath); } //安全 校验不通过 if(!checkFileSafe(filePath)){ StringBuilder sb=new StringBuilder("fileName:").append(fileName).append(" is invalid!"); if(logger.isDebugEnabled()){ logger.debug(sb.toString()); } response.setContentLength(sb.length()); response.getWriter().print(sb.toString()); return; } if(!Util.isEmptyString(absPath)){ try { if(logger.isDebugEnabled()){ StringBuilder sb=new StringBuilder("fileName:").append(fileName).append(",file absolute path:").append(absPath); logger.debug(sb.toString()); } //下载文件 开始 downloadFile(response,absPath,fileName); } catch (Exception e) { StringBuilder sb=new StringBuilder("download file exception,fileName:").append(fileName).append(",file absolute path:").append(absPath); logger.debug(sb.toString(), e); sb.delete(0, sb.length()); sb.append("<script type=\"text/javascript\">alert(\"download file err.\");</script>"); response.setCharacterEncoding(enc); response.setContentLength(sb.length()); response.getWriter().write(sb.toString()); return; } } }else{ StringBuilder sb=new StringBuilder("fileName:").append(fileName).append(",file directory not exists!"); logger.debug(sb.toString()); response.setContentLength(sb.length()); response.getWriter().print(sb.toString()); return; } } /** * 下载文件 * * @param response * @param absPath 文件的绝对路径 * @param fileName 文件的名字 空时 默认为 绝对路径的文件名 可以有后缀 或无后缀 * @throws IOException */ private void downloadFile(HttpServletResponse response,String absPath,String fileName) throws IOException{ File file=new File(absPath); //判断文件是否存在 和 可读性 if(!file.exists()|| !file.canRead()){ throw new RuntimeException(" File not exists or can not be read."); } String contentType=""; String conentDisposition="attachment;"; if(!Util.isEmptyString(fileName) || !fileName.contains(".")){ contentType=getContentType(file,false); if(Util.isEmptyString(contentType)){ contentType="application/x-msdownload"; } } response.reset(); FileInputStream fis=new FileInputStream(file); int contentLengh = fis.available(); if(Util.isEmptyString(fileName)){ response.setHeader("Content-Disposition",conentDisposition); response.setContentType(contentType); }else if(fileName.contains(".")){ //如果文件有后缀名 可以不用设置 contentType 浏览器会自动判断文件类型 response.setHeader("Content-Disposition",conentDisposition+"filename="+convertFileName(fileName)); } else{ //如果文件名没有后缀名 需要设置contentType response.setContentType(contentType); response.setHeader("Content-Disposition",conentDisposition+"filename="+convertFileName(fileName)); } if(contentLengh>0){ response.setContentLength(contentLengh); } ServletOutputStream sops=response.getOutputStream(); copyStream(fis,sops,true); fis.close(); sops.close(); fis=null; sops=null; file=null; } /** * 复制流 到 前端浏览器 * @param source 源文件输入流 * @param dest 输出流 * @param flush * @return */ private final long copyStream(InputStream source,OutputStream dest,boolean flush){ int bytes; long total=0l; byte [] buffer=new byte[bufferSize]; try { while((bytes=source.read(buffer))!=-1){ if(bytes==0){ bytes=source.read(); if(bytes<0) break; dest.write(bytes); if(flush) dest.flush(); total+=bytes; } dest.write(buffer,0,bytes); if(flush) dest.flush(); total+=bytes; } } catch (IOException e) { throw new RuntimeException("IOException caught while copying.",e); } return total; } /** * 根据传入的路径获取文件名 * @param filePath * @return */ private String getFileName(String filePath){ if(Util.isEmptyString(filePath)){ return ""; } int index1=filePath.lastIndexOf("/"); int index2=filePath.lastIndexOf("//"); int index=index1 > index2 ?index1:index2; if(index==-1) return filePath; String fileName=filePath.substring(index+1); return fileName; } /** * 转换中文文件名 * @param cfilename 中文文件名 * @return */ private String convertFileName(String filename){ try { filename=URLEncoder.encode(filename,enc); } catch (Exception e) { e.printStackTrace(); } return filename; } /** * 获取文件的类型 * @param file * @return * @throws MagicParseException * @throws MagicMatchNotFoundException * @throws MagicException */ private String getContentType(File file,boolean extensionHints){ try { Magic parser = new Magic(); MagicMatch match = parser.getMagicMatch(file, extensionHints); return match.getMimeType(); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 文件名的安全检查,以免被人通过"../../../"的方式获取其它文件 * @param filePath * @return false:不安全 ture:安全 */ private boolean checkFileSafe(String filePath){ return !filePath.contains("../"); } }