PostgreSQL+Postgis MapboxVectorTile应用

java+postgis实现4490坐标系动态矢量瓦片并实现后端聚合 java+postgis实现动态矢量瓦片并支持4490坐标系和实现后端聚合 阅读详情

背景

该实验基于Postgres+Postgis搭建实时矢量瓦片服务。
矢量瓦片的优势

  1. 可以支持高分辨率屏幕显示
  2. 地图渲染在前端,可以支持前端随意更改配图方案,解决传统栅格瓦片动态样式上的问题
  3. 要素查询可以在前端进行
  4. 保持了矢量数据的优势,同时采用切片方式在传输效率上有一定提升

实时矢量瓦片

不在线下用工具预先切片,采用即时浏览传输矢量瓦片;
采用实时矢量切片可以做到数据编辑功能,同时解决数据时效性问题

使用到的相关函数

ST_AsMvtGeo 将Geom转化为MVT的geom
ST_AsMVT 将geom转换为MVT数据
ST_TileEnvelope 根据行列号获取Envelop (该函数需要Postgis3.0才有,使用postgis-vt-util代替)

软件环境

  • PostgreSQL11
  • Postgis2.5
  • java
  • (前端渲染) leaflet1.7、mapbox

实现过程

模拟数据

使用sql语句创建表,并在给定坐标范围内模拟点数据

CREATE TABLE data_1000000 AS SELECT
( ST_Dump ( ST_GeneratePoints ( kl.geom, 200000 ) ) ).geom AS geom,
md5( ( random ( ) * random ( ) ) :: text ) AS id,
random ( ) * 1000 AS val 
FROM ( 
  SELECT ST_SetSRID ( ST_MakeBox2D ( ST_Point ( 113.213316,22.954094 ), ST_Point ( 113.62805,23.368228 ) ), 4326 
) geom ) kl;

sql解读:
创建表名:data_1000000
坐标范围:左下角坐标(113.213316,22.954094)、右下角坐标(113.62805,23.368228),坐标系SRID为4326
模拟数据量:100万
表字段:geom(空间字段)、id(md5格式的唯一编码)、val(点的权重值0-1000)

部署扩展函数

由于需要用到ST_TileEnvelope函数,该函数需要postgis3.0才支持,所以使用扩展的函数库实现(postgis-vt-util下载)
执行postgis-vt-util.sql添加相关函数到数据库

这个库由mapbox提供,生成符合mapbox矢量切片格式的数据

后端接口

后端需要实现前端请求切片范围的矢量切片生成,传入的参数可能是行列号或者经纬度范围,最终返回byte的矢量切片数据

处理逻辑

graph LR
start("前端请求") --> isEnvelop("是否传入经纬度范围")
isEnvelop --no--> tileBBox("根据切片z,x,y转换经纬度范围")
isEnvelop --yes--> makeEnvelop("生成几何范围")
tileBBox --> makeEnvelop
makeEnvelop --> asMVTGeom("将几何图形转为mapbox矢量瓦片坐标")
asMVTGeom --> asMVT("返回mapbox矢量切片的byte数组")

点线面在转换byte数组时需要分开处理

代码编写

//根据切片xyz获取矢量切片
public byte[] getMVT(String tableName, int x, int y, int z, int srid) {
    byte[] res;
    try {
        String sqlStr = "SELECT " +
                "ST_AsMVT( vt, 'points', 256, 'geo' ) FROM ( " +
                "SELECT ST_SetSRID ( ST_Point ( ST_X ( A.geo ), ST_Y ( A.geo )), " + srid + " ) geo FROM (" +
                "SELECT ST_AsMVTGeom ( w.geom, Box2D ( TileBBox ( " + z + "," + x + "," + y + ", " + srid + " )), 256, 0, TRUE ) AS geo  " +
                "FROM " + tableName + " w  WHERE TileBBox ( " + z + "," + x + "," + y + ", " + srid + " ) && geom  ) A  " +
                "GROUP BY ST_X ( A.geo ), ST_Y ( A.geo ) ) AS vt";

        res = jdbcTemplate.queryForObject(sqlStr,byte[].class);
    } catch (Exception e) {
        throw e;
    }
    return res;
}

