1. 概述

Web Feature Service(WFS)接口标准定义了一组接口,用于在Internet上访问要素和要素属性级别的地理信息。WFS提供了检索或查询矢量要素的方法,这种方法独立于它们发布的底层数据存储,WFS还可以更新或删除矢量要素。WFS的实例还能够存储查询,以便使客户机应用程序能够在稍后的时间点检索或执行查询

更多信息可参考:

中文版站点(翻译不完全准确):WFS-简介 — OGC e-Learning 2.0.0 文档 (osgeo.cn)

WFS服务器必须支持的操作:

  • GetCapabilities:返回一个文档,该文档描述由服务器提供的WFS服务提供的功能和资源

  • DescribeFeatureType:返回WFS实例提供或接受的功能类型和功能属性的结构描述

  • ListStoredQueries:返回存储在WFS实例中的查询列表

  • DescribeStoredQueries:返回存储在WFS实例中的查询的说明

  • GetFeature:从通过WFS发布的数据存储中返回要素实例的选择

WFS服务器通常也支持的操作:

  • GetPropertyValue:检索一组要素实例的要素特性值或复杂要素特性值的一部分
  • GetFeatureWithLock:提供与GetFeature请求类似的功能,但具有锁定特性的附加功能,可能是为了后续更新或更改
  • LockFeature:锁定一组要素实例,以便在锁定到位时,其他操作都不能修改数据
  • Transaction:允许插入、更新或删除要素实例及其属性
  • CreateStoredQuery:创建并存储一个查询,客户机可以在稍后的时间点快速地触发该查询
  • DropStoredQuery:从服务器中删除以前存储的查询

参考:WFS参考 — GeoServer 2.19.x User Manual (osgeo.cn)

GeoServer作为GIS服务器,支持WFS定义的一系列操作

WFS操作大部分支持KVP格式(URL里包含键值对的形式)和XML格式,少部分只支持XML格式(主要是更新与新增操作)

编写XML终究繁琐,OpenLayers支持OGC的WFS规范,可以基于WFS来对空间数据进行增、删、改、查(CRUD)

本文基于OpenLayers提供的WFS操作API,实现对GeoServer发布的空间数据进行增、删、改、查

本文大量参考了这篇文章:OpenLayers教程:网络要素服务(WFS) - 知乎 (zhihu.com)

2. 环境准备

GeoServer的下载与配置跨域可参考:

从官方下载的GeoServer带有示例数据,参考:

登录GeoServer,默认登录账户密码是:

  • 用户名: admin
  • 密码: geoserver

笔者这里使用的数据是 Tasmania roads:

另外,需要将此数据开启读写权限:

使用的OpenLayers版本是最新版6.15.1,CDN引入:

<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script>

3. 查询要素

这里的查询要素主要是指使用GetFeature操作,即获取要素

GetFeature操作可以使用KVP格式构造URL地址,参考官方自带示例:

可以通过构造URL来实现多种查询,构造的具体参数可以参考:

笔者这里查询Tasmania roads的所有要素并返回JSON格式:

http://localhost:8080/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:tasmania_roads&outputFormat=application/json

此外我们还可以使用GeoServer自带的图层预览来复制构造的URL:

直接在new ol.source.Vector中写入url参数,就可以利用WFS的KVP进行要素的查询,核心代码如下:

const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'http://localhost:8080/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:tasmania_roads&outputFormat=application/json',
format: new ol.format.GeoJSON()
})
});
map.addLayer(vectorLayer);

完整代码如下:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script>
<style>
html,
body {
height: 100%;
} body {
margin: 0;
padding: 0;
} #map {
height: 100%;
}
</style>
</head> <body>
<div id="map"></div>
<script>
const map = new ol.Map({
target: 'map',
layers: [],
view: new ol.View({
center: [147.01, -42.26],
zoom: 8,
projection: 'EPSG:4326'
})
});
map.addLayer(new ol.layer.WebGLTile({
source: new ol.source.OSM()
}));
const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'http://localhost:8080/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:tasmania_roads&outputFormat=application/json',
format: new ol.format.GeoJSON()
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#0000ff',
width: 2
})
})
});
map.addLayer(vectorLayer);
</script> </body> </html>

