1, realizar ideas
- Use java para llamar al comando cmd para ejecutar el script de python
- El entorno de python usa \ArcGIS\Pro\bin\Python\envs\arcgispro-py3 en el directorio de instalación de arcgis pro
- Antes de publicar la tabla de la base de datos, debe usar el archivo sde para crear la base de datos (la creación del archivo sde no necesita conectarse a arcgis)
- Al publicar una tabla, primero agregue la tabla de la base de datos como una capa en la plantilla de proyecto local vacía y luego cargue y publique el proyecto.
2, implementación de Java
2.1 Entrada de llamada
/**
* 创建数据库连接文件,传入数据库连接相关对象
* 保存路径在python中设置
*
* @param userDbInfo
*/
public void createArcgisSde(ExternalDataBaseDO userDbInfo) {
List<Object> params = new ArrayList<>();
params.add("cmd.exe");
params.add("/c");
params.add("python");
//创建sde的python脚本路径
String pyScriptName = scriptLocation + File.separator + PY_CREATE_SDE;
params.add(pyScriptName);
params.add(userDbInfo.getHost());
params.add(userDbInfo.getPort());
params.add(userDbInfo.getDataBaseName());
params.add(userDbInfo.getUserName());
params.add(userDbInfo.getPassWord());
params.add(userDbInfo.getId());
String[] arr = params.toArray(new String[params.size()]);
int i = execSync(pyScriptName, arr);
if (i != 0) {
log.error("调用" + scriptLocation + PY_CREATE_SDE + "python异常!");
}
}
/**
* 调用python发布sqlserver数据库要素类到arcgis
* @param sde sde全路径 D:\\ITS\\itsPython\\192.168.10.153.sde
* @param host arcgis的url https://aaa.myarcgis.com/arcgis
* @param name arcgis用户名 aaa
* @param password arcgis密码 xxxx
* @param table 要发布的表名 SD
* @return
* @throws Exception
*/
public String publishTableToArcgis(String sde, String host, String name, String password, String table) throws Exception {
host = host.replace("https", "http");
host = host.replace(":6443", "");
sde = sde.replace("\\", "/");
List<Object> params = new ArrayList<>();
params.add("cmd.exe");
params.add("/c");
params.add("python");
String pyScriptName = scriptLocation + File.separator + PY_PUBLISH_TABLE;
params.add(pyScriptName);
params.add(sde);
params.add(host);
params.add(name);
params.add(password);
params.add(table);
String[] arr = params.toArray(new String[params.size()]);
log.info("发布空间表参数:{}", Arrays.toString(arr));
//publish_single_table("D:\\ITS\\itsPython\\192.168.10.153.sde", "https://lzw.gis107.com/arcgis", "lzwpro", "lzwpro123", "dbo.SD")
int i = execSync(pyScriptName, arr);
if (i == 0) {
//拼接发布地址 https://lzw.gis107.com/server/rest/services/SD/MapServer
return getPublishTableUrl(host, table);
} else {
log.error("发布表失败:{}", i);
return "error";
}
}
2.2 Crear una tarea asíncrona
Puede llevar mucho tiempo ejecutar python. Este es un método general que necesita monitorear el estado de ejecución del script.
private int execSync(String fileName, String params[]) throws IOException {
log.info("同步读取python文件 init fileName={}", fileName);
Process process;
if (OS.startsWith("Windows")) {
// windows执行脚本需要使用 cmd.exe /c 才能正确执行脚本
process = new ProcessBuilder(params).
start();
} else {
// linux执行脚本一般是使用python3 + 文件所在路径
// process = new ProcessBuilder("python3", LINUX_PATH + fileName, params).start();
process = new ProcessBuilder(params).start();
}
taskPool.submit(() -> {
log.info("读取python文件 开始 fileName={}", fileName);
BufferedReader errorReader = null;
// 脚本执行异常时的输出信息
errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
List<String> errorString = read(fileName, errorReader);
log.info("读取python文件 fileName={} errorString={}", fileName, errorString);
});
taskPool.submit(() -> {
// 脚本执行正常时的输出信息
BufferedReader inputReader = null;
inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
List<String> returnString = read(fileName, inputReader);
log.info("读取python文件 fileName={} returnString={}", fileName, returnString);
});
try {
boolean res = process.waitFor(1L, TimeUnit.DAYS);
if (res) {
int i = process.exitValue();
log.info("执行python文件 fileName={} == 结束 == {}", fileName, i);
return i;
}
return 1;
} catch (InterruptedException e) {
log.error("同步读取python文件 fileName=" + fileName + " 等待结果返回异常", e);
return 1;
}
}
3, secuencia de comandos de Python
3.1 Crear archivo sde
import arcpy, os
# 从用户输入获取连接参数
def create_sde(ip, port, dbname, username, password, dbId):
# 创建临时 SDE 连接文件
temp_sde = os.path.join(arcpy.env.scratchFolder, "temp.sde")
arcpy.Delete_management(temp_sde)
arcpy.CreateDatabaseConnection_management(os.path.dirname(temp_sde),
os.path.basename(temp_sde),
"SQL_SERVER", ip+","+port, "DATABASE_AUTH",
username, password, "SAVE_USERNAME",
dbname)
#arcpy.CreateDatabaseConnection_management("C:/temp", "myDatabase.sde", "SQL_SERVER", "myServer", "DATABASE_AUTH", "myUser", "myPassword", "#", "myDatabase", "#", "#", "#", "#", "#")
# 复制并重命名临时 SDE 连接文件到指定位置D:\ITS\map\sde
output_sde = "D:\\ITS\\map\\sde\\" + dbId + ".sde"
if os.path.isfile(output_sde):
os.remove(output_sde)
arcpy.Copy_management(temp_sde, output_sde)
# 删除临时 SDE 连接文件
arcpy.Delete_management(temp_sde)
if __name__ == '__main__':
a = []
for i in range(1, len(sys.argv)):
print("arg:" + sys.argv[i])
a.append(sys.argv[i])
create_sde(a[0], a[1], a[2], a[3], a[4], a[5])
#create_sde("192.168.10.153", "1433", "测试中文数据库", "sa", "admin888888", "测试sde文件名")
3.2 Tabla de liberación
- La tabla de lanzamiento es un proyecto vacío localmente como plantilla (D:\ITS\map\MyProject2), agrega una tabla de base de datos y genera un archivo borrador para publicar;
- Los archivos de proyecto vacíos se pueden obtener utilizando arcgis pro para crear un proyecto y eliminar todos los mapas;
- Agregar una capa de tabla es distinguir entre una tabla vectorial y una tabla ráster según el tipo real de tabla espacial;
- Especificar el directorio de publicación es para garantizar que el directorio se haya creado en arcgis y que la capa de publicación se sobrescriba y se exponga directamente.
# -*- coding: UTF-8 -*-
import arcpy
import sys
import os
import calendar
import time
import shutil
# 将标准输出和标准错误输出都重定向到同一个文件中
log_file = open("D:/ITS/pythonlog.txt", "w")
sys.stdout = log_file
sys.stderr = log_file
# 覆盖
arcpy.env.overwriteOutput = True
projectDir = r"D:\ITS\map"
templateProject = "MyProject2"
# 创建临时目录
targetProject = "project_" + str(calendar.timegm(time.gmtime()))
targetProjectPath = os.path.join(projectDir, targetProject)
aprxName = "MyProject2.aprx"
def publish_single_table(sde, host, name, password, table):
arcpy.env.workspace = sde
# 数据库表追加feature前缀,用来区分要素类型,后期单表会发布成map服务
service_name = "feature_" + table
shutil.copytree(os.path.join(projectDir, templateProject), targetProjectPath)
mpmath = os.path.join(targetProjectPath, aprxName)
aprx = arcpy.mp.ArcGISProject(mpmath) # aprx存储路径
aprx_map = aprx.listMaps("*")[0] # 要将数据添加到aprx中的哪个地图下
# 先从矢量表找目标表,找不到就去栅格表找
sde_list = arcpy.ListFeatureClasses()
print("遍历矢量图层!")
for item in sde_list:
# 不确定sde文件中每张表的格式,有可能是 库名.组织.表名,也可能是 组织.表名,只匹配最后表名
if item.split(".")[-1] == table:
print("添加图层:" + sde + "/" + item)
aprx_map.addDataFromPath(sde + "/" + item)
break
else:
print('矢量图层没找到 ' + table)
# 如果未找到目标则遍历栅格图层
sde_list=arcpy.ListRasters()
print("遍历栅格图层!")
for item in sde_list:
if item.split(".")[-1] == table:
aprx_map.addDataFromPath(sde + "/" + item)
break
else:
print('栅格图层未找到 ' + table)
raise Exception(table + " table is not find")
# lyrx = arcpy.mp.LayerFile("D:\\ITS\\map\\style\\县界.lyrx")
# listLayers = aprxMap.listLayers()
# for layer in listLayers:
# arcpy.ApplySymbologyFromLayer_management(layer, "D:\\ITS\\map\\style\\县界.lyrx")
aprx.save()
# Sign in to portal
a = arcpy.SignInToPortal(host, name, password)
# Set output file names
out_dir = os.path.join(targetProjectPath, "out")
os.makedirs(out_dir)
sd_draft_filename = service_name + ".sddraft"
sd_draft_output_filename = os.path.join(out_dir, sd_draft_filename)
sd_filename = service_name + ".sd"
sd_output_filename = os.path.join(out_dir, sd_filename)
# Reference map to publish
# aprx = arcpy.mp.ArcGISProject("D:\\ITS\\map\\MyProjectMyProject.aprx")
m = aprx.listMaps()[0]
# Create FeatureSharingDraft and set metadata, portal folder, and export data properties
server_type = "HOSTING_SERVER"
sd_draft = m.getWebLayerSharingDraft(server_type, "FEATURE", service_name)
hosts = host.split("/")
b = hosts[len(hosts) - 1]
print(b)
sd_draft.federatedServerUrl = host.replace(b, "server")
sd_draft.credits = "These are credits"
sd_draft.description = "This is description"
sd_draft.summary = "This is summary"
sd_draft.tags = "tag1, tag2"
sd_draft.useLimitations = "These are use limitations"
sd_draft.serverFolder = "gptest"
sd_draft.allowExporting = True
sd_draft.overwriteExistingService = True
# Create Service Definition Draft file
sd_draft.exportToSDDraft(sd_draft_output_filename)
# Stage Service
print("Start Staging")
arcpy.StageService_server(sd_draft_output_filename, sd_output_filename)
# Share to portal
print("Start Uploading")
arcpy.UploadServiceDefinition_server(sd_output_filename, sd_draft.federatedServerUrl, service_name, None, None, "gptest",None, True, None, True, None, None)
print("Finish Publishing")
# https://lzw.gis107.com/server/rest/services/ROAD/MapServer
if __name__ == '__main__':
a = []
for i in range(1, len(sys.argv)):
print("arg:" + sys.argv[i])
a.append(sys.argv[i])
#执行一些操作并输出信息或错误信息
publish_single_table(a[0], a[1], a[2], a[3], a[4])
#publish_single_table("D:\\ITS\\map\\sde\\192.168.10.153.sde", "http://lzw.server.com/arcgis", "lzwpro", "lzwpro123", "STBHHX")
#shutil.rmtree(targetProjectPath)
4, problemas que pueden surgir
Si la versión de arcgis pro no es compatible con la versión de servicio de arcgis, python bajo pro también informará algunos errores extraños. Uso 3.0.1 pro y 10.6 arcgis; si ejecuta el problema de URL del paquete de secuencias de comandos de python, puede cambiar entre https
y Try http, está relacionado con la versión de arcgis;
al depurar, puede ver el registro de ejecución en la administración de arcgis https://aaa.myarcgis.com:6443/arcgis/manager