//根据空间范围获取矢量切片
public byte[] getMVTByEnvelop(String tableName, double lon_min, double lat_min, double lon_max, double lat_max, int srid) {
    byte[] res;
    try {
        String sqlStr = "SELECT " +
                "ST_AsMVT( vt, 'points', 256, 'geo' ) FROM ( " +
                "SELECT ST_SetSRID ( ST_Point ( ST_X ( A.geo ), ST_Y ( A.geo )), " + srid + " ) geo FROM (" +
                "SELECT ST_AsMVTGeom ( w.geom,ST_MakeEnvelope ( " + lon_min + "," + lat_min + "," + lon_max + "," + lat_max + ", " + srid + " ), 256, 0, TRUE ) AS geo  " +
                "FROM " + tableName + " w  WHERE ST_MakeEnvelope ( " + lon_min + "," + lat_min + "," + lon_max + "," + lat_max + ", " + srid + " ) && geom  ) A  " +
                "GROUP BY ST_X ( A.geo ), ST_Y ( A.geo ) ) AS vt";

        res = jdbcTemplate.queryForObject(sqlStr, byte[].class);
    } catch (Exception e) {
        throw e;
    }
    return res;
}

前端代码编写

mapboxgl加载方法

<!DOCTYPE html>
<html>
<head>
    <title>Mapbox加载MVT</title>
    <meta charset='utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <script src="https://api.mapbox.com/mapbox-gl-js/v1.10.0/mapbox-gl.js"></script>
    <link href="https://api.mapbox.com/mapbox-gl-js/v1.10.0/mapbox-gl.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        html,
        body,
        #map {
            height: 100%;
        }
        .layerPanel {
            position: absolute;
            top: 10px;
            right: 20px;
            background: #ffffff;
            padding: 5px 2px;
        }
    </style>
</head>

<body>
    <div id='map'></div>
    <script>
        let center = [113.33616, 23.0963];
		//获取地图样式
        let style = getStyle();
        //创建3857坐标系地图
        var map = window.map = new mapboxgl.Map({
            container: 'map',
            // epsg: 'EPSG:3857',
            center : center,
            zoom:12,
            hash: true,
            style: style
        });
        // map.showTileBoundaries = true;
        map.on('load', function () {
            //添加天地图底图
            addTDTLayers(map);
            map.addLayer({
                "type": "circle",
                "source": "test",
                "paint":{
					"circle-color": "blue",
					"circle-radius":4,
                },
                "source-layer": "points",
                "maxzoom": 17,
                "id": "1"
            })
        });

        function getStyle() {
            let style = {
                "version": 8,
                "name": "Basic-my",
                "metadata": {
                    "mapbox:autocomposite": true,
                    "mapbox:type": "template"
                },
                "center": center,
                "zoom": 3,
                "bearing": 0,
                "pitch": 0,
                "sources": {
                    "test": {
                        "type": "vector",
                        "tiles": ["{后端服务}/getMVT?tableName=data_1000000&x={x}&y={y}&z={z}"]
                    }
                },
                "layers": []
            };
            return style;
        }
        //添加3857坐标系天地图
        function addTDTLayers(map) {
            //添加3857天地图矢量source
            var source_vec = {
                "type": "raster",
                "tiles": [
                    "http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=7b06bd204544a8631beccd5fd56ad8c1",
                ],

                "tileSize": 256
            }
            if (!map.getSource("TDT_VEC")) {
                map.addSource("TDT_VEC", source_vec);
            }

            //添加3857天地图矢量图层
            var Layer_vec = {
                "id": "tdtvec",
                "type": "raster",
                "source": "TDT_VEC",
                "minzoom": 0,
                "maxzoom": 17
            }
            if (!map.getLayer("tdtvec")) {
                map.addLayer(Layer_vec);
            }
        }
    </script>
