Enterprise Java

Spring Boot @requestmapping To Serve A zip File

Serving a zip file from a Spring Boot application is a common requirement in modern web applications. Whether for compressing logs, providing downloadable resources, or bundling files, zip files make data sharing efficient. Let us delve into understanding how Spring Boot @requestmapping can be used to serve a zip file.

1. Code Example

Here is a code example for serving zip files. Before exploring the code, make sure to include the following dependencies in your pom.xml file.

<dependencies>
	<!-- Spring Boot Starter Web -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<!-- Zip4j for Password Protection -->
	<dependency>
		<groupId>net.lingala.zip4j</groupId>
		<artifactId>zip4j</artifactId>
		<version>your_jar_version</version>
	</dependency>

	<!-- Spring Boot Starter Test (optional, for testing) -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

Also, add a text file named example.txt to the src/main/resources directory containing the following content:

This is an example file to demonstrate zip functionality.

1.1 Create a Main class

package com.example.zipservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ZipServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZipServiceApplication.class, args);
    }
}

1.1.1 Code explanation

The above code defines the main entry point for a Spring Boot application. The class is annotated with @SpringBootApplication, which is a convenience annotation that combines several key annotations: @Configuration (for defining configuration classes), @EnableAutoConfiguration (to enable automatic configuration based on the classpath), and @ComponentScan (to scan for components, configurations, and services in the specified package and its sub-packages).

The main method calls SpringApplication.run(), passing the class and command-line arguments to bootstrap the Spring Boot application. This starts the embedded web server (like Tomcat or Jetty), initializes the Spring context, and makes the application ready to serve requests.

1.2 Create a Controller class

package com.example.zipservice;

import net.lingala.zip4j.ZipFile;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController  // This annotation marks the class as a REST controller to handle HTTP requests.
public class UnifiedZipController {

    // Endpoint to generate and return a zip file as a byte array
    @GetMapping("/zip-as-byte-array")
    public byte[] getZipAsByteArray() throws Exception {
        // ByteArrayOutputStream to hold the zip file content in memory
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        
        // Create a ZipOutputStream to write to the byte array output stream
        try (ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream)) {
            // Define the zip entry, which is a file inside the zip archive
            ZipEntry entry = new ZipEntry("example.txt");
            zipOut.putNextEntry(entry);
            
            // Write content to the zip entry
            zipOut.write("Hello, this is a zip file!".getBytes());
            zipOut.closeEntry();  // Close the entry
        }
        
        // Return the zip file as a byte array
        return byteArrayOutputStream.toByteArray();
    }

    // Endpoint to stream a zip file directly to the response
    @GetMapping("/zip-as-stream")
    public void getZipAsStream(HttpServletResponse response) throws Exception {
        // Set the response content type to indicate a zip file
        response.setContentType("application/zip");
        
        // Set the response header to trigger a file download with a custom name
        response.setHeader("Content-Disposition", "attachment; filename=example.zip");

        // Create a ZipOutputStream to write directly to the HTTP response output stream
        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
            // Define the zip entry, which is a file inside the zip archive
            ZipEntry entry = new ZipEntry("example.txt");
            zipOut.putNextEntry(entry);
            
            // Write content to the zip entry
            zipOut.write("Streaming zip content!".getBytes());
            zipOut.closeEntry();  // Close the entry
        }
    }

    // Endpoint to generate a zip file with compression
    @GetMapping("/zip-with-compression")
    public void getZipWithCompression(HttpServletResponse response) throws Exception {
        // Set the response content type to indicate a zip file
        response.setContentType("application/zip");
        
        // Set the response header to trigger a file download with a custom name
        response.setHeader("Content-Disposition", "attachment; filename=compressed.zip");

        // Create a ZipOutputStream to write directly to the HTTP response output stream
        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
            // Set the compression level to the highest
            zipOut.setLevel(Deflater.BEST_COMPRESSION);
            
            // Define the zip entry, which is a file inside the zip archive
            ZipEntry entry = new ZipEntry("example.txt");
            zipOut.putNextEntry(entry);
            
            // Write content to the zip entry
            zipOut.write("Optimized for compression!".getBytes());
            zipOut.closeEntry();  // Close the entry
        }
    }

    // Endpoint to generate a password-protected zip file
    @GetMapping("/zip-with-password")
    public void getPasswordProtectedZip(HttpServletResponse response) throws Exception {
        // Create a temporary zip file on the filesystem
        File tempZip = File.createTempFile("secure", ".zip");
        
        // Use the zip4j library to add files to the zip with password protection
        try (ZipFile zipFile = new ZipFile(tempZip)) {
            // Set the password for the zip file
            zipFile.setPassword("securePassword".toCharArray());
            
            // Add the file to the zip archive
            zipFile.addFile(new File("src/main/resources/example.txt"));
        }

        // Set the response content type to indicate a zip file
        response.setContentType("application/zip");
        
        // Set the response header to trigger a file download with a custom name
        response.setHeader("Content-Disposition", "attachment; filename=protected.zip");
        
        // Stream the temporary zip file to the response output stream
        try (OutputStream out = response.getOutputStream()) {
            Files.copy(tempZip.toPath(), out);  // Copy the temporary zip content to the response output stream
        }
    }
}

1.2.1 Code explanation

The UnifiedZipController class is a Spring Boot REST controller that provides multiple endpoints for serving zip files with different functionalities. Each method demonstrates a unique approach to handling zip file creation and response delivery.

The @RestController annotation makes the class a Spring MVC controller capable of handling HTTP requests. Each method is annotated with @GetMapping, specifying the endpoint’s URL and indicating that it handles GET requests.

The getZipAsByteArray() method demonstrates how to create a zip file in memory as a byte array. It uses a ByteArrayOutputStream to hold the zip file data and a ZipOutputStream to write a single file entry (“example.txt”) with some text content. The generated byte array is returned as the response.

The getZipAsStream() method streams the zip file directly to the client’s response output stream. By setting the appropriate content type and headers, the client can download the file as “example.zip”. The zip content is created on-the-fly using a ZipOutputStream.

The getZipWithCompression() method adds compression control to the zip file. It sets the compression level to Deflater.BEST_COMPRESSION, optimizing the file size. The rest of the logic is similar to the getZipAsStream() method.

The getPasswordProtectedZip() method demonstrates how to generate a password-protected zip file using the zip4j library. A temporary zip file is created, and a file (“example.txt”) is added to the archive with password protection. The file is then streamed to the client’s response, allowing them to download a secure zip file.

Each method provides a distinct capability, showcasing how Spring Boot and Java’s zip utilities (or third-party libraries like zip4j) can be combined to handle zip file operations effectively in a web application.

1.3 Updating Application properties

server.port=8080

The application.properties file is used in Spring Boot applications to define configuration settings. The property server.port=8080 specifies the port number on which the embedded web server (such as Tomcat) listens for incoming HTTP requests. By default, Spring Boot applications run on port 8080, but this property allows you to explicitly set or change the port number if needed.

For example, if another application is already using port 8080 or if you want to expose your service on a different port, you can modify this property to an available port, such as server.port=9090.

3. Run the code

To run the Spring Boot application, ensure that you have Maven installed on your system. Navigate to the project directory in your terminal and execute the command mvn spring-boot:run. This will start the application, and the embedded web server will listen for requests on the port specified in the application.properties file (default is 8080).

Once the application is running, you can trigger the endpoints using a web browser, curl, or tools like Postman. The available endpoints and their functionalities are as follows:

  • /zip-as-byte-array: Returns a zip file as a byte array. Access this endpoint via http://localhost:8080/zip-as-byte-array. The response will download the zip file.
  • /zip-as-stream: Streams a zip file directly to the client. Use http://localhost:8080/zip-as-stream to download the zip file.
  • /zip-with-compression: Generates a zip file with maximum compression. Trigger it by visiting http://localhost:8080/zip-with-compression.
  • /zip-with-password: Creates a password-protected zip file. Access it via http://localhost:8080/zip-with-password. The file will require a password (securePassword) to extract.

Each endpoint demonstrates a unique way to serve zip files, making them easy to test and integrate into your projects.

4. Conclusion

Spring Boot makes it straightforward to serve zip files using various methods. Whether working with byte arrays, streams, or libraries for advanced features like password protection, Spring Boot provides the flexibility to meet your application’s needs. Choose the approach that best fits your use case and ensure your implementation aligns with performance and security best practices.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button