1,前言
继上一篇 ArcGis系列-java调用GP分析 ,已经实现了gp工具的发布,调用,轮询,并已经分别保存好发布地图服务所需的矢量数据json,栅格数据tif文件和样式文件
要将gp分析的结果发布为图层供前端展示,基础的python环境还是跟发布空间表一样,
实现思路基本一样,同样是用本地的空项目构添加图层构建草稿文件上传发布
2,java代码
如果调用发布的python执行成功,先在ArcGIS Enterprise控制台的内容去看下发布地址,
再在getPublishLayerUrl方法中拼接正确的发布地址
/**
* 调用python发布图层到arcgis
* @param dir 图层及样式文件临时目录
* @param host
* @param name
* @param password
* @param serviceName 图层服务名称
* @return
* @throws Exception
*/
public String publishLayerToArcgis(String dir, String host, String name, String password, String serviceName) throws Exception {
//host = host.replace("https","http");
dir = dir.replace("\\","/");
List<Object> params = new ArrayList<>();
params.add("cmd.exe");
params.add("/c");
params.add("python");
//python全路径
String pyScriptName = scriptLocation + File.separator + PY_PUBLISH_LAYER;
params.add(pyScriptName);
params.add(dir);
params.add(host);
params.add(name);
params.add(password);
params.add(serviceName);
String[] arr = params.toArray(new String[params.size()]);
log.info("发布gp结果参数:{}", Arrays.toString(arr));
int i = execSync(pyScriptName, arr);
if (i == 0) {
return getPublishLayerUrl(host, serviceName);
} else {
throw new Exception("调用" + scriptLocation + PY_PUBLISH_LAYER + "python异常!");
}
}
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,python代码
在项目中分别遍历json文件,和tif文件,全部添加到新项目中,然后创建草稿;
因为是以gp分析id作为serverName,前端允许重复分析,所以发布时必须设置覆盖
# -*- coding: UTF-8 -*-
import arcpy
import os
import sys
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 = "layer_project_" + str(calendar.timegm(time.gmtime()))
targetProjectPath = os.path.join(projectDir, targetProject)
aprxName = "MyProject2.aprx"
gdbName = "MyProject2.gdb"
def publish_layers(temp_dir, host, name, password, service_name):
arcpy.env.workspace = targetProjectPath
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中的哪个地图下
json_dir = os.path.join(temp_dir, "json")
file_list = os.listdir(json_dir)
for file in file_list:
# 利用os.path.join()方法取得路径全名,并存入cur_path变量,否则每次只能遍历一层目录
json_file_path = os.path.join(json_dir, file)
feature_name = file.split(".")[0]
arcpy.conversion.JSONToFeatures(json_file_path, os.path.join(gdbName, feature_name))
aprx_map.addDataFromPath(os.path.join(targetProjectPath, gdbName, feature_name))
#aprx_map.addDataFromPath("D:\\ITS\\map\\layerparam\\dem1.tif")
json_dir = os.path.join(temp_dir, "tif")
for subdir, dirs, files in os.walk(json_dir):
for file in files:
tifpath = os.path.abspath(os.path.join(subdir, file))
if tifpath.endswith(".tif"): # 如果文件后缀是tif
aprx_map.addDataFromPath(tifpath)
else:
os.remove(tifpath) # 删除该文件
# 遍历图层添加样式
layers = aprx_map.listLayers()
for layer in layers:
layer_name = arcpy.Describe(layer).file + ".lyrx"
layer_name = layer_name.replace(".tif", "")
print(layer_name)
style_path = os.path.join(temp_dir, "style", layer_name)
if os.path.exists(style_path):
arcpy.ApplySymbologyFromLayer_management(layer, style_path)
aprx.save()
# Sign in to portal
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 = "FEDERATED_SERVER"
sd_draft = m.getWebLayerSharingDraft(server_type, "MAP_IMAGE", 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.overwriteExistingService=service_name
sd_draft.portalFolder = "gptest"
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)
arcpy.UploadServiceDefinition_server(sd_output_filename, sd_draft.federatedServerUrl, service_name, None, None, "gptest",None, True, None, True, None, None)
print("Finish Publishing")
if __name__ == '__main__':
a = []
for i in range(1, len(sys.argv)):
print("arg:" + sys.argv[i])
a.append(sys.argv[i])
publish_layers(a[0], a[1], a[2], a[3], a[4])
#publish_layers("D:/ITS/map/layerparam/44bgexhvc10000", "https://aaa.bbbb.com/arcgis", "name", "password","44bgexhvc10000")
# shutil.rmtree(a[0])
4,可能会遇到的问题
如果arcgis pro的版本与arcgis的服务版本不兼容,pro下的python也会报一些奇怪的错,我使用的3.0.1的pro和10.6的arcgis;
如果执行python脚本包url问题,可以切换https与http试下,与arcgis的版本有关;
调试时在arcgis的manage可以查看执行日志 https://aaa.myarcgis.com:6443/arcgis/manager