View RSS Feed

Servlet

How to write a Servlet that sends file to user to download

Rating: 7 votes, 4.86 average.
by , 12-10-2011 at 04:54 AM (64433 Views)
Downloading files is a very popular task on the World Wide Web. Users click on a download link and the file gets downloaded into their computer. Technically, a download can be achieved by either of the two forms as following:

  • Direct link: the link points directly to a file on a server, for example: http://www.server.com/download/report.xls. This kind of link requires no additional effort on the server side, since the web server automatically hands the file over to users as per request. However, this form may pose a security threat because the server’s directory structure maybe guessed by looking at the link.
  • Indirect link: the link actually points to a program on server (i.e a Java Servlet, a Perl script, or a PHP script…) which does additional tasks before handing the file over to users, such as writing a log entry, updating a database record, sending an email, etc… This form may improve security since the actual link is hidden from end users.


In this article you will be instructed to write a simple Java Servlet that implements the latter form: User clicks on a link that points to a Servlet which reads a file on server and sends it to user. Browser will ask user to download the file.
We will be creating the following items for a simple Java web application:

  • A JSP page that simply presents a download link to the user. The link refers to a servlet’s URL which will be deployed on Tomcat server.
  • A Java servlet that reads a file on the server and sends it to the user as a stream of bytes.


This article assumes that you are familiar with Java web development with Eclipse IDE and Tomcat web server.

Writing the Servlet
Following is the Servlet’s code:


Java Code: Implementation of the servlet
package com.hainasoft.web;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DownloadServlet extends javax.servlet.http.HttpServlet implements
        javax.servlet.Servlet {
    static final long serialVersionUID = 1L;
    private static final int BUFSIZE = 4096;
    private String filePath;
   
    public void init() {
        // the file data.xls is under web application folder
        filePath = getServletContext().getRealPath("") + File.separator + "data.xls";
    }
   
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        File file = new File(filePath);
        int length   = 0;
        ServletOutputStream outStream = response.getOutputStream();
        ServletContext context  = getServletConfig().getServletContext();
        String mimetype = context.getMimeType(filePath);
       
        // sets response content type
        if (mimetype == null) {
            mimetype = "application/octet-stream";
        }
        response.setContentType(mimetype);
        response.setContentLength((int)file.length());
        String fileName = (new File(filePath)).getName();
       
        // sets HTTP header
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
       
        byte[] byteBuffer = new byte[BUFSIZE];
        DataInputStream in = new DataInputStream(new FileInputStream(file));
       
        // reads the file's bytes and writes them to the response stream
        while ((in != null) && ((length = in.read(byteBuffer)) != -1))
        {
            outStream.write(byteBuffer,0,length);
        }
       
        in.close();
        outStream.close();
    }
}


We define an integer constant BUFSIZE for the size of buffer is used when reading file’s content.
The member variable filePath points to the actual file on server, it is initialized in the init() method of the Servlet, by the following line of code:


Java Code:
        filePath = getServletContext().getRealPath("") + File.separator + "data.xls";


The file name is data.xls and it is placed under the web application folder, so you should remember to put that file there, before testing the application.

We implement the Servlet’s doGet() method which is invoked when user clicks on the download link from the JSP page. In order to send data to the user, we obtain the response’s output stream object:


Java Code:
        ServletOutputStream outStream = response.getOutputStream();


In order to read the file’s content, we creates an instance of the DataInputStream object:


Java Code:
        DataInputStream in = new DataInputStream(new FileInputStream(file));


It’s important that we should set the MIME type for the response:


Java Code:
            mimetype = "application/octet-stream";


And add an attribute Content-Disposition for the response’s header:


Java Code:
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");


to force the browser displays a download dialog to users.

We read the file’s content and write bytes stream to the response in the while loop:


Java Code:
        while ((in != null) && ((length = in.read(byteBuffer)) != -1))
        {
            outStream.write(byteBuffer,0,length);
        }


When the reading/writing ends, we close the both streams:


Java Code:
        in.close();
        outStream.close();


Depending on your application, you may need to perform some tasks before the file is sent to the user, such as writing a log entry, sending an email, etc…

Writing the JSP page

We create a simple JSP page that contains only a download link:


XML Code: The JSP file download.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
   pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Download Servlet Test</title>
</head>
<body>
Click on the link to download: <a href="DownloadServlet">Download Link</a>
</body>
</html>


You can notice that the href attribute of the anchor tag point to the DownloadServlet.
Although it is possible to type the servlet’s URL directly into browser’s address bar and that seems to be unnecessary to create the JSP page, but the JSP page’s purpose is to demonstrate a real scenario where the user clicks on a link to download.

Configure the web.xml

Finally, we need to map the DownloadServlet class to a URL pattern in the web configuration file:

XML Code: Mapping the servlet to a URL
    <servlet>
        <description></description>
        <display-name>DownloadServlet</display-name>
        <servlet-name>DownloadServlet</servlet-name>
        <servlet-class>com.hainasoft.web.DownloadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DownloadServlet</servlet-name>
        <url-pattern>/DownloadServlet</url-pattern>
    </servlet-mapping>
Deploy and Test the download file page

Package the application as a WAR file then deploy it on a container like Tomcat, browse the download.jsp page at the URL: http://localhost/CodeWeb/download.jsp.

The following screenshot shows the download.jsp page:

Name:  screenshot.PNG
Views: 39099
Size:  66.5 KB
Figure: The download page

Click on the link presented in the download.jsp page, the DownloadServlet will be invoked and the browser will ask you to download the data.xls file, the browser asks to save the file:

Name:  screenshot2.PNG
Views: 39140
Size:  80.2 KB
Figure: The confirm download dialog

Well, so far we have created a simple server script that allows user to download a file through an indirect link. This has a number of advantages over the direct link: the actual path of the file is hidden, you can do some tasks before or after sending the file to user such as logging, updating database, sending emails, etc.

Submit "How to write a Servlet that sends file to user to download" to Facebook Submit "How to write a Servlet that sends file to user to download" to Digg Submit "How to write a Servlet that sends file to user to download" to del.icio.us Submit "How to write a Servlet that sends file to user to download" to StumbleUpon Submit "How to write a Servlet that sends file to user to download" to Google

Categories
Servlet , File

Comments