SpringBoot中 Gzip 压缩的两种开启方式:GeoJSON 瘦身实战
文章详细介绍在 SpringBoot 中开启 Gzip 压缩的两种方式的具体实现步骤,并通过实际的 GeoJSON 数据压缩案例,展示这两种方式的应用效果。
目录
前言
在当今数字化时代,随着互联网应用的飞速发展,数据传输的效率和性能成为了至关重要的问题。GeoJSON 是一种基于 JSON 格式的地理空间数据交换格式,它广泛应用于地理信息系统(GIS)领域,用于描述地理空间数据的几何形状、属性等信息。GeoJSON 数据通常包含大量的地理坐标点、几何形状等信息,数据量往往较大。在 Web 地理信息系统应用中,如地图展示、地理数据可视化等场景,GeoJSON 数据的传输效率直接关系到地图加载的速度和用户体验。因此,对 GeoJSON 数据进行有效的压缩,以减少数据传输的体积,显得尤为重要。对于基于SpringBoot 框架构建的 WebGIS 应用来说,如何高效地传输数据、减少网络带宽的占用,是提升用户体验和系统性能的关键所在。而 Gzip 压缩技术,作为一种被广泛采用的解决方案,无疑为这一问题的解决提供了强大的助力。
以 GeoJSON 数据为例,通过在 SpringBoot 应用中开启 Gzip 压缩,对 GeoJSON 数据进行瘦身,不仅可以显著减少数据传输的体积,提高地图加载的速度,还可以提升用户的交互体验。在实际的 Web 地理信息系统开发中,这种优化手段是非常实用和有效的。通过对 GeoJSON 数据的压缩处理,我们可以更好地满足用户对于地图快速加载和流畅交互的需求,同时也为整个应用的性能优化提供了有力的支持。
在接下来的内容中,我们将详细介绍在 SpringBoot 中开启 Gzip 压缩的两种方式的具体实现步骤,并通过实际的 GeoJSON 数据压缩案例,展示这两种方式的应用效果和优缺点。希望通过本文的介绍,能够帮助读者更好地理解和掌握在 SpringBoot 应用中使用 Gzip 压缩技术的方法,从而提升自己开发的 WebGIS 应用的性能和用户体验。
一、GZIP压缩知识简介
GZIP 是一种数据压缩格式,只能用于压缩单个文件。它可用于网络文件传输时的压缩,例如 nginx 中的 ngx_http_gzip_module,启用压缩功能后可以节约带宽;也可用于本地文件存储时的压缩。本节将重点对Gzip进行一个简单的介绍,让大家对Gzip的相关知识有一个简单的了解。
1、什么是Gzip
Gzip 的压缩算法基于 LZ77 算法 和 Huffman 编码 的结合。具体过程如下:
LZ77 算法:LZ77 算法通过查找和替换重复的字节序列来压缩数据。它维护一个滑动窗口,在窗口内查找匹配的字符串,然后使用指针来替代这些重复的字符串。例如,对于字符串 "http://jiurl.yeah.nethttp://jiurl.nease.net",LZ77 算法会将其压缩为 "http://jiurl.yeah.net(22,13)nease(23,4)",其中 (22,13) 表示距离当前位置 22 个字符处的 13 个字符与当前位置的字符相同。
Huffman 编码:Huffman 编码是一种基于字符频率的编码方法。它为出现频率高的字符分配较短的编码,为出现频率低的字符分配较长的编码,从而达到压缩的目的。在 Gzip 中,LZ77 算法的输出结果会进一步通过 Huffman 编码进行压缩。
Gzip 文件结构:Gzip 文件包含文件头、压缩数据块和文件尾。文件头存储文件的元数据,如压缩方法、时间戳等;压缩数据块是使用 DEFLATE 算法压缩后的数据;文件尾存储校验和(CRC32)和原始文件大小,以确保文件的完整性
2、Gzip特点
无损压缩:Gzip 是一种无损压缩算法,数据在解压缩后可以完全还原,没有任何损失。
高效的压缩率:对于文本文件(如 HTML、JSON、XML),Gzip 的压缩率通常在 50%-90% 之间。它通过查找重复的字符串并用较短的指针替代,以及根据字符频率进行编码,从而实现高效压缩。
广泛支持:Gzip 被几乎所有现代浏览器、服务器和编程语言支持。在 HTTP 传输中,服务器可以根据浏览器的请求头(如 Accept-Encoding: gzip
)来判断是否使用 Gzip 压缩响应内容。
压缩和解压速度较快:Gzip 的压缩和解压速度相对较快,尤其是解压过程,因为解压时只需根据指针和编码还原数据,计算量相对较小。
适用于特定文件类型:Gzip 对文本文件的压缩效果较好,但对于已经压缩过的文件(如图片、音乐、视频)效果不明显,甚至可能导致文件变大
3、Gzip在GIS方面的应用
地理数据传输:在 GIS 应用中,地理数据(如 GeoJSON 文件)通常包含大量的坐标点和几何形状信息,数据量较大。使用 Gzip 压缩可以显著减少数据传输的体积,加快地图加载速度,提升用户体验。
服务器端优化:在服务器端,可以配置 Web 服务器(如 Nginx)开启 Gzip 压缩功能。当客户端请求地理数据时,服务器会自动对响应内容进行压缩,减少网络带宽的占用。
前端性能优化:在前端开发中,可以通过工具(如 Webpack 的 Compression-webpack-plugin 插件)在构建过程中对地理数据文件进行 Gzip 压缩,然后在服务器上直接提供压缩后的文件,减少服务器的实时压缩负载。
数据存储优化:对于存储在服务器上的地理数据文件,使用 Gzip 压缩可以节省存储空间。在需要读取数据时,再进行解压处理。
总之,Gzip 压缩技术在 GIS 领域的应用,不仅可以提高数据传输效率,还可以优化服务器性能和存储空间,是提升 GIS 应用性能的重要手段之一。
二、SpringBoot中开启Gzip的方式
SpringBoot 是一个非常流行的 Java 基于 Spring 框架的快速开发框架,它极大地简化了 Spring 应用的开发过程。在 SpringBoot 应用中,通过合理的配置和编程,可以很方便地集成 Gzip 压缩功能,从而实现对响应数据的自动压缩。这不仅可以提高数据传输的效率,还可以减轻服务器的负载,提升整个应用的性能。本节将重点介绍在SpringBoot中关于Gzip的相关知识以及在SpringBoot中GeoJSON的一些实践案例。
1、在SpringBoot中开启Gzip的知识简介
在 SpringBoot 中,开启 Gzip 压缩主要有两种方式:一种是通过配置文件进行全局配置,另一种是通过编程的方式在特定的控制器或方法上进行局部配置。这两种方式各有优缺点,适用于不同的应用场景。
全局配置方式 :通过在 SpringBoot 的配置文件(如 application.yml 或 application.properties)中添加相关的 Gzip 压缩配置,可以实现对整个应用的 HTTP 响应进行统一的压缩处理。这种方式简单方便,适用于大多数需要压缩的场景,但缺乏对特定数据类型的针对性处理。
局部配置方式 :通过在控制器或方法上添加自定义的注解或逻辑,可以实现对特定数据类型的压缩处理。这种方式更加灵活,可以根据不同的数据类型和业务需求,定制不同的压缩策略,但相对来说实现起来较为复杂,需要更多的编程工作。
这里首先简单介绍了两种在SpringBoot中开启Gzip压缩的方式,为下文全面讲解这两种方式做准备,先让大家了解相关知识。
2、SpringBoot中GeoJSON的实例
GeoJSON在WebGIS中的用处很多,很多矢量数据的边界,范围点等数据,我们都是直接以GeoJSON的格式返回给前端,并直接进行展示的。比如之前很多的行政区划展示,省市县等不同的行政区划范围展示等,我们的实现过程都是在后台的Controller层中返回一个包含GeoJSON的对象,方法如下:
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)//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的方法中我们调用如下:
@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);
}
经过以上的代码输出接口中就包含GeoJOSN数据,如下图所示:
其具体的geoJSON值如下图:
在网络窗口中可以看到整个接口返回的数据大小大约为5MB,如果遇到更大范围的行政区划,返回的数据肯定会大,比如西藏的行政区划大约有14MB,如图所示:
那么如何通过开启Gzip来减少这些数据的输出呢?下面两个部分来重点讲解。
三、全局开启Gzip实现
本节将详细介绍如何在SpringBoot中开启Gzip压缩的配置。
1、实现原理
在 application.yml
或 application.properties
中添加以下配置:
示例:application.yml
server:
compression:
enabled: true
mime-types: application/json
min-response-size: 1KB # 小于1KB的响应不压缩
或者application.properties中:
server.compression.enabled=true
server.compression.mime-types=application/json
server.compression.min-response-size=1024
请注意:该配置会对所有返回 application/json
的接口启用 GZIP 压缩。
2、实现效果
在我们的工程中配置文件是以yml的形式配置的,按照上面的步骤进行设置后,重新启动应用程序后来看一下同样的接口,其返回的数据量大小是多少:
通过以上图片可以直观的看到,开启全局压缩后,我们的接口返回大小,从14.4M下降了5MB,几乎是原来的1/3,这个压缩比例还是可以的。
四、局部约定配置
上面的这种实现方式全局的开启,也就是所有的接口都会开启,虽然可以设置mime-types来进行一定的过滤,但是依然会有很大的覆盖面。如果只想对某个接口生效或者指定一些接口生效又应该怎么实现呢?本节来讲讲针对这种情况的实现。
1、实现原理
基于局部约定配置的方式的实现原理其实是通过自定义 Filter
来精确控制哪些接口启用压缩,因此通过过滤器就可以将我们需要设定的请求路径进行针对性过滤,从而开启针对这些接口的Gzip过滤压缩。下面我们来看看在SpringBoot中如何实现呢?
2、具体代码实现
首先在SpringBoot中直接创建一个过滤器Filter,关键代码如下:
package com.yelang.framework.interceptor.gzip;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.zip.GZIPOutputStream;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
@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();
boolean match = gzipPatterns.stream()
.anyMatch(pattern -> pathMatcher.match(pattern, requestUri));
if (match) {
System.out.println("成功匹配");
// 启用 GZIP 压缩逻辑(同上)
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 {
System.out.println("未匹配上...");
chain.doFilter(request, response);
}
}
static class GZIPResponseWrapper extends HttpServletResponseWrapper {
private final GZIPOutputStream gzipOutputStream;
public GZIPResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
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();
}
}
}
这里演示了如何设置多个目标URL地址的配置方式,使用AntPathMatcher 来进行匹配实现。需要注意的是,这里我们没有区分请求的头地址,以若依为例,可能会在匹配时无法正确对应,导致无法正常的开启Gzip压缩,因此为了保证正确的启用,我们在进行地址匹配时,需要自动过滤项目的服务名称,详细代码如下:
String contextPath = req.getContextPath();
// 去掉 context-path 部分,只匹配相对路径
String relativePath = requestUri.substring(contextPath.length());
System.out.println("relativePath==>" + relativePath);
/*boolean match = gzipPatterns.stream()
.anyMatch(pattern -> pathMatcher.match(pattern, requestUri));*/
boolean match = gzipPatterns.stream()
.anyMatch(pattern -> pathMatcher.match(pattern, relativePath));
其实这里的contenxPath对应的就是配置文件中定义的参数:
# 开发环境配置
server:
# 服务器的HTTP端口,默认为80
port: 8080
servlet:
# 应用的访问路径
context-path: /earthqadmin
GeoJSON 数据通常体积较大,压缩后可显著减少传输时间。以下是实战建议:
项目 | 建议值 | 说明 |
---|---|---|
压缩类型 | GZIP | 浏览器原生支持 |
最小压缩阈值 | 1KB 或更小 | GeoJSON 一般远大于此值 |
MIME 类型 | application/json |
保持标准兼容 |
实测效果 | 原始 15MB → 压缩后 300KB | 压缩率可达 90%+ |
只有加上以上代码后才能实现正确匹配,在访问地址被请求是输出如下信息:
五、总结
以上就是本文的主要内容,我们将详细介绍在 SpringBoot 中开启 Gzip 压缩的两种方式的具体实现步骤,并通过实际的 GeoJSON 数据压缩案例,展示这两种方式的应用效果和优缺点。希望通过本文的介绍,能够帮助读者更好地理解和掌握在 SpringBoot 应用中使用 Gzip 压缩技术的方法,从而提升自己开发的 WebGIS 应用的性能和用户体验。博文首先简单介绍了Gzip的相关知识,然后介绍了在SpringBoot中开启Gzip的方式,最后以代码加案例的形式详细的介绍全局开启Gzip和局部开启Gzip的两种不同模式实现原理及具体代码实现。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。
更多推荐
所有评论(0)