前段时间接了一个项目,涉及到了空间信息三维可视化的工作。之前在网上查找无意中看到ArcGIS API for JavaScript(以下简称“ArcGIS API”或“该API”)可以在网页上制作三维可视化图。好在有友人在国外帮我把整个文档和API下载下来了,于是就着手学习了一下这个API。

简介

做GIS的肯定清楚ArcGIS是什么,包括一系列的ArcMap、ArcScence、ArcEngine等。ArcGIS推出了这套JavaScript API,现在有4.2版本,该版本可以创建二维、三维的网页应用程序。

下面是官网给出的一些三维可视化的示例。

 

 

ArcGIS制作可视化图的大体结构为:View 包含 Map 包含 Layer(s) 包含 Graphic(s)。带(s)表示是一个数组。其中

  • View(视图):对应HTML上的一个元素,在该元素中显示底图以及底图上的所有图层。
  • Map(底图):可以为多种类型:街道图、卫星图、大洋图、地表图等。
  • Layer(图层):有多种类型,如FeatureLayer、GraphicLayer、PointCloudLayer,甚至有CSVLayer等。对于图层的解释,ArcGIS官方文档指出:

    图层是 ArcMap、ArcGlobe 和 ArcScene 中地理数据集的显示机制。一个图层引用一个数据集,并指定如何利用符号和文本标注绘制该数据集。向地图添加图层时,要指定它的引用数据集并设定地图符号和标注属性。

  • Graphic(图形):图形在官方文档中的解释是:“图形是一个矢量图,代表了真实世界的地理事物或地理现象。它可以包含geometry(几何)、symbol(符号)、attributes(特性)。”

    A Graphic is a vector representation of real world geographic phenomena. It can contain geometry, a symbol, and attributes.A  Graphic is displayed in the GraphicsLayer.

    当我们拿到带有空间信息的数据,就可以对每个数据设计可视化的图形,将同类的数据显示的图形添加到同一个图层中,就可以显示了。官方指出Graphic是显示在GraphicLayer中的,但是FeatureLayer中有一个source属性,可以将Grapchic自动转换(autocast),从而在Layer中显示。

制作可视化图

使用ArcGIS API,需要引用各个组件(Map, SenceView, FeatureLayer ...),各个组件引用的路径在官网文档上会标注。引用时使用require()函数(这里使用TypeScript语法表示变量的类型)

require(modules: Array<String>, callback: function) => void

即可将各个组件引用到应用程序中。其中

  • modules:是一个字符串数组,每一项代表了一个组件的引用路径。例如,组件Map的地址是 “esri/Map” 。
  • callback:是一个回调函数,表示各个组件加载完成后执行的函数操作。这个函数的的参数比较特别,参数个数与modules中引用的组件的个数相同,每个参数与modules中的组件路径一一对应,表示引用的各个组件的一个对象。

于是,脚本整体上类似于:

require(["esri/Map","esri/views/SceneView","dojo/domReady!"
], function(Map, SceneView) {// Code to create the map and view will go here
});

当然这些脚本要写在一对script标签里。

添加底图

在ArcGIS API中,所有地图要素都是以对象的形式存在的。要在地图上添加地理地图,就需要创建地理地图对象。Map类的对象就表示一个地理地图。当引用了MA类组件之后,就可以创建其一个Map类的对象了。

var map = new Map({basemap: "streets",ground: "world-elevation"
});

Map类的属性有这些:

  • basemap:地理底图的类型。ArcGIS提供了多种类型的地理底图,包括了OpenStreetMap(osm)。
  • layers:包含了地图上展示的要素所在的图层,这个图层是“可操作的”,包括FeatureLayers、WebTileLayers和GraphicsLayers,其中不包含basemaps,也就是无法通过访问layers属性访问basemap。
  • allLayers:与layers属性不同的是,这个属性包含了basemap图层、ground图层以及“可操作图层”。
  • ground:这个属性只在使用三维视角的时候有用。ground属性是一个Ground类的对象,它将真实世界的地形或地势渲染到底图上。它包含了一组图层来显示地图。在创建地理底图的时候,ground属性可以包含一组layer,也可以仅仅赋予一个字符串 world-elevation ,通过操作ground中的layer属性来对底图进行操作。示例见Toggle ground elevation。

通过调节这些属性,就可以实现我们想要的地图。

添加视图

我们需要一个视图来对我们所制作的地图进行观察,包括对底图的观察以及其他所有要素的观察。在ArcGIS软件中,如果制作二维地图或进行二维分析,就使用ArcMap软件;如果制作三维地图或进行三维分析,就使用ArcScene软件。在ArcGIS API中也是一样的。我们如果制作二维地图,就使用MapView类的对象创建视图;如果制作三维地图,就使用SceneView类的对象创建视图。

创建一个视图可以的方法与创建底图类似,如

var view = new SceneView({container: "viewDiv",map: map
});

这个SceneView的属性非常多,日后有空一一列举,与我们制作的三维地图关系较大的有:

  • container:是一个DOM元素的id,地图将渲染在该DOM元素内。ArcGIS API制作的地图可以自适应。
  • map:显示的底图。制作好底图后,在这里引用制作的底图实例,即可在地图上显示。
  • camera:视图摄像机。摄像机代表了三位观察的位置和方向。该属性是一个Camera类的实例,使用三个参数确定了摄像机的位置和方向:
    • position:摄像机的位置。是一个Point类的对象,可以使用经(longitude)纬(latitude)度作为平面位置的参数,也可以使用大地坐标(x, y)作为平面位置的参数。高程都是用z属性来指定的。还有一个spatialReference的属性,用于指定参考系。
    • heading:摄像机朝向的方位角。
    • tilt:摄像机的“垂直角”,这个定义与测量学中的垂直角(天顶距)定义不同,当摄像机竖直向下时,该角度为0°。

一旦创建了视图对象,就会在选定的DOM元素中进行渲染。

添加图层

ArcGIS API提供了丰富的图层可以使用,但是不同的图层代表了不同的含义。这里只分析一下FeatureLayer和GraphicLayer的区别:当图层与某一地理实体相对应时,最好使用FeatureLayer,表示是地理要素的图层,具有实体含义;否则使用GraphicLayer,表示仅仅是一些几何元素,没有地理含义。

我所拿到的项目要可视化的内容具有地理实体含义,所以使用FeatureLayer。一个FeatureLayer对象包含很多属性,可以通过REST服务创建,也可以本地创建。使用REST服务创建需要发布REST服务,然后在url属性上填入REST服务的地址。这里介绍从本地创建FeatureLayer中的要素,官网示例见Sample - Create a FeatureLayer with GeoJSON data。

如果要从本地创建要素,需要同时设置FeatureLayer的五个属性:fields、objectIdField、spatialReference、geometryType和source。

  • fields:是一个对象数组,相当于ArcMap中的属性表各个字段的配置,每一个对象表示了属性表中的一个字段。每个对象有以下几个常用属性

    • name:字段名。
    • type:字段的数据类型,与ArcMap中一样,有small-integer、integer、single、double、string、date、oid、geometry、blob、raster、guid、global-id、xml等。
    • alias:字段替用名。
    • length:字段长度。
    • nullable:字段是否可空。
    • editable:字段时候可编辑。
  • objectIdField:指定fields中那个字段代表了要素的ObjectId。ObjectId是每个要素的唯一标识符。
  • spatialReference:指定地理参考系。
  • geometryType:表示要素的几何类型,有point、mulitpoint、polyline、polygon等类型。
  • source:是一个Graphic对象的集合。每个Graphic对象包括三个部分:geometry、symbol和attribute。
    • geometry:是一个Geometry类的对象,定义了Graphic对象的地理位置。Geometry类的派生类有Point(点)、MultiPoint(多点)、Polyline(折线)、Polygon(折线)等。
    • symbol:该要素显示时的符号,代表了可视化方式。在创建Graphic对象的时候直接指定其symbol属性不是一个比较好的做法。比较好的做法是使用Renderer(渲染器)来对图层中的所有要素进行统一渲染。
    • attribute:是一个对象数组,每个对象要包含fields中声明的所有不可空字段。

除此之外,还有一些属性是非常有用的:

  • renderer:渲染器。是一个Renderer类的对象,表示对要素的geometry和attribute如何进行渲染。
  • popupTemplate:弹出框的模板,是一个PopupTemplate对象,可以用来显示要素的数据。

当我们获取到了可视化的数据,首先创建一个Graphic数组,在官网示例中,是这样的

