This tutorial demonstrates how to download a Base64 encoded image using a RESTful web service with Jersey 2 and Tomcat 8. The example Java project is available on Git and requires Maven.
1. Prerequisites
- Install Apache Tomcat (we use version 8.5). If not already installed, please have a look at these 2 tutorials:
- Install Apache Tomcat on Windows
- Add Tomcat server runtime to EclipseEE (if you work with EclipseEE)
- Install Apache Maven to build the project
- You can just run a “clean install” on the Maven project and deploy the created WAR file to Tomcat directly. Although we recommend to work with an IDE like EclipseEE or IntelliJ to adapt or debug the project
- If you import the Maven project to EclipseEE, activate and adapt the Project Facets to use the Dynamic Web Project 3.1, Java 1.8 and JAX-RS 2.0
2. Code step-by-step
Starting of with the project setup, we explain the web.xml, some dependencies in the pom.xml and move on to the code example.
2.1 Configuration of web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>jersey2-base64-image-download</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <servlet> <servlet-name>jersey2-base64-image-download</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.tutorialacademy.rest.DownloadRestService</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey2-base64-image-download</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>
The web.xml is straight forward. We specify a welcome file that is displayed when requesting the root folder of our Servlet. In order to do so you have to use another sub root for your Servlet mapping (like <url-pattern>/rest/*</url-pattern>). Using <url-pattern>/*</url-pattern> leads to undefined behavior since the Servlet and the WebContent share the same root.
Furthermore we define the applications initialization parameters <param-value>com.tutorialacademy.rest.DownloadRestService</param-value>. You can do that via a ResourceConfig file as well, but we only use one REST service in this example.
2.2 Dependencies in pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tutorialacademy.rest</groupId> <artifactId>jersey2-base64-image-download</artifactId> <packaging>war</packaging> <version>0.0.1</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jersey2.version>2.25</jersey2.version> <apachecommons.version>2.5</apachecommons.version> <log4j.version>1.2.17</log4j.version> </properties> <build> <finalName>jersey2-base64-image-download</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.0.0</version> <configuration> <warSourceDirectory>WebContent</warSourceDirectory> </configuration> </plugin> </plugins> </build> <dependencies> <!-- JERSEY 2 --> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>${jersey2.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet-core</artifactId> <version>${jersey2.version}</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${apachecommons.version}</version> </dependency> <!-- Logging --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </project>
Nothing too fancy here either. We use Jersey 2 in version 2.25, the Apache Commons library in version 2.5 as Base64 encoder. Furthermore we specify the Java 1.8 compiler and the WAR file source directory.
2.3 Base64 download REST web service
@Path("/") public class DownloadRestService extends ResourceConfig { final static Logger logger = Logger.getLogger( DownloadRestService.class ); @GET @Path( "download/{fileName}" ) @Produces( MediaType.APPLICATION_OCTET_STREAM ) public Response download( @PathParam( "fileName" ) final String fileName ) { logger.info( "Download Request: " + fileName ); try { // get relative file path ClassLoader classLoader = new DownloadRestService().getClass().getClassLoader(); File file = new File( classLoader.getResource( fileName ).getFile()); logger.info( "File Found: " + file.exists() ); // encode to base64 byte[] data = Base64.getEncoder().encode( IOUtils.toByteArray( file.toURI() ) ); // prepare response return Response .ok( data, "image/jpg" ) .header( "Content-Disposition","inline; filename = \"" + fileName + "\"" ) .build(); } catch ( IOException e ) { return Response.status( Response.Status.NOT_FOUND ).entity( e.getMessage() ).build(); } } }
This is basically our only Java code. We create a download web service that extends the ResourceConfig. Then we provide one GET method that is reachable via …/jersey2-base64-image-download/rest/download/image_name.jpg and produces MediaType.APPLICATION_OCTET_STREAM.
The most interesting part here is the Base64 encoder of the Apache Commons library and how the response is built.
In the response we specify the byte array data and the content type. Afterwards, we enhance the response header for Content-Disposition with the parameter inline. This indicates that the image should be displayed and not downloaded. Using the parameter attachment will result in the file download. Additionally we attach the file name.
2.4 Display the image via index.html
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script> $(document).ready( function() { $("#showImageButton").click(function(){ $.ajax({ type: "GET", contentType: "image/jpg", url: 'http://localhost:8080/jersey2-base64-image-download/rest/download/RoadToDataScientist.jpg', success: function( data ){ $("<img>", { "src": "data:image/jpeg;base64," + data, }) .appendTo("#img_preview"); } }); }); }); </script> </head> <body> <h1>jersey2-base64-image-download</h1> <div id="img_preview"></div> <button id="showImageButton" type="button">Show Image</button> <br> <br> <b>Powered by <a href="https://tutorial-academy.com">tutorial-academy.com</a> © 2017 - Check out the tutorial <a href="https://tutorial-academy.com/rest-jersey2-image-base64-download">here</a>!</b> </body> </html>
We use JQuery to retrieve the data from the previously presented GET method. You have a button to click on to display the image. Remember to adapt the GET call if you run your server on a different port than the standard 8080. The index.html is placed in the folder WebContent/WEB-INF/ and refers to our welcome file in the web.xml.
3. Build and run the project
Build the project via the Maven command clean install. This should create a jersey2-base64-image-download.war file.
Check out this tutorial chapter 10 for Eclipse users if you need help with the deployment. However, you can deploy directly from Eclipse or IntelliJ or copy the WAR file into the Tomcat WebApps folder. After the successful deployment and with a running Tomcat, you should see the following website when visiting http://localhost:8080/jersey2-base64-image-download/. Remember to adapt different port and mapping settings if you changed anything.
Click the Show Image button in order to download and display the provided image. The image path is hard coded to an example image located in the resources folder (RoadToDataScientist.jpg).
4. Conclusion
This small example project demonstrates that very little code is required to download and display a Base64 encoded image via a Jersey 2 web service. We feel that the most trouble is not actually writing the code, but getting the configuration (especially the web.xml) to work correctly.
If you have problems or errors, feel free to comment and ask.





