Zip Download Servlet
by tgutwin
Posted on Sunday Oct 16, 2016 at 12:33PM in Programming
I needed a simple Java Servlet to zip a directory of files (or a single file) with parameters to dynamically specify what to zip up.
It does NOT create a temp file; it zips and streams the output directly to the client.
its called ZipFiles.
Here it is...
/* * $HeadURL: svn://svn.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/servlet/ZipFiles.java $ * $Revision: 1105 $ * $LastChangedDate: 2016-05-16 19:19:44 -0700 (Mon, 16 May 2016) $ * $LastChangedBy: tgutwin $ * Copyright (c) 2016 Tom B. Gutwin P.Eng. North Vancouver BC Canada * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see <http://www.gnu.org/licenses/>. */ package ca.bc.webarts.servlet; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.oreilly.servlet.ParameterParser; import com.oreilly.servlet.ParameterNotFoundException; import com.oreilly.servlet.ServletUtils; /** * <h1>Downloading single or Multiple Files As Zip file.</h1> * * <h2>3 steps to implement</h2><ol><li>add this class to WEB-INF/classes</li> * <li>add the following to your web.xml file<pre> <servlet> <servlet-name>ZipFiles</servlet-name> <servlet-class>ca.bc.webarts.servlet.ZipFiles</servlet-class> </servlet> <servlet-mapping> <servlet-name>ZipFiles</servlet-name> <url-pattern>/zipfiles/*</url-pattern> </servlet-mapping> </servlet> </pre></li><li>Add the URL link to your webpage (html or jsp). The syntax (based on the mapping you setup in the web.xml) * and parameters are as follows:<ul><li>http://<yourWebServerAddress>/<yourWebAppContextName><b>/zipfiles/?filename=<fileToZip>&dirname=<suDirWhereFileLives></b></li> * <li> example: http://warp4.webarts.bc.ca/tunes/ZipFiles/?filename=AThousandSuns_03-Radiance.ogg&dirname=mythTunes/LinkinPark/AThousandSuns</li> * <li> NOTE: filename param is OPTIONAL. if NOT provided, this servlet will zip all files in the dirname.</li> * </ul> * </li> * </ol> * <h3> This code is Copyright © 2016 Tom B. Gutwin P.Eng. North Vancouver BC Canada,</h3><h4>and relesed under the <a href="http://www.gnu.org">GNU</a> * <a href="http://www.gnu.org/licenses/licenses.html#GPL">General Public License (GNU GPL)</a>.</h4> */ public class ZipFiles extends HttpServlet { private static final long serialVersionUID = -2767248383788052391L; /** Class constant. **/ protected static final String className_ = "ZipFiles"; private final static String SYSTEM_FILE_SEPERATOR = File.separator; /** Version String. */ private final static String SERVLET_VERSION = "0.01_[$Rev: 1105 $]"; /** Build String. (yymmddhhss) */ private final static String BUILD_TAG = "161015143718"; private static String webServerHostName_ = "warp4.webarts.bc.ca"; private boolean debugOut_ = false; /** flag if the parms have specified a file (true) or a dir (false) to zip. **/ private boolean fileZip_ = true; /** flag if the parms are valid. **/ private boolean validParms_ = true; /** controls if extra info is dumped to system.out. **/ private String debugOut = ""; /** not used. **/ private String browserName = ""; /** not used. **/ private String browserVersion = ""; /** Servlet parameter to specify the specific file(name) to zip up and return. **/ private String filename = ""; /** Servlet parameter to specify the specific directory to zip up and return; OR if a filename is ALSO specified, the dire where the file exists. **/ private String dirname = ""; private String someParamYouWannaSet_ = ""; /** * Gets the ServletInfo attribute of this servlet * * @return The ServletInfo value */ public String getServletInfo() { final String methodName = "getServletInfo"; return "WebARTS Design ZipFiles servlet. Version:" + SERVLET_VERSION + " Build:" + BUILD_TAG; } /** * The one time servlet init stuff goes here. It sets the derbyDBDir based on the following prioritized varables: * <ol><li>context init param: derbyDBDir</li><li>servlet init param (from web.xml): derbyDBDir</li> * <li>default hardcoded variable: derbyDBDir</li></ol>If defined in multiple places, the higher priority item will * be used. **/ public void init() { System.out.println("\n~~~~~~~~\n~~~~~~~~\nInitializing ca.bc.webarts.servlet.ZipFiles\n~~~~~~~~\n~~~~~~~~"); boolean notFoundInit = true; boolean notFoundContext = true; java.util.Enumeration <String> initEnum = getInitParameterNames(); for (; notFoundInit && initEnum.hasMoreElements();) { if(initEnum.nextElement().equals("someParamYouWannaSet")) { notFoundInit = false; /* Do something with the init param */ someParamYouWannaSet_ = getInitParameter("someParamYouWannaSet"); System.out.println("\n~~~~~~~~\n INIT ServletParam: someParamYouWannaSet="+someParamYouWannaSet_); } } //also check context initEnum = getServletConfig().getServletContext().getInitParameterNames(); for (; notFoundContext && initEnum.hasMoreElements();) { if(initEnum.nextElement().equals("someParamYouWannaSet")) { notFoundContext = false; /* Do something with the init param */ someParamYouWannaSet_ = getServletConfig().getServletContext().getInitParameter("baseDir"); System.out.println("\n~~~~~~~~\n INIT ContextParam: someParamYouWannaSet="+someParamYouWannaSet_); } } if(notFoundInit && notFoundContext ) { /* Set the default values */ //eagleDBDir_ = pEye_.getDerbyDBDir(); } try { webServerHostName_ = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException ex) { webServerHostName_ = "warp4.webarts.bc.ca"; } } /** Override to close Things up. **/ public void destroy() { super.destroy(); } /** Parses any defined servlet params into the defined class vars. **/ private void parseParams(HttpServletRequest req) { ParameterParser parser = new ParameterParser(req); if(debugOut_) { System.out.println("\nRequest Params:"); Enumeration<String> parmNames = req.getParameterNames(); for (; parmNames.hasMoreElements();) { String currParamName = (String) parmNames.nextElement(); System.out.println(" "+currParamName+"="+req.getParameter(currParamName)); } } /* parse out the requeSystem.out.println("lastFmst params into class vars */ debugOut = parser.getStringParameter("debugOut", ""); browserName = parser.getStringParameter("clientBrowser",""); browserVersion = parser.getStringParameter("clientBrowserVersion",""); filename = parser.getStringParameter("filename",""); dirname = parser.getStringParameter("dirname",""); if(filename.equals("")) { fileZip_=false; if(dirname.equals("")) validParms_=false; } if(debugOut_) { System.out.println(" filename="+filename+" dirname="+dirname );} } /** * Initisalizes File only if it is directory.It is represented by the passed * in String. * * @param s the directory name to init as a File * @return An instatiated File object if the passed string is a dir, null * if not */ private static File initDirFile(String s) { File retVal = null; File dirFile = new File(s); if (dirFile.isDirectory() && dirFile.canRead()) { retVal = dirFile; } return retVal; } /** * Takes a dirname and lists the contained files in an ArrayList for easier processing. * * @param d the directory name to scan for Files * @return An instatiated ArrayList object full of the contained files or null if invalid. */ private ArrayList <File> listDirFiles(String d) { ArrayList retVal = new ArrayList();; File dirToList = initDirFile(d); if (dirToList != null) { String[] files = dirToList.list(); File tempFile; //loop through all the files in the dir for (int i = 0; i < files.length; i++) { tempFile = new File(d + File.separator + files[i]); if (tempFile.isDirectory()) { // recurse on the subdirectory if(debugOut_) System.out.println("Adding DIR to list " + d + File.separator + files[i]); retVal.addAll(listDirFiles(d + File.separator + files[i])); } else { if(debugOut_) System.out.println("Adding to list " + d + File.separator + files[i]); retVal.add(new File(d + File.separator + files[i])); } } } else { if(d!=null && !d.equals("")) { if(debugOut_) System.out.println("Adding to list: " + d ); retVal.add(new File(d)); } else retVal = null; } return retVal; } /** Servlet get processing method. **/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { parseParams(request); ServletContext context = getServletConfig().getServletContext(); String cPath = context.getRealPath("/"); if(validParms_) { String zipFilename = (fileZip_? filename.substring(0, (filename.lastIndexOf(".")>0? filename.lastIndexOf("."): filename.length()))+".zip" : dirname+".zip"); ServletOutputStream out = response.getOutputStream(); String conPath = request.getContextPath(); if(debugOut_) { System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~"); System.out.println("ZipFiles.doGet debugOut="+debugOut); System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~"); } // Set the content type based to zip response.setContentType("Content-type: text/zip"); response.setHeader("Content-Disposition", "attachment; filename="+zipFilename); // List of files to be downloaded String fPath = cPath+File.separator+(dirname.equals("")?"":dirname+File.separator)+filename; ArrayList <File> filesList = listDirFiles(fPath); if(debugOut_) System.out.println("Searching for file in " + fPath); if(filesList!=null) { ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(out)); for (File file : filesList) { if(debugOut_) System.out.println("Adding to zip" + file.getName()); zos.putNextEntry(new ZipEntry(file.getName())); // Get the file FileInputStream fis = null; try { fis = new FileInputStream(file); } catch (FileNotFoundException fnfe) { // If the file does not exists, write an error entry instead of // file // contents zos.write(("ERROR: could not find file " + file.getName()) .getBytes()); zos.closeEntry(); System.out.println("Could find file " + file.getAbsolutePath()); continue; } BufferedInputStream fif = new BufferedInputStream(fis); // Write the contents of the file int data = 0; while ((data = fif.read()) != -1) { zos.write(data); } fif.close(); zos.closeEntry(); System.out.println("Finished zipping file " + file.getName()); } zos.close(); } } } }