return arrayUtils.map(geoJson.features, function(feature, i) {return {geometry: new Point({x: feature.geometry.coordinates[0],y: feature.geometry.coordinates[1]}),// select only the attributes you care about
    attributes: {ObjectID: i,title: feature.properties.title,type: feature.properties.type,place: feature.properties.place,depth: feature.geometry.coordinates[2] + " km",time: feature.properties.time,mag: feature.properties.mag,mmi: feature.properties.mmi,felt: feature.properties.felt,sig: feature.properties.sig,url: feature.properties.url}};
});

这里使用了arrayUtils的方法将一个数组映射为另一个数组。也可以使用foreach循环来完成这件事。将Griphic数组用一个变量保存起来。

fields也需要我们进行创建,官网的示例中创建了如下的属性表:

var fields = [{name: "ObjectID",alias: "ObjectID",type: "oid"},{name: "title",alias: "title",type: "string"},{name: "type",alias: "type",type: "string"},{name: "place",alias: "place",type: "string"},{name: "depth",alias: "depth",type: "string"},{name: "time",alias: "time",type: "date"},{name: "mag",alias: "Magnitude",type: "double"},{name: "url",alias: "url",type: "string"},{name: "mmi",alias: "intensity",type: "double"},{name: "felt",alias: "Number of felt reports",type: "double"},{name: "sig",alias: "significance",type: "double"}
];

我们现在就可以创建FeatureLayer了,示例代码如下:

var lyr = new FeatureLayer({source: graphics, // autocast as an array of esri/Graphic// create an instance of esri/layers/support/Field for each field objectfields: fields, // This is required when creating a layer from GraphicsobjectIdField: "ObjectID", // This must be defined when creating a layer from Graphicsrenderer: quakesRenderer, // set the visualization on the layer
    spatialReference: {wkid: 4326},geometryType: "point", // Must be set when creating a layer from Graphics
    popupTemplate: pTemplate
});map.add(lyr);

最后一行通过map类对象的add()方法,将该要素图层添加到地图上。其中,quakesRenderer是创建的渲染器,下小节中会详细讲解。

设计渲染器

渲染器是地图显示符号的方法,相当于Echarts中的VisualMap配置项。ArcGIS API中有很多渲染器,我们这里对点符号的渲染可以使用SimpleRenderer,有几个属性

  • label:渲染器标签。
  • symbol:渲染用的符号。是Symbol类的一个对象。Symbol的派生类包含了丰富的可视化类型,有二维的和三维的。如果使用三维的可视化符号,使用Symbol3D类,包括二维可视化符号的三维版本和一些三维可视化特有的符号,如MeshSymbol3D。
  • visualVariables:视觉变量,是一个对象数组。效果类似于Echarts中的VisualMap配置项,可以根据某一属性值对颜色、尺寸、透明度、旋转角度进行映射调整。每一个元素都是以下几种类型:ColorVisualVariable、SizeVisualVariable、OpacityVisualVariable、RotationVisualVariable。

官网设计的渲染器如下所示:

var quakesRenderer = new SimpleRenderer({
symbol: new SimpleMarkerSymbol({style: "circle",size: 20,color: [211, 255, 0, 0],outline: {width: 1,color: "#FF0055",style: "solid"}
}),
visualVariables: [
{type: "size",field: "mag", // earthquake magnitudevalueUnit: "unknown",minDataValue: 2,maxDataValue: 7,// Define size of mag 2 quakes based on scale
    minSize: {type: "size",expression: "view.scale",stops: [{value: 1128,size: 12},{value: 36111,size: 12},{value: 9244649,size: 6},{value: 73957191,size: 4},{value: 591657528,size: 2}]},// Define size of mag 7 quakes based on scale
    maxSize: {type: "size",expression: "view.scale",stops: [{value: 1128,size: 80},{value: 36111,size: 60},{value: 9244649,size: 50},{value: 73957191,size: 50},{value: 591657528,size: 25}]}
}]
});

这个渲染器的效果如下所示

