在当今数字化时代,随着互联网应用的飞速发展,数据传输的效率和性能成为了至关重要的问题。GeoJSON 是一种基于 JSON 格式的地理空间数据交换格式,它广泛应用于地理信息系统(GIS)领域,用于描述地理空间数据的几何形状、属性等信息。
GeoJSON 数据通常包含大量的地理坐标点、几何形状等信息,数据量往往较大。在 Web 地理信息系统应用中,如地图展示、地理数据可视化等场景,GeoJSON 数据的传输效率直接关系到地图加载的速度和用户体验。
因此,对 GeoJSON 数据进行有效的压缩,以减少数据传输的体积,显得尤为重要。对于基于SpringBoot 框架构建的 WebGIS 应用来说,如何高效地传输数据、减少网络带宽的占用,是提升用户体验和系统性能的关键所在。
而 Gzip 压缩技术,作为一种被广泛采用的解决方案,无疑为这一问题的解决提供了强大的助力。
图片
以 GeoJSON 数据为例,通过在 SpringBoot 应用中开启 Gzip 压缩,对 GeoJSON 数据进行瘦身,不仅可以显著减少数据传输的体积,提高地图加载的速度,还可以提升用户的交互体验。在实际的 Web 地理信息系统开发中,这种优化手段是非常实用和有效的。通过对 GeoJSON 数据的压缩处理,我们可以更好地满足用户对于地图快速加载和流畅交互的需求,同时也为整个应用的性能优化提供了有力的支持。
在接下来的内容中,我们将详细介绍在 SpringBoot 中开启 Gzip 压缩的两种方式的具体实现步骤,并通过实际的 GeoJSON 数据压缩案例,展示这两种方式的应用效果和优缺点。
希望通过本文的介绍,能够帮助读者更好地理解和掌握在 SpringBoot 应用中使用 Gzip 压缩技术的方法,从而提升自己开发的 WebGIS 应用的性能和用户体验。
GZIP 是一种数据压缩格式,只能用于压缩单个文件。它可用于网络文件传输时的压缩,例如 nginx 中的 ngx_http_gzip_module
,启用压缩功能后可以节约带宽;也可用于本地文件存储时的压缩。本节将重点对Gzip进行一个简单的介绍,让大家对Gzip的相关知识有一个简单的了解。
Gzip 的压缩算法基于 LZ77 算法 和 Huffman 编码 的结合。具体过程如下:
http://jiurl.yeah.nethttp://jiurl.nease.net
",LZ77 算法会将其压缩为 "http://jiurl.yeah.net(22,13)nease(23,4)
",其中 (22,13) 表示距离当前位置 22 个字符处的 13 个字符与当前位置的字符相同。Accept-Encoding: gzip
)来判断是否使用 Gzip 压缩响应内容。Compression-webpack-plugin
插件)在构建过程中对地理数据文件进行 Gzip 压缩,然后在服务器上直接提供压缩后的文件,减少服务器的实时压缩负载。总之,Gzip 压缩技术在 GIS 领域的应用,不仅可以提高数据传输效率,还可以优化服务器性能和存储空间,是提升 GIS 应用性能的重要手段之一。
SpringBoot 是一个非常流行的 Java 基于 Spring 框架的快速开发框架,它极大地简化了 Spring 应用的开发过程。在 SpringBoot 应用中,通过合理的配置和编程,可以很方便地集成 Gzip 压缩功能,从而实现对响应数据的自动压缩。这不仅可以提高数据传输的效率,还可以减轻服务器的负载,提升整个应用的性能。
本节将重点介绍在SpringBoot中关于Gzip的相关知识以及在SpringBoot中GeoJSON的一些实践案例。
在 SpringBoot 中,开启 Gzip 压缩主要有两种方式:一种是通过配置文件进行全局配置,另一种是通过编程的方式在特定的控制器或方法上进行局部配置。这两种方式各有优缺点,适用于不同的应用场景。
application.yml
或 application.properties
)中添加相关的 Gzip 压缩配置,可以实现对整个应用的 HTTP 响应进行统一的压缩处理。这种方式简单方便,适用于大多数需要压缩的场景,但缺乏对特定数据类型的针对性处理。这里首先简单介绍了两种在SpringBoot中开启Gzip压缩的方式,为下文全面讲解这两种方式做准备,先让大家了解相关知识。
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来减少这些数据的输出呢?下面两个部分来重点讲解。
本节将详细介绍如何在SpringBoot中开启Gzip压缩的配置。
在 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 压缩。
在我们的工程中配置文件是以yml的形式配置的,按照上面的步骤进行设置后,重新启动应用程序后来看一下同样的接口,其返回的数据量大小是多少:
图片
通过以上图片可以直观的看到,开启全局压缩后,我们的接口返回大小,从14.4M下降了5MB,几乎是原来的1/3,这个压缩比例还是可以的。
上面的这种实现方式全局的开启,也就是所有的接口都会开启,虽然可以设置mime-types
来进行一定的过滤,但是依然会有很大的覆盖面。如果只想对某个接口生效或者指定一些接口生效又应该怎么实现呢?本节来讲讲针对这种情况的实现。
基于局部约定配置的方式的实现原理其实是通过自定义 Filter 来精确控制哪些接口启用压缩,因此通过过滤器就可以将我们需要设定的请求路径进行针对性过滤,从而开启针对这些接口的Gzip过滤压缩。下面我们来看看在SpringBoot中如何实现呢?
首先在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() {
returntrue;
}
@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 数据通常体积较大,压缩后可显著减少传输时间。以下是实战建议:
图片
只有加上以上代码后才能实现正确匹配,在访问地址被请求是输出如下信息:
图片
以上就是本文的主要内容,我们将详细介绍在 SpringBoot 中开启 Gzip 压缩的两种方式的具体实现步骤,并通过实际的 GeoJSON 数据压缩案例,展示这两种方式的应用效果和优缺点。
希望通过本文的介绍,能够帮助读者更好地理解和掌握在 SpringBoot 应用中使用 Gzip 压缩技术的方法,从而提升自己开发的 WebGIS 应用的性能和用户体验。
博文首先简单介绍了Gzip的相关知识,然后介绍了在SpringBoot中开启Gzip的方式,最后以代码加案例的形式详细的介绍全局开启Gzip和局部开启Gzip的两种不同模式实现原理及具体代码实现。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。