加载的地图如下:

4. 添加要素

更新、添加、删除要素操作都不支持KVP格式,所以只能使用XML文档的形式来请求

一个完整的XML字段解释如下图:

参考GeoServer自带的添加要素的示例:

编写XML字符过于繁琐,OpenLayers提供了编写WFS XML的API:

参考OpenLayers的API文档:OpenLayers v6.15.1 API - Class: WFS

核心代码如下:

// 服务配置,命名空间、图层、服务地址等
const geoserverData = {
workSpaceName: 'topp',
uri: 'http://www.openplans.org/topp',
wfsURL: 'http://localhost:8080/geoserver/topp/ows?',
layer: 'tasmania_roads'
} function addFeatureWFS(features) {
let WFS = new ol.format.WFS();
// 生成XML格式的WFS请求信息
let transact_xml = WFS.writeTransaction(
features, null, null,
{
srcName: 'EPSG:4326',
featureNS: geoserverData.uri,
featurePrefix: geoserverData.workSpaceName,
featureType: [geoserverData.layer],
}
);
// 将XML格式请求信息序列化为字符串格式
transact_str = (new XMLSerializer()).serializeToString(transact_xml);
// 使用Fetch将请求发送到后端
fetch('http://localhost:8080/geoserver/wfs', {
method: 'POST',
body: transact_str,
headers: {
'Content-Type': 'text/xml'
}
}).then(res => res.text()).then(res => {
console.log(res);
});
}

完整代码如下:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script>
<style>
html,
body {
height: 100%;
} body {
margin: 0;
padding: 0;
} #map {
height: 100%;
}
</style>
</head> <body>
<button id="draw">绘制</button>
<button id="add">添加</button>
<button id="exit">退出</button>
<div id="map"></div>
<script>
const map = new ol.Map({
target: 'map',
layers: [],
view: new ol.View({
center: [147.01, -42.26],
zoom: 8,
projection: 'EPSG:4326'
})
});
map.addLayer(new ol.layer.WebGLTile({
source: new ol.source.OSM()
}));
const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'http://localhost:8080/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:tasmania_roads&outputFormat=application/json',
format: new ol.format.GeoJSON()
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#0000ff',
width: 2
})
})
});
map.addLayer(vectorLayer); // 绘制控件
let drawedFeatures = [];
let draw = new ol.interaction.Draw({
source: vectorLayer.getSource(),
type: 'MultiLineString',
geometryName: 'the_geom' // 注意:这里图形信息字段一定要和后端服务器一致
});
draw.on('drawend', (event) => {
let feature = event.feature;
// 为要素添加属性,我这里随便设置属性
feature.set('TYPE', 'highway');
drawedFeatures.push(event.feature);
});
map.addInteraction(draw);
draw.setActive(false); document.querySelector('#add').addEventListener('click', (event) => {
// 将绘制的要素添加到后台
addFeatureWFS(drawedFeatures);
});
document.querySelector('#draw').addEventListener('click', (event) => {
// 绘制要添加的要素
draw.setActive(true);
});
document.querySelector('#exit').addEventListener('click', (event) => {
// 退出绘制
draw.setActive(false);
}); // 服务配置,命名空间、图层、服务地址等
const geoserverData = {
workSpaceName: 'topp',
uri: 'http://www.openplans.org/topp',
wfsURL: 'http://localhost:8080/geoserver/topp/ows?',
layer: 'tasmania_roads'
} function addFeatureWFS(features) {
let WFS = new ol.format.WFS();
// 生成XML格式的WFS请求信息
let transact_xml = WFS.writeTransaction(
features, null, null,
{
srcName: 'EPSG:4326',
featureNS: geoserverData.uri,
featurePrefix: geoserverData.workSpaceName,
featureType: [geoserverData.layer],
}
);
// 将XML格式请求信息序列化为字符串格式
transact_str = (new XMLSerializer()).serializeToString(transact_xml);
// 使用Fetch将请求发送到后端
fetch('http://localhost:8080/geoserver/wfs', {
method: 'POST',
body: transact_str,
headers: {
'Content-Type': 'text/xml'
}
}).then(res => res.text()).then(res => {
let transactRes = WFS.readTransactionResponse(res);
let str = transactRes.transactionSummary.totalInserted +
" totalInserted!, insertIds: " + transactRes.insertIds + "\n";
str += transactRes.transactionSummary.totalUpdated + " totalUpdated!\n";
str += transactRes.transactionSummary.totalDeleted + " totalDeleted!";
alert(str);
});
}
</script> </body> </html>