整体代码

  1 var arcgis_groupLayer;
  2
  3 function ArcGIS_Map_Init() {
  4     require([
  5         "esri/layers/GroupLayer",
  6         "esri/layers/FeatureLayer",
  7         "esri/Map",
  8         "esri/views/SceneView",
  9         "esri/widgets/LayerList",
 10         "esri/layers/support/Field",
 11         "esri/geometry/Point",
 12         "esri/renderers/SimpleRenderer",
 13         "esri/symbols/PointSymbol3D",
 14         "esri/symbols/ObjectSymbol3DLayer",
 15         "esri/request",
 16         "dojo/_base/array",
 17         "dojo/dom",
 18         "dojo/on",
 19         "dojo/domReady!"
 20     ], function (GroupLayer, FeatureLayer, Map, SceneView, LayerList, Field, Point, SimpleRenderer, PointSymbol3D, ObjectSymbol3DLayer, esriRequest,
 21     arrayUtils, dom, on) {
 22
 23         var arcgis_fields = [
 24             {name: "ObjectID", alias: "ObjectID", type: "oid"},
 25             {name: "title", alias: "title", type: "string"},
 26             {name: "num", alias: "num", type: "integer"}
 27         ];
 28
 29         arcgis_groupLayer = new GroupLayer({
 30             title: "消防数据",
 31             visibility: true,
 32             visibilityMode: "exclusive"
 33         })
 34
 35         var arcgis_arcgismap = new Map({
 36             basemap: "osm",
 37             layers: [arcgis_groupLayer]
 38         });
 39
 40         var arcgis_initCam = {
 41             position: {
 42                 x: 120.61,
 43                 y: 30.50,
 44                 z: 100000,
 45                 spatialReference: {
 46                     wkid: 4326
 47                 }
 48             },
 49             heading: 15,
 50             tilt: 60
 51         };
 52
 53         var arcgis_view = new SceneView({
 54             map: arcgis_arcgismap,
 55             container: "arcgismap",
 56             camera: arcgis_initCam
 57         });
 58
 59         arcgis_view.then(function () {
 60             arcgis_layerList = new LayerList({
 61                 view: arcgis_view
 62             })
 63
 64             arcgis_view.ui.add(arcgis_layerList, "top-right");
 65         })
 66
 67         $.getJSON("js/json/fire.json", function (data) {
 68             var graphics = [];
 69
 70             data.forEach(function(iSender, i) {
 71                 graphics.push({
 72                     geometry: new Point({
 73                         longitude: iSender.longitude,
 74                         latitude: iSender.latitude
 75                     }),
 76                     attributes: {
 77                         ObjectID: iSender.senderId,
 78                         title: iSender.senderName,
 79                         num: iSender.num
 80                     }
 81                 })
 82             }, this);
 83
 84             var arcgis_fireRenderer = new SimpleRenderer({
 85                 symbol: new PointSymbol3D({
 86                     symbolLayers: [new ObjectSymbol3DLayer({
 87                         resource: {
 88                             primitive: "cube"
 89                         },
 90                         width: 500,
 91                         depth: 500,
 92                         material: {color: "#e6b600"}
 93                     })]
 94                 }),
 95                 label: "火警数",
 96                 visualVariables: [{
 97                     type: "size",
 98                     field: "num",
 99                     axis: "height"
100                 },{
101                     type: "size",
102                     axis: "width-and-depth",
103                     useSymbolValue: true,
104                 }]
105             });
106
107             var arcgis_fireLayer = new FeatureLayer({
108                 source: graphics,
109                 fields: arcgis_fields,
110                 objectIdField: "ObjectID",
111                 renderer: arcgis_fireRenderer,
112                 spatialReference: {
113                     wkid: 4326
114                 },
115                 geometryType: "point",
116                 popupTemplate: {
117                     title: "{title}",
118                     content: [{
119                         type: "fields",
120                         fieldInfos: [{
121                             fieldName: "num",
122                             label: "火警数",
123                             visible: true
124                         }]
125                     }]
126                 },
127                 title: "火警数",
128                 id: "fireLayer"
129             })
130
131             arcgis_groupLayer.add(arcgis_fireLayer, 0);
132         })
133
134         $.getJSON("js/json/fault.json", function (data) {
135             var graphics = [];
136
137             data.forEach(function(iSender, i) {
138                 graphics.push({
139                     geometry: new Point({
140                         longitude: iSender.longitude,
141                         latitude: iSender.latitude
142                     }),
143                     attributes: {
144                         ObjectID: iSender.senderId,
145                         title: iSender.senderName,
146                         num: iSender.num
147                     }
148                 })
149             }, this);
150
151             var arcgis_faultRenderer = new SimpleRenderer({
152                 symbol: new PointSymbol3D({
153                     symbolLayers: [new ObjectSymbol3DLayer({
154                         resource: {
155                             primitive: "cube"
156                         },
157                         width: 500,
158                         depth: 500,
159                         material: {color: "#0098d9"}
160                     })]
161                 }),
162                 label: "故障数",
163                 visualVariables: [{
164                     type: "size",
165                     field: "num",
166                     axis: "height"
167                 },{
168                     type: "size",
169                     axis: "width-and-depth",
170                     useSymbolValue: true,
171                 }]
172             });
173
174             var arcgis_faultLayer = new FeatureLayer({
175                 source: graphics,
176                 fields: arcgis_fields,
177                 objectIdField: "ObjectID",
178                 renderer: arcgis_faultRenderer,
179                 spatialReference: {
180                     wkid: 4326
181                 },
182                 geometryType: "point",
183                 popupTemplate: {
184                     title: "{title}",
185                     content: [{
186                         type: "fields",
187                         fieldInfos: [{
188                             fieldName: "num",
189                             label: "故障数",
190                             visible: true
191                         }]
192                     }]
193                 },
194                 title: "故障数",
195                 id: "faultLayer",
196                 visible: false
197             })
198
199             arcgis_groupLayer.add(arcgis_faultLayer, 1);
200         })
201
202         $.getJSON("js/json/linkage.json", function (data) {
203             var graphics = [];
204
205             data.forEach(function(iSender, i) {
206                 graphics.push({
207                     geometry: new Point({
208                         longitude: iSender.longitude,
209                         latitude: iSender.latitude
210                     }),
211                     attributes: {
212                         ObjectID: iSender.senderId,
213                         title: iSender.senderName,
214                         num: iSender.num
215                     }
216                 })
217             }, this);
218
219             var arcgis_linkageRenderer = new SimpleRenderer({
220                 symbol: new PointSymbol3D({
221                     symbolLayers: [new ObjectSymbol3DLayer({
222                         resource: {
223                             primitive: "cube"
224                         },
225                         width: 500,
226                         depth: 500,
227                         material: {color: "#2b821d"}
228                     })]
229                 }),
230                 label: "联动数",
231                 visualVariables: [{
232                     type: "size",
233                     field: "num",
234                     axis: "height"
235                 },{
236                     type: "size",
237                     axis: "width-and-depth",
238                     useSymbolValue: true,
239                 }]
240             });
241
242             var arcgis_linkageLayer = new FeatureLayer({
243                 source: graphics,
244                 fields: arcgis_fields,
245                 objectIdField: "ObjectID",
246                 renderer: arcgis_linkageRenderer,
247                 spatialReference: {
248                     wkid: 4326
249                 },
250                 geometryType: "point",
251                 popupTemplate: {
252                     title: "{title}",
253                     content: [{
254                         type: "fields",
255                         fieldInfos: [{
256                             fieldName: "num",
257                             label: "联动数",
258                             visible: true
259                         }]
260                     }]
261                 },
262                 title: "联动数",
263                 id: "linkageLayer",
264                 visible: false
265             })
266
267             arcgis_groupLayer.add(arcgis_linkageLayer, 2);
268         })
269     })
270 }
271
272 spatial_echarts_instant.arcgismap = {
273     init: function () {
274         ArcGIS_Map_Init();
275     },
276     clear: function (params) {
277         arcgis_view = {};
278     },
279     resize: function (params) {
280
281     },
282     setOption: function (params) {
283         require([
284             "esri/views/SceneView"
285         ], function (SceneView) {
286             arcgis_view = new SceneView({
287                 map: arcgis_arcgismap,
288                 container: "arcgismap",
289                 camera: arcgis_initCam
290             });
291         })
292     },
293     changeLayer: function (layerIndex) {
294         var layerId = null;
295         switch (layerIndex) {
296             case 1:
297                 layerId = "fireLayer";
298                 break;
299             case 2:
300                 layerId = "faultLayer";
301                 break;
302             case 3:
303                 layerId = "linkageLayer";
304                 break;
305             default:
306                 break;
307         }
308         if (layerId) {
309             var layer = arcgis_groupLayer.findLayerById(layerId);
310             layer.visible = true;
311         }
312     }
313 }
314
315 $(function () {
316     ArcGIS_Map_Init();
317 })