</body>
</html>

Leaflet加载方式

<!DOCTYPE html>
<html>
<head>
	<title>VectorGrid.Protobuf example</title>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="src/leaflet.css" />
</head>
<body style='margin:0'>
	<div id="map" style="width: 100vw; height: 100vh; background: white"></div>
	<script type="text/javascript"  src="src/leaflet-src.js"></script>
	<script type="text/javascript"  src="src/Leaflet.VectorGrid.js"></script>
	<script>
		var map = L.map('map',{
			renderer: L.canvas
		});			
		map.setView({ lat: 23.0963, lng: 113.33616 }, 14);
		//加载底图
		L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
			attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
		}).addTo(map);
	
		var vectorTileStyling = {
			points:{
				weight: 2,
				color: 'red',
				opacity: 1,
				fillColor: 'yellow',
				fill: true,
				radius: 6,
				fillOpacity: 0.7
			}
		}
		
		var mapboxUrl = "http://localhost:8081/xxx/getMVT?tableName=data_1000000&x={x}&y={y}&z={z}";

		var mapboxVectorTileOptions = {
			rendererFactory: L.canvas.tile,
			vectorTileLayerStyles: vectorTileStyling
		};

		var mapboxPbfLayer = L.vectorGrid.protobuf(mapboxUrl, mapboxVectorTileOptions);
		map.addLayer(mapboxPbfLayer)
	</script>
</body>
</html>

结果展示

详情浏览

相关链接

https://blog.youkuaiyun.com/qq_35241223/article/details/106439268
https://github.com/mapbox/postgis-vt-util

百万级别矢量数据动态切片,这个方法很实用 对于矢量数据的渲染显示,一般是以geojson的方式加载,或者直接以shp的形式解析加载,不管那种方法,对于少量的数据显示还可以满足要求,但是面对百万级别的数据量,直接加载显示的话,会造成严重的卡顿,甚至卡死。这里介绍一种动态切片的方法,轻松加载百万级别的矢量数据。 用到的工具有:postgis + openlayers + springboot 用到的数据有:100万条点数据 数据准备 首先将数据导入到数据库,我这里使用的是测试数据,java连接数据库生成了包括经纬度和时间、类型、UUID等字段的矢量点数 阅读详情

相关推荐

pgsql+postgis 实时返回mvt(Mapbox Vector Tiles) 矢量瓦片。

