ArcGis series-java release spatial table as feature service (feature)

1, Realize ideas

  1. Use java to call cmd command to execute python script
  2. The python environment uses \ArcGIS\Pro\bin\Python\envs\arcgispro-py3 in the arcgis pro installation directory
  3. Before publishing the database table, you need to use the sde file to create the database (creating the sde file does not need to connect to arcgis)
  4. When publishing a table, first add the database table as a layer in the local empty project template, and then upload and publish the project

2, Java implementation

2.1 Call entry

     /**
     * 创建数据库连接文件,传入数据库连接相关对象
     * 保存路径在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 Create an asynchronous task

It may take a long time to execute python. This is a general method that needs to monitor the script execution status

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 script

3.1 Create sde file

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 Release table

  • The release table is an empty project locally as a template (D:\ITS\map\MyProject2), add a database table, and generate a draft file to publish;
  • Empty project files can be obtained by using arcgis pro to create a project and delete all maps;
  • Adding a table layer is to distinguish vector table and raster table according to the actual type of spatial table;
  • Specifying the publishing directory is to ensure that the directory has been created in arcgis, and the publishing layer is overwritten and directly exposed.
# -*- 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, problems that may be encountered

If the version of arcgis pro is not compatible with the service version of arcgis, the python under pro will also report some strange errors. I use 3.0.1 pro and 10.6 arcgis; if you execute the python script package url problem, you can switch between https
and Try http, it is related to the version of arcgis;
when debugging, you can view the execution log in the manage of arcgis https://aaa.myarcgis.com:6443/arcgis/manager
insert image description here

Guess you like

Origin blog.csdn.net/u012796085/article/details/130942956
Recommended