转载于:https://www.cnblogs.com/MSspblxh/p/6273998.html

用ArcGIS API for JavaScript制作三维可视化图相关推荐

  1. ArcGIS API for JavaScript之基础篇(二)

    ArcGIS API for JavaScript之基础篇(二) 上一篇文章介绍了Map MapView SceneView的基本知识以及简单的demo.最近几天学习了WebMap WebScene ...

  2. ArcGIS API for JavaScript——地图展示

    ArcGIS API for JavaScript 能够实现的最基本功能就是地图展示,包括地图缩放.平移.定位.实时显示坐标.展示地图要素(指北针.比例尺.图例).切换地图等.本文将详细介绍地图展示的 ...

  3. 视频教程-主流前端框架下ArcGIS API for JavaScript的开发-其他

    主流前端框架下ArcGIS API for JavaScript的开发 毕业于中国矿业大学地理信息科学专业.现就任于全球领先的GIS公司,主要担任地理平台研发工作,日常工作任务是ArcGIS JS A ...

  4. ArcGIS API for JavaScript web前端应用

    ArcGIS API for JavaScript 文档查看地址: https://developers.arcgis.com/javascript/latest/ 现在分未3.x和4.x两种版本,对 ...

  5. 13 ArcGIS API for JavaScript开发入门文档

    写在前面 这篇文章写在我用ArcGIS API for JavaScript(后面统称为"ArcGIS JS API")开发了两年项目后的某一天夜里.写这篇文章主要是两个目的吧,第 ...

  6. arcgis api for JavaScript _跨域请求

    arcgis api for JavaScript  中出现跨域请求是常见问题, 通常出现类似如下错误消息类似: XMLHttpRequest cannot load http://10.32.2.7 ...

  7. 基于ArcGIS API for JavaScript加载天地图

    文章目录 前言 效果图 详细代码 总结 参考链接 前言 该篇主要介绍如何用ArcGIS JS API加载天地图,具体应用场景以及需求分析等,在上篇基于ArcGIS API for JavaScript ...

  8. 基于ArcGIS API for JavaScript加载百度各种类型切片地图

    文章目录 应用场景 需求分析 效果图 实现代码 原理解读 应用场景 部分项目基于ArcGIS平台,但是甲方只提供部分矢量数据,用作底图的地形图数据没有,表示可以使用百度地图作为底图.所以才会有使用Ar ...

  9. ArcGIS.Server.9.3和ArcGIS API for JavaScript实现Identify功能(六)

    目的: 1.ArcGIS.Server.9.3和ArcGIS API for JavaScript实现Identify功能,鼠标点击后获取被点击对象的然后以infoWindow的方式显示点击对象的属性 ...

