Using a servlet, how do you download multiple files from a database and zip them for client download
Asked Answered
S

2

5

I have a jsp/servlet web app in which the client can choose a "course" and an "assignment" via dropdown boxes, and then click a button to download all the files in the database that are listed under that course/assignment combination. The servlet code isn't quite working, as the zip file is not being sent to the browser as an attachment. I do have working code for downloading one file at a time, but something is getting stuck with this code for zipping the files. All the files in the database are actually zip files themselves, so I am trying to zip up a bunch of zip files. I didn't think this would require that they be treated differently than zipping any other format of files. Can anyone see what is missing? Here is my doGet method code in the servlet that handles the downloading. Much of this code was found here on stackoverflow. Please note that the FileSubmitted object is my DOA containing all the file info for each file in the database, including the Blob itself:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
    List<FileSubmitted> fileList = new ArrayList<FileSubmitted>();
    String course= request.getParameter("course");
    String assignment = request.getParameter("assignment");

    java.sql.PreparedStatement pstmt = null;
    java.sql.Connection conn = null;
    ResultSet rs;
    String queryString;

    try {
        conn = ConnectionManager.getConnection();
        conn.setAutoCommit(false);

        queryString = "SELECT * FROM files WHERE courseID=\""+course+"\" AND assignmentID=\""+assignment+"\";";
        pstmt = conn.prepareStatement(queryString);
        rs = pstmt.executeQuery(queryString);
        while(rs.next())
        {
            fileList.add(new FileSubmitted(rs.getString("username"),
                                           rs.getString("courseID"),
                                           rs.getString("assignmentID"),
                                           rs.getString("fileName"),
                                           rs.getString("mimeType"),
                                           (Blob) rs.getBlob("contents")));
        }


        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=\"allfiles.zip\"");

        ZipOutputStream output = null;
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];

        try {
            output = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE));

            for (FileSubmitted file : fileList)
            {
                InputStream input = null;
                try {
                        input = new BufferedInputStream(file.getContents().getBinaryStream(), DEFAULT_BUFFER_SIZE);
                        output.putNextEntry(new ZipEntry(file.getFileName()));
                        for (int length = 0; (length = input.read(buffer)) > 0;)
                        {
                            output.write(buffer, 0, length);
                        }
                    }//try
                    catch (SQLException e) {e.printStackTrace();}
                    finally{}
                    output.closeEntry();
            }//for
          }//try
          finally{}
     } 
     catch (Exception e1) {e1.printStackTrace();}
     finally{}
}
Stomatal answered 12/4, 2013 at 2:37 Comment(2)
please can you expand on 'something is getting stuck with this code for zipping the files' - is there an error, have you added logging to see what is going on? You could try isolating the problem by taking you zip code out of a servlet and running in a main method with a small number of known files. Try zipping the same files using the command line and see what the timings are - maybe your files are large and it's just taking a long time.Exothermic
Sorry, I realize that was vague. By "something is getting stuck", I meant that I am not getting any errors, but the zip file is not being sent to the browser for download. I have tried putting print statements throughout the code to make sure the whole method is executing, and it seems to be. It's just not quite accomplishing what I want it to. I will try some of your suggestions. Thank you.Stomatal
S
5

In case this can be helpful to anyone else, I found the answer to the problem. The code posted above actually works perfectly for downloading multiple files from a database and creating a zip file for the client to download. The problem was that I was calling the servlet via ajax, and apparently you can't download files via an ajax call. So I changed my jsp page to call the servlet via submitting a form, and then the download came through to the browser perfectly.

Stomatal answered 14/4, 2013 at 16:1 Comment(0)
D
3

First create a zip file which contains all the zip files.

Use ServletOutputStream instead of ZipOutputStream.

Then use the below code

protected void doGet(final HttpServletRequest request, final HttpServletResponse response) {
        final String filename = "/usr/local/FileName" + ".zip";

        BufferedInputStream buf = null;
        ServletOutputStream myOut = null;

        try {
            myOut = response.getOutputStream();

            File myfile = new File(filename);

            if (myfile.exists()) {
                //myfile.createNewFile();
                //set response headers
                response.setHeader("Cache-Control", "max-age=60");
                response.setHeader("Cache-Control", "must-revalidate");
                response.setContentType("application/zip");

                response.addHeader("Content-Disposition", "attachment; filename=" + filename);

                response.setContentLength((int) myfile.length());

                FileInputStream input = new FileInputStream(myfile);
                buf = new BufferedInputStream(input);
                int readBytes = 0;

                //read from the file; write to the ServletOutputStream
                while ((readBytes = buf.read()) != -1) {
                    myOut.write(readBytes);
                }
            }

        } catch (Exception exp) {
        } finally {
            //close the input/output streams
            if (myOut != null) {
                try {
                    myOut.close();
                } catch (IOException ex) {
                }
            }
            if (buf != null) {
                try {
                    buf.close();
                } catch (IOException ex) {
                }
            }

        }
    }
Disaccredit answered 12/4, 2013 at 5:4 Comment(2)
Thank you, I will try this Kiran Jujare. Can you tell me - 'final String filename = "/usr/local/FileName" + ".zip";' is the name of the zip file already created? How do you know the extention is '/usr/local/FileName' ?Stomatal
You have to create the zip file which you want to download the pass the name to String filename.Disaccredit

© 2022 - 2024 — McMap. All rights reserved.