Inside Java

Zip files and Servlets


 

Servlets

Here is the first technical article on servlets on Inside Java.
We assume here your know what a servlets is. For more information, read first an introduction to servlets , a servlet tutorial , the Developer Documentation and the Servlet API (all links from JavaSoft).

This article aims at presenting how to create a servlet that sends a zip file to the user. We create here a html page with a form where you can enter an url. The servlet will get the content of this url (only the html page, not the images or other frames), create a zip file with it, and send you the file.
This example can be used as a basis to do various things.

The html form

Simply enter the URL you would like to download. If this URL uses a post method, then select the corresponding post method.
The servlet gets the content of this url, zips it, and sends you the corresponding file name output.zip.

If you would like to try this post feature, you can use the following link: http://mccoy.cs.twsu.edu:2666//cgi-bin/cjhock/ctest?name=java&crust=thin&topping=Ham
This link points to a cgi that process the output of a form located at: http://mccoy.cs.twsu.edu:2666/~cjhock/form_post.
This is a pizza order form...

The source code

You can download the whole example:

This servlet must be used with the previous form. It answers to GET request, and takes two parameters: dopost and url.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.zip.*;
import java.net.*;
import java.util.*;

public class zipservlet extends HttpServlet {
   
    public void doGet (HttpServletRequest req, HttpServletResponse res)    throws ServletException, IOException
    {
       
        byte b[]=new byte[30000];
        boolean dopost=false;
        URL url;
        String temp;
       
        ByteArrayOutputStream bout=new ByteArrayOutputStream();
        ZipOutputStream zout=new ZipOutputStream(bout);                
        ServletOutputStream out = res.getOutputStream();   
        ServletContext servletContext = getServletContext();   
       
        if (req.getParameter("dopost")!=null) dopost=true;
        if ((temp=req.getParameter("url"))!=null)
        {
           
            try {
               
                url=new URL(temp);
                URLConnection uc = url.openConnection();
                uc.setDoOutput(dopost);
               
                if (dopost) {
                    PrintWriter output=new PrintWriter(uc.getOutputStream());
                    temp=temp.substring(temp.indexOf('?')+1);
                    Hashtable h=HttpUtils.parseQueryString(temp);
                    Enumeration e=h.keys();
                   
                    while (e.hasMoreElements())
                    {
                        String param=(String)e.nextElement();
                        String value=((String[]) (h.get(param)))[0];
                        output.print(param+"=" + URLEncoder.encode(value));
                        if (e.hasMoreElements()) output.print('&');
                    }
                    output.println();
                    output.flush(); //Flush the stream now!
                }
                DataInputStream input = new DataInputStream(uc.getInputStream());
               
                int numRead=0;
                int size=0;
               
                while (numRead != -1) {
                   
                    numRead = input.read(b,size,20000);
                    size+=numRead;
                }
               
                zout.putNextEntry(new ZipEntry("file.html"));
                zout.write(b,0,size);
                zout.closeEntry();
                zout.finish();
                String zip=bout.toString();
               
                res.setContentType("application/zip");
                res.setHeader("Content-Disposition","attachment; filename=output.zip;");
                out.println(zip);
            }
            catch (Exception e)
            {
                res.setContentType("text/html");
                out.println("");
                out.println("Error");
                out.println("");
                out.println("");
                out.println("An error has occured while processing "+temp+"
");
                out.println("Here is the exception:
"+e+"
");
                e.printStackTrace(new PrintWriter(out));
                out.println("");
                out.println("");
            }        
                                   
        }   
    }
       
}

Sending a file with a servlet

This involves two headers: Content-Type and Content-Disposition. The content type is set to "application/zip". The other one is used to specify the filename used by the browser when it starts downloading the file.

res.setContentType("application/zip");
res.setHeader("Content-Disposition","attachment; filename=output.zip;");

In this example, we create a zip file. We'll discuss later on how to create such files. As soon as we get a byte array with the zip file, we are ready to send it.
We simply call out.println(zip) to send the file.

Creating a zip file

Have you ever noticed the package ?
Basically, a zip file is created by adding to a .
Once we have create a ZipEntry with a file name, we are ready to write an array of byte to the ZipOutputStream. Then we close the entry, finish the work with a call to finish(). We finally get a String containing the zipped file.

zout.putNextEntry(new ZipEntry("file.html"));
zout.write(b,0,size);
zout.closeEntry();
zout.finish();
String zip=bout.toString();

Doing a POST in Java

Doing a POST in java is very easy. You have to create an URL, get the URLConnection from this URL and call the setDoOutput() method.
Then you have to send all the parameters to the remote machine:

if (dopost) {
                    PrintWriter output=new PrintWriter(uc.getOutputStream());
                    temp=temp.substring(temp.indexOf('?')+1);
                    Hashtable h=HttpUtils.parseQueryString(temp);
                    Enumeration e=h.keys();
                   
                    while (e.hasMoreElements())
                    {
                        String param=(String)e.nextElement();
                        String value=((String[]) (h.get(param)))[0];
                        output.print(param+"=" + URLEncoder.encode(value));
                        if (e.hasMoreElements()) output.print('&');
                    }
                    output.println();
                    output.flush(); //Flush the stream now!

}

We parse the url send to the form in order to get the parameters. With the Pizza URL, it should be name=java&crust=thin&topping=Ham.
Then we use the parseQueryString() method to get an Hashtable with those parameters (key=parameter name, value=array of Strings with the values). This is a static method from HttpUtils.
Then for each parameter, we encode its value and send it to the remote cgi.
Notice that we flush the output immediately.