pgsql+postgis 实时返回mvt(Mapbox Vector Tiles) 切片。 xmin,ymin,xmax,ymax 为瓦片范围坐标,下面有x,y,z转换为瓦片空间范围方法。 SELECT ST_AsMVT ( fmvt, 'pointLayer', 4096, 'geom' ) as "mvt" FROM (SELECT dwmc, ST_AsMVTGeom (ST_Transform ( st_simplify (dgeom,${tolerance},true), 3395)

keepstudy_yangzh的博客 5155

基于mapbox搭建可离线的矢量切片地图服务-2.PostGIS+GeoServer矢量切片

作者:ATtuing 出处:http://www.cnblogs.com/ATtuing 最近在做关于mapbox的项目,看到这篇文章感觉特别好,特此转载记录一下。 先不说废话直接上地址:(所有东西都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵)。 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.html 02:德国-德累斯顿市:http://test.sharegis.cn/mapbox/html/6germany.html 1.Pos

weixin_42562567的博客 1875

GIS技术 MVT动态矢量切片(MapBox Vector Tile)

GIS动态矢量切片 前言 有关矢量切片以及MVT(MapBox Vector Tile)自行搜索了解,不再赘述。 接口格式 http://domain:port/map/vector/tile/{z}/{x}/{y},其中z代表缩放层级,x、y代表当前行列号 一、方法 采用postgis的函数ST_AsMVT、ST_AsMVTGeom、ST_TileEnvelope函数,实现此功能。 简单讲 ST_TileEnvelope 函数用于计算行列并返回对应的矩形范围,ST_AsMVTGeom返回图层中对应行

Birds-Frags's Blog 1万+

postgis mvt矢量切片 django drf mapboxgl

postgis mvt矢量切片 django drf mapboxgl

LEILEI18A的博客 2670

搭建webgis环境 (Java、Tomcat、GeoServer、PostgreSQL、PostGIS、OpenLayers3) 超详细

1.安装并配置Java 1.1下载Java1.8 根据系统架构下载对应版本,32位选择“Windows x86”,64为选择“Windows x64” URL:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html   我的系统是64位,所以下载的文件是 jdk-8u161-windo...

AaronWmy的博客 3845

tomcat+geoserver+postgis构建开源Webgis平台(windows)

这篇文章是自己参考了 网上几位前辈的文章写出来的,自己的东西不多,但是比较实用。1. 安装tomcat2. 安装postgreSQL:   PostgreSQL 8.0.2 已经正式发布,该版本被官方建议广泛使用,从8.0开始增加了对 Windows2K/XP 平台的直接支持,并随安装包附带了 pgAdmin III 图形界面的数据库管理工具(开源),您可以通过该图形管理界面创建数和操作据库、表空

wangqiaowqo的专栏 1584

postgresql矢量切片坐标转换的ST_AsMVTGeom函数使用

Wagyu库比默认的GEOS库更快且能产生更正确的结果,但是它可能会丢弃小的多边形。buffer —— 矢量坐标空间中缓冲区的距离,位于该缓冲区的几何图形部位根据clip_geom参数被裁剪或保留。如果为NULL,则默认为256。extent —— 是按规范定义的矢量切片坐标空间中的某个矢量切片的范围。将一个图层中位于参数box2d范围内的一个几何图形的所有坐标转换为MapBox VectorTile坐标空间里的坐标。bounds —— 某个矢量切片的范围对应的空间参考坐标系中的几何矩形框(没有缓冲区)。

经历过大厂、小厂风风雨雨的程序佬 1469

geoserver+postgis+openlayers 空间要素的增删改

geoserver+postgis+openlayers 空间要素的增删改功能,具体还可参考https://blog.youkuaiyun.com/rrrrroy_Ha/article/details/90904465

java map vector_使用java生成mapbox-gl可读的vector tile

概述mapbox-gl主要数据源来自mapbox vector tile,本文就是要阐述怎样把postgresql中的地理空间数据转换成vector tile,流程图如下:配置该工程采用spring boot+maven,所以第一步少不了pom.xml配置:xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apac...

weixin_36237278的博客 1849

2.(高级示例篇)leaflet+postgres+postgis+geoserver实现高性能聚合图(亿级别数据量).zip

该资源包的执行效果查看地址:https://blog.youkuaiyun.com/m0_60387551/article/details/123184049 “地图之家”专栏中的“2.(高级示例篇)leaflet+postgres+postgis+geoserver实现高性能聚合图(亿级别数据量)”。如下载有问题,可联系博主。 解压密码:leaflet

单细胞多组学数据整合分析实战:从原始数据到跨平台合并

本文详细介绍了单细胞多组学数据整合分析的实战流程,从原始数据处理到跨平台合并分析。通过Seurat和Harmony等工具的应用,帮助研究者有效解决批次效应问题,保留真实的生物学信号。文章包含代码示例和常见问题解决方案,特别适合需要进行单细胞合并分析的研究人员参考。

weixin_30752699的博客 91

Java SpringBoot 集成PostGIS(附项目代码)

Java SpringBoot 集成PostGIS(附代码) 环境 java 1.8 框架:springboot2 持久层:mybatis plus 数据库:postgresql+postgis 1、gradle配置postgresql依赖 dependencies { ... compile group: 'org.postgresql', name: 'postgresql', version: '42.2.14' ... } 2、配置yml文件 spring: data

u011505575的博客 7032

拌合楼软件开发(24)接收微信消息生成车辆计划

【摘要】针对拌合站客户群体文化程度不高、习惯微信群沟通的业务场景,提出通过企业微信机器人实现微信对话下单的解决方案。核心是利用WorkTool工具的消息回调机制:1)配置接收消息的API接口;2)解析JSON格式的对话数据,筛选@机器人的有效消息;3)采用*号分隔符提取订单信息并进行校验;4)建立微信昵称与客户系统的映射关系。方案解决了传统系统登录门槛高的问题,但需注意群名唯一性、多系统对接及客户身份识别等关键问题。全文重点阐述技术实现逻辑而非具体代码。

