目錄
前言
一、GZIP壓縮知識簡介
1、什么是Gzip
2、Gzip特點
3、Gzip在GIS方面的應用
二、SpringBoot中開啟Gzip的方式
1、在SpringBoot中開啟Gzip的知識簡介
2、SpringBoot中GeoJSON的實例
三、全局開啟Gzip實現
1、實現原理
2、實現效果
四、局部約定配置
1、實現原理
2、具體代碼實現
五、總結
前言
????????在當今數字化時代,隨著互聯網應用的飛速發展,數據傳輸的效率和性能成為了至關重要的問題。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: truemime-types: application/jsonmin-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");@Overridepublic 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());}@Overridepublic ServletOutputStream getOutputStream() {return new ServletOutputStream() {@Overridepublic void write(int b) throws IOException {gzipOutputStream.write(b);}@Overridepublic boolean isReady() {return true;}@Overridepublic 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端口,默認為80port: 8080servlet:# 應用的訪問路徑context-path: /earthqadmin
????????GeoJSON 數據通常體積較大,壓縮后可顯著減少傳輸時間。以下是實戰建議:??????
項目 | 建議值 | 說明 |
---|---|---|
壓縮類型 | GZIP | 瀏覽器原生支持 |
最小壓縮閾值 | 1KB 或更小 | GeoJSON 一般遠大于此值 |
MIME 類型 | application/json | 保持標準兼容 |
實測效果 | 原始 15MB → 壓縮后 300KB | 壓縮率可達 90%+ |
????????只有加上以上代碼后才能實現正確匹配,在訪問地址被請求是輸出如下信息:
五、總結
????????以上就是本文的主要內容,我們將詳細介紹在 SpringBoot 中開啟 Gzip 壓縮的兩種方式的具體實現步驟,并通過實際的 GeoJSON 數據壓縮案例,展示這兩種方式的應用效果和優缺點。希望通過本文的介紹,能夠幫助讀者更好地理解和掌握在 SpringBoot 應用中使用 Gzip 壓縮技術的方法,從而提升自己開發的 WebGIS 應用的性能和用戶體驗。博文首先簡單介紹了Gzip的相關知識,然后介紹了在SpringBoot中開啟Gzip的方式,最后以代碼加案例的形式詳細的介紹全局開啟Gzip和局部開啟Gzip的兩種不同模式實現原理及具體代碼實現。行文倉促,定有不足之處,歡迎各位朋友在評論區批評指正,不勝感激。