注意:

  • geometryName要和后端GIS服务器的数据保持一致,它将会被写为XML标签,可以从GetFeature结果查询,参考下图
  • WFS.writeTransaction中的featureType参数是图层名字,它将会被写为XML标签,参考下图

增加要素后的结果:

5. 更新要素

使用OpenLayers,更新要素的流程:

  • 加载初始要素
  • 创建选择控件选择要素
  • 创建修改控件修改要素
  • 将修改后的要素和信息写为XML
  • 序列化XML
  • 提交XML到服务器

核心代码如下:

// 服务配置,命名空间、图层、服务地址等
const geoserverData = {
workSpaceName: 'topp',
uri: 'http://www.openplans.org/topp',
wfsURL: 'http://localhost:8080/geoserver/topp/ows?',
layer: 'tasmania_roads'
} // 选择要素控件
let select = new ol.interaction.Select({
layers: [vectorLayer],
hitTolerance: 10
});
map.addInteraction(select); // 修改要素控件
let modify = new ol.interaction.Modify({
features: select.getFeatures()
});
// 保存修改完成的要素
let modifiedFeatures = null; // 用于保存被修改的要素
modify.on('modifyend', (event) => {
modifiedFeatures = event.features;
});
map.addInteraction(modify); document.querySelector('#modify').addEventListener('click', (event) => {
let features = [];
modifiedFeatures.forEach(function (item, index, array) {
features.push(item);
});
updateWFS(features);
}); function updateWFS(features) {
let WFS = new ol.format.WFS();
// 生成XML格式的WFS请求信息
let transact_xml = WFS.writeTransaction(
null, features, null,
{
srcName: 'EPSG:4326',
featureNS: geoserverData.uri,
featurePrefix: geoserverData.workSpaceName,
featureType: [geoserverData.layer],
}
)
// 将XML格式请求信息序列化为字符串格式
transact_str = (new XMLSerializer()).serializeToString(transact_xml);
// 使用Fetch将请求发送到后端
fetch('http://localhost:8080/geoserver/wfs', {
method: 'POST',
body: transact_str,
headers: {
'Content-Type': 'text/xml'
}
}).then(res => res.text()).then(res => {
console.log(res);
});
}

完整代码如下:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script>
<style>
html,
body {
height: 100%;
} body {
margin: 0;
padding: 0;
} #map {
height: 100%;
}
</style>
</head> <body>
<button id="select">选择</button>
<button id="modify">提交</button>
<button id="exit">退出</button>
<div id="map"></div>
<script>
const map = new ol.Map({
target: 'map',
layers: [],
view: new ol.View({
center: [147.01, -42.26],
zoom: 8,
projection: 'EPSG:4326'
})
});
map.addLayer(new ol.layer.WebGLTile({
source: new ol.source.OSM()
}));
const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'http://localhost:8080/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:tasmania_roads&outputFormat=application/json',
format: new ol.format.GeoJSON({
geometryName: 'the_geom'
})
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#0000ff',
width: 2
})
})
});
map.addLayer(vectorLayer); document.querySelector('#select').addEventListener('click', (event) => {
select.setActive(true);
});
document.querySelector('#exit').addEventListener('click', (event) => {
select.setActive(false);
}); // 服务配置,命名空间、图层、服务地址等
const geoserverData = {
workSpaceName: 'topp',
uri: 'http://www.openplans.org/topp',
wfsURL: 'http://localhost:8080/geoserver/topp/ows?',
layer: 'tasmania_roads'
} // 选择要素控件
let select = new ol.interaction.Select({
layers: [vectorLayer],
hitTolerance: 10
});
map.addInteraction(select);
select.setActive(false); // 修改要素控件
let modify = new ol.interaction.Modify({
features: select.getFeatures()
});
// 保存修改完成的要素
let modifiedFeatures = null; // 用于保存被修改的要素
modify.on('modifyend', (event) => {
modifiedFeatures = event.features;
});
map.addInteraction(modify); document.querySelector('#modify').addEventListener('click', (event) => {
let features = [];
modifiedFeatures.forEach(function (item, index, array) {
features.push(item);
});
updateWFS(features);
}); function updateWFS(features) {
let WFS = new ol.format.WFS();
// 生成XML格式的WFS请求信息
let transact_xml = WFS.writeTransaction(
null, features, null,
{
srcName: 'EPSG:4326',
featureNS: geoserverData.uri,
featurePrefix: geoserverData.workSpaceName,
featureType: [geoserverData.layer],
}
)
// 将XML格式请求信息序列化为字符串格式
transact_str = (new XMLSerializer()).serializeToString(transact_xml);
// 使用Fetch将请求发送到后端
fetch('http://localhost:8080/geoserver/wfs', {
method: 'POST',
body: transact_str,
headers: {
'Content-Type': 'text/xml'
}
}).then(res => res.text()).then(res => {
let transactRes = WFS.readTransactionResponse(res);
let str = transactRes.transactionSummary.totalInserted +
" totalInserted!, insertIds: " + transactRes.insertIds + "\n";
str += transactRes.transactionSummary.totalUpdated + " totalUpdated!\n";
str += transactRes.transactionSummary.totalDeleted + " totalDeleted!";
alert(str);
});
}
</script> </body> </html>