morsth的博客 1045

基于 PostGIS 生成MVT矢量瓦片

基于Springboot+PostGIS动态生成MVT矢量瓦片

xuyizhuo的博客 3826

抖音Web端私信Protobuf逆向解析实战

本文详细解析了抖音Web端私信通信的逆向过程,发现其核心采用WebSocket传输Protobuf序列化数据。通过抓包获取二进制样本,利用protoc工具进行原始解码,并逐步推导和编写出对应的.proto协议定义文件,最终实现模拟消息的编码与解码,为理解私有协议逆向提供了完整实战案例。

water的专栏 762

从Reset到Read:深入解析Rolling Shutter曝光流水线

本文深入解析Rolling Shutter(卷帘曝光)的工作原理,重点探讨Reset和Read信号在图像传感器中的关键作用。通过Reset-Read流水线机制,详细解释了曝光控制、时序调优及运动伪影补偿等核心技术,帮助读者理解卷帘曝光在高速摄影和动态场景中的应用。

weixin_42531925的博客 254

瓦片地图服务器搭建步骤

目录 一、系统环境以及软件要求 gcc 升级到5.4以上,推荐升级至最新版 mapnik 安装 安装nodejs 安装node-mapnik 数据库: PostgreSQL 地图数据下载以及使用 启动服务器 二、gcc要求和mapnik安装 三、nodejs安装 四、安装node-mapnik 五、数据库安装 PostgreSQL以及启动 六、地图数据下载以及导入 七、...

Samshuo的博客 7799

FFMPEG音频开发: Linux下采集摄像头(使用V4L2框架)数据录制成MP4视频保存到本地

一、环境介绍 操作系统介绍:ubuntu 18.04 FFMPEG版本: 4.4.2 摄像头: USB摄像头、虚拟机挂载本机自带摄像头 二、FFMPEG与X264下载编译 X264下载地址: http://www.videolan.org/developers/x264.html FFMPEG下载地址:https://ffmpeg.org/download.html Yasm ...

8873

Postgis动态矢量瓦片前后端部署指南

webgis最近随着智慧城市、数字孪生等项目大火,成为当下非常热门的技术。mapbox提出的矢量瓦片技术,解决的B/S端在面对大体量gis数据时的前端的渲染压力。使得前端地图在面对百万级的数据量依旧游刃有余,甚至比在C端上的浏览还要丝滑。动态矢量瓦片技术,解决了矢量存储在数据库中的实时动态更新,以及不再需要使用离线工具对矢量进行本地切片发布的问题

weixin_57664381的博客 3902

CDMamba安装配置Windows(50系列的显卡)

本人家里的显卡是RTX3050的,运行起来非常缓慢,大家可以参考上一篇文章,以下是用RTX5080配置的CDMamba,里面有一些库没有更新,因此会比较坑爹。就是pytorch已经更新了,搭配的是cuda12.8,但是cdmamba里的mmcv只更新到cuda12.1的版本,当然很多人会说那就向下兼容,但是笔者已经尝试了,会一直提示mmcv的问题。因此,索性直接不用mmcv。

hanfeng5268的博客 686

SAP PI 系统复制,不只是把数据库拷过去,而是一次集成拓扑的重新落位