最新文章

  1. 第七章 右左法则----复杂指针解析
  2. 机器学习知识点(二十八)Beta分布和Dirichlet分布理解
  3. java复制类mytool_MyTools
  4. 时序分析:Kalman滤波(状态空间)
  5. Swift - 数组排序方法(附样例)
  6. python列表添加字符串_2.python基础之—列表,元组,字典,集合,字符串的使用方法...
  7. 一文详解Serverless架构模式
  8. iPad开发(相对于iPhone开发时专有的API)
  9. 软件单元测试数据分析模板,单元测试报告模板
  10. 高清录播系统与流媒体服务器,来同品牌全高清录播系统方案
  11. 计算机术语 gc 是什么意思,GC是什么?为什么我们要去使用它
  12. URAL-1941 Scary Martian Word 队列维护
  13. 【codeforces round#800 B. Paranoid String】DP
  14. esp32-qcloud腾通连连编译指南
  15. 苹果免密支付怎么关闭_有人苹果手机被盗刷了!那是设置有问题...
  16. [组图教程]:8大方法!解决CPU资源占用100%[ZT]
  17. 微信小程序怎么样与mysql一起开发_莲米粒是一个基于PHP+MySQL+微信小程序技术栈...
  18. Karplus-Strong Algorithm 弦乐器模拟 吉他弦乐器发声原理 泛音 乐理概述
  19. 前端开发免费学习资源分享
  20. 从零开始建站(四) - 后端项目搭建

热门文章

  1. Springboot 分布式会话 io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication required
  2. Qlik Sense的8个提示和技巧
  3. JS学习笔记——前端的webview是什么东西
  4. Moviepy模块之视频添加字幕(一)
  5. Linux - Tcpdump工具
  6. linux 常用命令搜集 —— 筑梦之路
  7. 影像科dsa为什么必须买维修保险_浅谈DSA基本部件的维修技巧
  8. 【财富空间】达利欧:一切解读都不及自己用16页ppt彻底讲清
  9. 除了Visio还有哪个软件画流程图好用呢?
  10. 一文讲述,什么是pci总线原理?