注意:

  • 此处加载WFS时需要指定geometryName
  • OpenLayers控件的使用可以参考官方API,Modify控件在Select控件选择后跟随圆点拖拽就行

修改后的结果如下:

6. 删除要素

使用OpenLayers,删除要素的流程:

  • 加载初始要素
  • 创建选择控件选择要素
  • 将选择的要素和信息写为XML
  • 序列化XML
  • 提交XML到服务器

核心代码如下:

// 服务配置,命名空间、图层、服务地址等
const geoserverData = {
workSpaceName: 'topp',
uri: 'http://www.openplans.org/topp',
wfsURL: 'http://localhost:8080/geoserver/topp/ows?',
layer: 'tasmania_roads'
} // 选择要素控件
let select = new ol.interaction.Select({
layers: [vectorLayer],
hitTolerance: 10
});
map.addInteraction(select); document.querySelector('#delete').addEventListener('click', (event) => {
let features = [];
select.getFeatures().forEach(function (item, index, array) {
features.push(item);
});
deleteWFS(features);
}) function deleteWFS(features) {
let WFS = new ol.format.WFS();
// 生成XML格式的WFS请求信息
let transact_xml = WFS.writeTransaction(
null, null, features,
{
srcName: 'EPSG:4326',
featureNS: geoserverData.uri,
featurePrefix: geoserverData.workSpaceName,
featureType: [geoserverData.layer],
}
)
// 将XML格式请求信息序列化为字符串格式
transact_str = (new XMLSerializer()).serializeToString(transact_xml);
// 使用Fetch将请求发送到后端
fetch('http://localhost:8080/geoserver/wfs', {
method: 'POST',
body: transact_str,
headers: {
'Content-Type': 'text/xml'
}
}).then(res => res.text()).then(res => {
console.log(res);
});
}

完整代码如下:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script>
<style>
html,
body {
height: 100%;
} body {
margin: 0;
padding: 0;
} #map {
height: 100%;
}
</style>
</head> <body>
<button id="select">选择</button>
<button id="delete">删除</button>
<button id="exit">退出</button>
<div id="map"></div>
<script>
const map = new ol.Map({
target: 'map',
layers: [],
view: new ol.View({
center: [147.01, -42.26],
zoom: 8,
projection: 'EPSG:4326'
})
});
map.addLayer(new ol.layer.WebGLTile({
source: new ol.source.OSM()
}));
const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'http://localhost:8080/geoserver/topp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=topp:tasmania_roads&outputFormat=application/json',
format: new ol.format.GeoJSON({
geometryName: 'the_geom'
})
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#0000ff',
width: 2
})
})
});
map.addLayer(vectorLayer); document.querySelector('#select').addEventListener('click', (event) => {
select.setActive(true);
});
document.querySelector('#exit').addEventListener('click', (event) => {
select.setActive(false);
}); // 服务配置,命名空间、图层、服务地址等
const geoserverData = {
workSpaceName: 'topp',
uri: 'http://www.openplans.org/topp',
wfsURL: 'http://localhost:8080/geoserver/topp/ows?',
layer: 'tasmania_roads'
} // 选择要素控件
let select = new ol.interaction.Select({
layers: [vectorLayer],
hitTolerance: 10
});
map.addInteraction(select);
select.setActive(false); document.querySelector('#delete').addEventListener('click', (event) => {
let features = [];
select.getFeatures().forEach(function (item, index, array) {
features.push(item);
});
deleteWFS(features);
}) function deleteWFS(features) {
let WFS = new ol.format.WFS();
// 生成XML格式的WFS请求信息
let transact_xml = WFS.writeTransaction(
null, null, features,
{
srcName: 'EPSG:4326',
featureNS: geoserverData.uri,
featurePrefix: geoserverData.workSpaceName,
featureType: [geoserverData.layer],
}
)
// 将XML格式请求信息序列化为字符串格式
transact_str = (new XMLSerializer()).serializeToString(transact_xml);
// 使用Fetch将请求发送到后端
fetch('http://localhost:8080/geoserver/wfs', {
method: 'POST',
body: transact_str,
headers: {
'Content-Type': 'text/xml'
}
}).then(res => res.text()).then(res => {
let transactRes = WFS.readTransactionResponse(res);
let str = transactRes.transactionSummary.totalInserted +
" totalInserted!, insertIds: " + transactRes.insertIds + "\n";
str += transactRes.transactionSummary.totalUpdated + " totalUpdated!\n";
str += transactRes.transactionSummary.totalDeleted + " totalDeleted!";
alert(str);
});
} </script> </body> </html>

删除后的结果如下:

7. 参考资料

[1]WFS - Introduction — OGC e-Learning 2.0.0 documentation (opengeospatial.github.io)

[2]WFS-简介 — OGC e-Learning 2.0.0 文档 (osgeo.cn)

[3]WFS参考 — GeoServer 2.19.x User Manual (osgeo.cn)

[4]使用.net c# 对GeoServer要素进行Insert和Delete操作_我是小怪兽-的博客-CSDN博客_c# geoserver

[5]开源GIS(十五)——openlayers通过geoserver中WFS删除要素_gis_morningsun的博客-CSDN博客

[6]OGC的网络要素服务(WFS)(持续更新。。。) - 知乎 (zhihu.com)

[7]OpenLayers v6.15.1 API - Class: WFS

[8]geoserver跨域 - 知乎 (zhihu.com)

基于OpenLayers使用WFS实现GeoServer地图要素的增删改查的更多相关文章

  1. Mybatis框架基于注解的方式,实对数据现增删改查

    编写Mybatis代码,与spring不一样,不需要导入插件,只需导入架包即可: 在lib下 导入mybatis架包:mybatis-3.1.1.jarmysql驱动架包:mysql-connecto ...

  2. Mybatis框架基于映射文件和配置文件的方式,实现增删改查,可以打印日志信息

    首先在lib下导入: 与打印日志信息有关的架包 log4j-1.2.16.jar mybatis架包:mybatis-3.1.1.jar 连接数据库的架包:mysql-connector-java-5 ...

  3. arcgis 要素服务增删改查

    两种方式: 第一种 要素服务的增删改操作,在ArcGIS API for JS中给我们提供了三个类用于要素的增Add,删Delete,改Update 添加draw和要素服务 //用于操作的要素图层,注 ...

  4. Node.js、express、mongodb 入门(基于easyui datagrid增删改查)

    前言 从在本机(win8.1)环境安装相关环境到做完这个demo大概不到两周时间,刚开始只是在本机安装环境并没有敲个Demo,从周末开始断断续续的想写一个,按照惯性思维就写一个增删改查吧,一方面是体验 ...

  5. iOS sqlite 增删改查 简单封装(基于 FMDB)

    /** *  对 sqlite 的使用进行简单封装,仅涉及简单的单表 增删改查 * *  基于 FMDB * *  操作基于 model ,数据库表字段与 model 属性一一对应,对 model 整 ...

  6. 基于SSM之Mybatis接口实现增删改查(CRUD)功能

    国庆已过,要安心的学习了. SSM框架以前做过基本的了解,相比于ssh它更为优秀. 现基于JAVA应用程序用Mybatis接口简单的实现CRUD功能: 基本结构: (PS:其实这个就是用的Mapper ...

  7. 基于SpringBoot开发一个Restful服务,实现增删改查功能

    前言 在去年的时候,在各种渠道中略微的了解了SpringBoot,在开发web项目的时候是如何的方便.快捷.但是当时并没有认真的去学习下,毕竟感觉自己在Struts和SpringMVC都用得不太熟练. ...

  8. Mybatis_3.基于注解的增删改查

    1.实体类User.java public class User { private int id; private String name; private int age; //getter.se ...

  9. Mybatis_2.基于XML的增删改查

    1.实体类User.java public class User { private int id; private String name; private int age; //getter.se ...

  10. 基于SpringMVC的文件(增删改查)上传、下载、更新、删除

    一.项目背景 摘要:最近一直在忙着项目的事,3个项目过去了,发现有一个共同的业务,那就是附件的处理,附件包括各种文档,当然还有图片等特殊文件,由于时间的关系,每次都是匆匆忙忙的搞定上线,称这项目的空档 ...

随机推荐

  1. SVNAdmin2 - 基于web的SVN管理系统

    1. 介绍 SVNAdmin2 是一款通过图形界面管理服务端SVN的web程序. 正常情况下配置SVN仓库的人员权限需要登录到服务器手动修改 authz 和 passwd 两个文件,当仓库结构和人员权 ...

  2. pickle兼容问题

    1 import pickle 2 3 with open('a.pkl',mode='wb') as f: 4 # 一:在python3中执行的序列化操作如何兼容python2 5 # python ...

  3. 2、Navicat安装提示报错

    问题描述:激活navicat15的注册码时报出"rsa public key not find"错误原因:没有生成破解版的RegPrivateKey.pem文件解决方案:重新安装N ...

  4. 结合商业项目深入理解Go知识点

    这篇文章比较硬核,爆肝5千字,把之前整理的知识点都串起来了.建议先收藏,慢慢看. 前言 上一篇文章 #[Go WEB进阶实战]开源的电商前后台API系统 很受大家欢迎,有好多小伙伴私信我问题:&quo ...

  5. netcore下死RabbitMQ队列、死信队列、延时队列及小应用

    关于安装rabbitmq这里一笔掠过了. 下面进入正题: 1.新建aspnetcorewebapi空项目,NormalQueue,删除controllers文件夹已经无关的文件,这里为了偷懒不用con ...

  6. Java学习笔记:2022年1月6日(补充)

    Java学习笔记:2022年1月6日(补充) ​ 摘要:这篇笔记主要记录了2022年1月6日下午的笔记,主要内容为Java语言中的基础操作,以及基础知识点,了解这些后基本上就可以使用Java写算法了. ...

  7. (10)go-micro微服务发送邮件

    目录 一 获取QQ邮箱Pass 二 安装gomail 三 初始化发送邮件 四 发送注册邮件 五 发送重置密码邮件 六 最后 一 获取QQ邮箱Pass 1.登录QQ邮箱 2.点击设置,点击账户,下拉找到 ...

  8. 真正“搞”懂HTTP协议09之这个饼干不能吃

    我们在之前的文章中介绍HTTP特性的时候聊过,HTTP是无状态的,每次聊起HTTP特性的时候,我都会回忆一下从前辉煌的日子,也就是互联网变革的初期,那时候其实HTTP不需要有状态,就是个浏览页面,没有 ...

  9. Python爬取cnnvd

    利用python监控CNNVD上面的新出漏洞实例,可以配合邮箱推送获取最新的漏洞情报 爬取cnnvd import requests from bs4 import BeautifulSoup imp ...

  10. 玩转web3第一篇——web3-react

    概况 web3-react是由Noah Zinsmeister开发的一个web3框架,主要功能是实时获取DApp里的关键数据(如用户当前连接的地址.网络.余额等). Noah也是著名的去中心化交易所u ...