文章摘要:SAP PI/PO系统刷新生产数据到测试环境时,标准系统复制无法自动处理集成中枢特有的环境绑定问题。系统复制后,PI仍保留生产环境的连接配置,可能导致测试系统向生产环境发送消息。SAP提供的CTC模板可自动化部分后续配置,但无法替代人工对接口风险的全面评估。关键在于系统复制前绘制接口风险地图,复制后进行分层次验证:禁用生产连接、重定向测试接口、复核安全配置,并通过代表性链路测试确保系统行为符合预期。这需要结合SAP标准流程与业务语义判断,形成完整的治理闭环。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 85

使用PostgreSQL+PostGIS实现地图引擎(经历ArcGIS Server/GeoServer/MapServer后)

地图服务器方案探索 研究GIS服务器已经很长一段时间,最开始使用ArcGIS Server,后来由于费用问题公司基于nginx和lua自己做了一套矢量瓦片的地图服务器,再后来开始研究使用Geoserver,再后来由于性能问题改研究Mapserver,最近由于开发的灵活性和业务需求开始研究PostgreSQL+PostGIS的方案。 PostGIS官方方案 WITH mvtgeom AS ( SELECT ST_AsMVTGeom(geom, ST_TileEnvelope(12,513,412)) AS

liujiusheng的博客 2714

手把手教你学Simulink——基础电机控制场景实例:基于Simulink的永磁同步发电机温度场耦合仿真

摘要:本文详细介绍了基于Simulink的永磁同步发电机(PMSG)电-热耦合仿真方法。通过Simscape Electrical搭建含热端口的PMSG模型,结合集总参数热网络(LPTN)实现损耗计算与温度反馈,分析了过载工况下温升对电阻和永磁体性能的影响。仿真结果表明:150%过载20秒会导致绕组温升132°C,电阻增加42%,磁链衰减10.5%。文章还提供了自然冷却与强迫风冷的对比数据,并建议通过多物理场耦合仿真预防实机过热问题。该方法可有效支撑高功率密度电机热设计,避免永磁体退磁风险。

MHD0815的博客 252

Shapefile导入PostGIS的方法介绍

本篇博文主要介绍工具法:使用PostGIS自带工具(PostGIS Shapefile and Dbf Loader Exporter)和QGIS 在入库时的区别及注意事项。 使用PostGIS自带工具入库 如下图所示,单击 Add File 可以选择需要入库的 Shapefile文件,可以设置数据库模式(Schema)、数据表的名称(Table,默认为Shapefile文件名称)、Geo Column名称(几何列名称,默认为geom)、空间参考ID(SRID,默认为0,可根据需要设置为 4326或38

sll714827的博客 743

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

点、线、面生成mvt(MapBox Vector Tile)格式的瓦片总结

矢量切片可以以三种形式呈现:GeoJSON、TopoJSON 和 MapBox Vector Tile(.mvt),矢量切片技术继承了矢量数据和切片地图的双重优势,有以下优点: 瓦片以mvt格式的存储,是以每一个瓦片号为基准进行存储的。大小都是256*256;粒度更小,信息接近无损;前端可根据数据定制渲染样式;数据更新快,更灵活; .mvt 压缩率更高,体积更小; 点: 每一级别:经纬度转像素坐标 像素坐标计算所在瓦片号 像素坐标转瓦片内像素坐标 根据瓦片内像素坐标:进行聚合————同一个像素点聚合后记录一

qq_40985985的博客 9845

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

fast-lio2复现跑avia数据集

本文详细介绍了在Windows WSL2中安装Ubuntu 22.04并配置ROS2 Humble环境的全过程,涵盖系统初始化、ROS2安装、Livox雷达驱动编译及FAST-LIO2 ROS2版本的构建与验证。通过完整数据集回放与建图测试,成功实现点云地图生成与轨迹记录,并利用evo工具完成轨迹分析与可视化。最终输出包括累积点云地图、位姿轨迹及实验配置文件,为后续精度评估与复现提供基准。

chase_my_dream的博客 359

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

上一篇: PostgreSQL+postgis实时矢量切片效果展示
下一篇: Vue Cli4.0+Cesium1.77应用示例
上古石
博客等级 码龄16年 19粉丝 17原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值