File Download Example Using RESTful Web Service with JAX-RS and Jersey

File Download Example

In this example we are going to develop file download capability using RESTful web service using JAX-RS and Jersey. As you will see, downloading a File using Jersey is very easy as it uses the HTTP GET for the file operations. In our web service, we will be allowing you to download the file via two mechanisms. You will be able to download by HTTP query parameters via @QueryParam and also by using the path parameters via @PathParam.

Our sample HTML form is incredibly simple, having only only one input field of type text so you can supply a filename (with extension).

Getting Started

In order to run this tutorial yourself, you will need the following:

  • Java JDK 1.6 or greater
  • Favorite IDE Spring Tool Suite (STS), Eclipse IDE or NetBeans (I happen to be using STS because it comes with a Tomcat server built-in)
  • Tomcat 7 or greater or other popular container (Weblogic, Websphere, Glassfish, JBoss, VMWare vFabric, etc). For this tutorial I am using VMware vFabric tc Server Developer Edition which is essentially an enhanced Tomcat instance integrated with Spring STS
  • Jersey JAX-RS
  • log4J (for logging purposes)

Required Libraries

Copy all of the following jars to WebContent->WEB-INF->lib folder.

asm-3.1.jar
jersey-client-1.18.jar
jersey-core-1.18.jar
jersey-json-1.18.jar
jersey-multipart-1.18.jar
jersey-server-1.18.jar
jersey-servlet-1.18.jar
jsr311-api-1.1.1.jar
log4j-1.2.17.jar
mimepull-1.6.jar

Complete Project Overview

I have added the project overview to give you a full view of the structure and show you all files contained in this sample project.

jax-rs download project struct

RESTful Web Service End Points

#URIMethodDescription
1/rest/files/versionGETReturns version # of application (dummy method I use to ensure web service is running)
2/rest/files/download?filename=XXXXXGETDownloads the file passed in via query parameter. This web service endpoint will be used when being accessed from web page with form having method=GET.
3/rest/files/download/{filename}GETDownloads the file passed in via path parameter. This web service endpoint is typically used when URI path parameters are extracted from the request URI, and the parameter names correspond to the URI path template variable names.

Implement our File Download Service Class using the JAX-RS API

Implementing a RESTful service requires nothing more than creating a POJO and annotating using the javax.ws.rs.* annotations. Additionally, you will need to ensure your class is under the package you defined in your web descriptor as Jersey will use this package to scan your classes for the existence RESTful resources.

In the RestFileDownloadExample service class, you will notice that I am using @Produces annotation with a media type of MediaType.APPLICATION_OCTET_STREAM. This allow us to download the file as a binary file and download it directly in your browser. In addition, I decided to have two methods that will allow download us to download file. One method, downloadFilebyQuery uses the @QueryParam annotation which binds the value of a HTTP query parameter to our resource method parameter filename.

download url structure

http://localhost:8080/RestfulFileDownloadExample/rest/files/download?filename=DEBUG.txt

The other method, downloadFilebyPath uses the @PathParam annotation which binds the value of a URI template parameter or a path segment containing the template parameter to a resource method parameter.

download url structure2

http://localhost:8080/RestfulFileDownloadExample/rest/files/download/DEBUG.txt

The other point worth mentioning is the fact that we are performing some basic file checking by ensuring that the file the user wishes to download actually exists in our file system. Failure to do so could result in some pretty ugly exceptions being returned to the user and our logs. If the file exists, we return it to the user and if the file is missing, we construct an appropriate error message and return a 404 status error to the user.

package com.avaldes;

import java.io.File;
import java.text.NumberFormat;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.apache.log4j.Logger;

@Path("/files")
public class RestFileDownloadExample {
  static Logger logger = Logger.getLogger(RestFileDownloadExample.class);
  private static final String api_version = "1.01A rev.1";
  private static final String FILE_FOLDER = "c://tmp/";
  
  @Path("/version")
  @GET
  @Produces(MediaType.TEXT_HTML)
  public String returnVersion() {
    return "<p>Version: " + api_version + "</p>";
  }
  
  @GET
  @Path("/download")
  @Produces(MediaType.APPLICATION_OCTET_STREAM)
  public Response downloadFilebyQuery(@QueryParam("filename") String fileName) {
    return download(fileName);
  }
  
  @GET
  @Path("/download/{filename}")
  @Produces(MediaType.APPLICATION_OCTET_STREAM)
  public Response downloadFilebyPath(@PathParam("filename")  String fileName) {
    return download(fileName);
  }

  private Response download(String fileName) {     
    String fileLocation = FILE_FOLDER + fileName;
    Response response = null;
    NumberFormat myFormat = NumberFormat.getInstance();
      myFormat.setGroupingUsed(true);
    
    // Retrieve the file 
    File file = new File(FILE_FOLDER + fileName);
    if (file.exists()) {
      ResponseBuilder builder = Response.ok(file);
      builder.header("Content-Disposition", "attachment; filename=" + file.getName());
      response = builder.build();
      
      long file_size = file.length();
            logger.info(String.format("Inside downloadFile==> fileName: %s, fileSize: %s bytes", 
                fileName, myFormat.format(file_size)));
    } else {
      logger.error(String.format("Inside downloadFile==> FILE NOT FOUND: fileName: %s", 
                fileName));
      
      response = Response.status(404).
              entity("FILE NOT FOUND: " + fileLocation).
              type("text/plain").
              build();
    }
     
    return response;
  }
}

Simple HTML Web Page (index.html)

This page is very simple having only an input field of type text with a name=”filename”. One thing I will note is that I am using a GET instead of a POST in the form.

<h1>RESTful Web Service - File Download Example</h1>  
<form action="/RestfulFileDownloadExample/rest/files/download" method="GET">  
 <p><label for="name">File Name:</label>  
   <input type="text" name="filename" size="50">   
 </p>  
 <input type="submit" value="Download File" />  
</form>
 

Web Deployment Descriptor (web.xml)

This is a pretty straight forward deployment descriptor file – only thing you need to add is the location of you java package in the Jersey ServletContainer entry as init-param. Please ensure you add it to the web.xml file as shown below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>com.omega.rest</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
 
   <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.avaldes</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

Testing out the Web Services

To test out the application, simply enter a filename into the text box labeled File Name. Then click on the Download File button.

file download page

When file is missing, we notify the user with an appropriate message.

file download error page

Download the Code

That’s It!

I hope you enjoyed this tutorial. It was certainly a lot of fun putting it together and testing it out. Please continue to share the love and like us so that we can continue bringing you quality tutorials. Happy Coding!!!

java jaxrs download

Please Share Us on Social Media

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *