Boost WebGIS Performance: Enable Gzip Compression in SpringBoot

This article explains why compressing large GeoJSON payloads is essential for WebGIS applications and provides step‑by‑step guidance on configuring Gzip compression globally or selectively in SpringBoot, complete with code examples and performance results.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Boost WebGIS Performance: Enable Gzip Compression in SpringBoot

Introduction

In the digital age, efficient data transmission is crucial for WebGIS applications. GeoJSON files often contain massive coordinate data, leading to slow map loading and poor user experience. Enabling Gzip compression in SpringBoot can significantly reduce payload size and improve performance.

GZIP Compression Basics

1. What is Gzip

LZ77 algorithm: Replaces repeated byte sequences using a sliding window and pointers, e.g., compressing repeated URL strings.

Huffman coding: Assigns shorter codes to frequent characters and longer codes to rare ones, further reducing size after LZ77.

Gzip file structure: Consists of a header, compressed data blocks (DEFLATE), and a footer with CRC32 and original size.

2. Gzip Features

Lossless compression: Data can be fully restored after decompression.

High compression ratio: Text files (HTML, JSON, XML) often shrink by 50‑90%.

Wide support: All modern browsers, servers, and languages recognize the Accept-Encoding: gzip header.

Fast compression/decompression: Especially quick for decompression.

Best for text: Limited benefit for already compressed media files.

3. Gzip in GIS

Geodata transmission: Compressing GeoJSON reduces transfer volume and speeds up map rendering.

Server‑side optimization: Configure Nginx or other servers to gzip responses automatically.

Frontend performance: Use tools like Webpack’s Compression-webpack-plugin to serve pre‑compressed files.

Storage savings: Gzip reduces disk usage for stored GeoJSON files.

Enabling Gzip in SpringBoot

SpringBoot simplifies integration of Gzip compression. There are two main approaches: a global configuration that compresses all HTTP responses, and a selective configuration that targets specific endpoints.

1. Global Configuration

Add the following to application.yml or application.properties:

server:
  compression:
    enabled: true
    mime-types: application/json
    min-response-size: 1KB

Or:

server.compression.enabled=true
server.compression.mime-types=application/json
server.compression.min-response-size=1024
Note: This enables Gzip for all application/json responses.

2. Selective Configuration

Create a custom filter to compress only chosen URLs. Example filter:

package com.yelang.framework.interceptor.gzip;

import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.*;
import java.util.zip.GZIPOutputStream;

@Component
public class SelectiveGzipFilter implements Filter {
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    private final List<String> gzipPatterns = Arrays.asList(
        "/eq/province/geojson/**",
        "/eq/province/detourcoefficient/list/**",
        "/eq/info/home/earthinfo",
        "/eq/province/abbreviations/list"
    );

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String requestUri = req.getRequestURI();
        String contextPath = req.getContextPath();
        String relativePath = requestUri.substring(contextPath.length());
        boolean match = gzipPatterns.stream()
                .anyMatch(pattern -> pathMatcher.match(pattern, relativePath));
        if (match) {
            HttpServletResponse res = (HttpServletResponse) response;
            res.setHeader("Content-Encoding", "gzip");
            res.setHeader("Content-Type", "application/json");
            GZIPResponseWrapper gzipResponse = new GZIPResponseWrapper(res);
            chain.doFilter(request, gzipResponse);
            gzipResponse.finish();
        } else {
            chain.doFilter(request, response);
        }
    }

    static class GZIPResponseWrapper extends HttpServletResponseWrapper {
        private final GZIPOutputStream gzipOutputStream;
        public GZIPResponseWrapper(HttpServletResponse response) throws IOException {
            super(response);
            this.gzipOutputStream = new GZIPOutputStream(response.getOutputStream());
        }
        @Override
        public ServletOutputStream getOutputStream() {
            return new ServletOutputStream() {
                @Override public void write(int b) throws IOException { gzipOutputStream.write(b); }
                @Override public boolean isReady() { return true; }
                @Override public void setWriteListener(WriteListener writeListener) { throw new UnsupportedOperationException(); }
            };
        }
        public void finish() throws IOException { gzipOutputStream.finish(); }
    }
}

This filter matches the defined patterns using AntPathMatcher and applies Gzip only to those requests.

GeoJSON Example in SpringBoot

Define a VO class for GeoJSON data:

package com.yelang.project.meteorology.domain;

import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@Data
@ToString(callSuper=true)
@EqualsAndHashCode(callSuper=false)
public class AreaWeatherVO extends WeatherNow implements Serializable {
    private static final long serialVersionUID = -7559774548761847068L;
    @TableField(exist = false, value = "province_code")
    private String provinceCode;
    @TableField(exist = false, value = "province_name")
    private String provinceName;
    @TableField(exist = false, value = "city_code")
    private String cityCode;
    @TableField(exist = false, value = "city_name")
    private String cityName;
    @TableField(exist = false, value = "area_name")
    private String areaName;
    @TableField(exist = false)
    private String geomJson;
    private String lat;
    private String lon;
}

Controller method returning GeoJSON:

@RequiresPermissions("met:province:weather:list")
@GetMapping("/list/{pcode}")
@ResponseBody
public AjaxResult ewsnProvinceList(@PathVariable("pcode") String pcode){
    String day = "2025-08-17";
    List<AreaWeatherVO> dataList = weatherNowService.getWeatherByProvinceAndday(pcode, day);
    return AjaxResult.success().put("data", dataList);
}

The response size for a typical province is around 5 MB; for larger regions like Tibet it can exceed 14 MB. Enabling Gzip reduces these sizes dramatically, as shown in the following screenshots.

GeoJSON size before compression
GeoJSON size before compression
GeoJSON size after compression
GeoJSON size after compression

Conclusion

The article demonstrated two ways to enable Gzip compression in SpringBoot—global configuration and selective filter—using a real GeoJSON use case. Applying these techniques can markedly shrink response payloads, accelerate map loading, and improve overall WebGIS performance.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performanceSpringBootWebGISGeoJSON
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.