1. ThingWorx扩展开发环境搭建

ThingWorx 平台自带大量开箱即用的构件(Thing、ThingTemplate、Mashup、Service 等),但当业务需要接入私有协议、封装专有算法、复用已有 Java 类库,或对平台行为做底层增强时,就必须走扩展(Extension)这条路。扩展本质上是一个遵循固定目录约定的 Java 工程,编译打包成 .zip 后由平台导入,其中的自定义服务、资源、配置项会被注册进运行时,像平台原生构件一样被调用。本章的目标很明确:把工具链装好、把工程骨架建对、把第一个自定义服务真正跑起来。

1.1 扩展开发的三件套

要开发 ThingWorx 扩展,需要三样东西:JDK、Extension SDK、IDE。三者版本必须匹配,否则最常见的报错就是编译期找不到 com.thingworx.* 包,或者打包后平台导入失败。

JDK 版本取决于目标平台版本。ThingWorx 8.x 系列通常使用 JDK 8,9.x 及以后逐步迁移到 JDK 11 或 17。判断方法很简单:登录平台后查看 System > Information 中的 Java 版本,或直接询问平台管理员。SDK 必须与平台版本严格对应,例如平台是 9.4,就应使用 9.4 对应的 Extension SDK,跨大版本混用极易出现 API 不兼容。

Extension SDK 可以从 PTC 支持站点下载,解压后得到的是一个包含 lib、samples、templates 等目录的文件夹。其中 lib 下的 thingworx-common.jar、thingworx-platform-common.jar 等是编译扩展时必须引用的核心依赖;samples 里则提供了官方示例工程,是理解目录结构最好的参考。

1.2 配置 Eclipse 或 IntelliJ IDEA

IDE 的选择不影响最终产物,只影响开发体验。Eclipse 与 SDK 的契合度更高,官方示例多为 Eclipse 工程;IntelliJ IDEA 在代码提示、重构和 Maven 集成上更顺手。下面以 IntelliJ IDEA 为例说明配置要点,Eclipse 的操作逻辑一致。

第一步,新建一个普通 Java 工程,不要选 Maven 或 Gradle 模板,因为 SDK 的构建脚本是自带的 Ant 脚本。第二步,在 Project Structure > Libraries 中把 SDK 的 lib 目录整体加入依赖,这样 ThingworxService、ThingworxBaseThing 等基类才能被识别。第三步,把 SDK 中的 build.xml、build-common.xml 等构建文件复制到工程根目录,并修改其中的 SDK 路径变量,使其指向本机实际解压位置。

第四步,配置编译输出。扩展工程通常约定源码放在 src,编译产物放在 bin,最终打包目录为 dist。在 IDEA 中把 Project Structure > Modules > Paths 的输出路径设为 bin,并确保 src 被标记为 Sources Root。第五步,验证环境:在工程中新建一个类,尝试继承 ThingworxBaseThing,如果 IDE 能正常解析且无红色报错,说明 SDK 依赖已生效。

1.3 扩展项目的目录结构

扩展工程的目录结构不是随意约定的,平台在导入时会按固定路径扫描元数据。一个最小可用的扩展工程结构如下:

HelloWorldExtension/
├── build.xml                 # Ant 构建脚本
├── build-common.xml          # SDK 公共构建逻辑
├── src/
│   └── com/example/hello/
│       └── HelloWorldThing.java
├── configfiles/
│   └── metadata.xml          # 扩展元数据:名称、版本、厂商
├── lib/                      # 第三方 jar(可选)
├── bin/                      # 编译输出
└── dist/                     # 打包输出 HelloWorldExtension.zip

其中 metadata.xml 是扩展的“身份证”,必须包含扩展名称、版本号、供应商、平台版本范围等信息。平台导入时会读取它,若版本范围与当前平台不匹配,导入会被拒绝。src 下按 Java 包名组织源码,包名建议使用反向域名,避免与平台类冲突。

1.4 创建第一个 Hello World 自定义服务

下面编写一个最简单的自定义服务:接收一个字符串参数 name,返回拼接后的问候语。在 src/com/example/hello/ 下新建 HelloWorldThing.java:

package com.example.hello;

import com.thingworx.types.InfoTable;
import com.thingworx.types.collections.ValueCollection;
import com.thingworx.types.primitives.StringPrimitive;
import com.thingworx.entities.utils.ThingUtilities;
import com.thingworx.metadata.annotations.ThingworxServiceDefinition;
import com.thingworx.metadata.annotations.ThingworxServiceParameter;
import com.thingworx.metadata.annotations.ThingworxServiceResult;
import com.thingworx.things.Thing;

public class HelloWorldThing extends Thing {

    @ThingworxServiceDefinition(
        name = "SayHello",
        description = "返回问候语",
        category = "Hello")
    @ThingworxServiceResult(
        name = "result",
        baseType = "STRING",
        description = "问候结果")
    public String SayHello(
        @ThingworxServiceParameter(
            name = "name",
            baseType = "STRING",
            description = "用户名") String name) throws Exception {

        if (name == null || name.trim().isEmpty()) {
            name = "ThingWorx";
        }
        return "Hello, " + name + "!";
    }
}

这段代码的关键在于三个注解:@ThingworxServiceDefinition 声明服务名与分类,@ThingworxServiceParameter 声明入参,@ThingworxServiceResult 声明返回值。平台在导入扩展时会扫描这些注解,自动在 Thing 上生成对应的服务定义,无需手工在 Composer 中配置。

1.5 打包与部署

在工程根目录执行 Ant 构建:

ant -f build.xml

构建成功后,dist 目录下会生成 HelloWorldExtension.zip。部署有两种方式:一是登录 Composer,进入 Import/Export > Import,选择该 zip 上传;二是把 zip 直接放入平台安装目录的 ThingworxStorage/extensions/ 下,然后重启平台。前者适合开发调试,后者适合批量部署。

导入成功后,在 Composer 中新建一个 Thing,将其 Base Thing Template 设为 GenericThing,然后在 Implement Shape 中勾选 HelloWorldThing。保存后进入该 Thing 的 Services 页签,就能看到 SayHello 服务。点击执行,在 name 参数填入 Engineer,返回结果应为 Hello, Engineer!。若返回为空或报错,优先检查扩展是否真正导入成功、Thing 是否实现了对应 Shape。

ThingWorx 扩展开发与部署链路 开发环境 JDK 8 / 11 / 17 Extension SDK Eclipse / IntelliJ IDEA Ant 构建脚本 扩展工程结构 src/ 源码 configfiles/metadata.xml lib/ 第三方依赖 dist/ 打包输出 HelloWorldThing @ThingworxServiceDefinition @ThingworxServiceParameter @ThingworxServiceResult SayHello(name) Ant 打包 HelloWorldExtension.zip 部署到平台 Import / extensions 目录 ThingWorx 平台运行时 Composer 中新建 Thing → Implement Shape: HelloWorldThing 执行 SayHello(name="Engineer") → 返回 "Hello, Engineer!" 结果验证 Services 页签可见 返回问候语正确

1.6 常见问题与排查

扩展开发初期最容易踩的坑集中在三处。第一,SDK 版本与平台版本不匹配,表现为导入时提示版本范围校验失败,解决方法是核对平台版本并更换对应 SDK。第二,注解缺失或拼写错误,表现为服务导入后在 Composer 中看不到,需检查 @ThingworxServiceDefinition 是否写在 public 方法上、参数注解是否完整。第三,打包时未包含 metadata.xml,表现为平台提示扩展元数据缺失,需确认 build.xml 的打包目标是否把 configfiles 目录纳入 zip。

建议在第一次成功部署后,立即把工程提交到版本库,并把 SDK 路径、JDK 版本、平台版本记录在 README 中。扩展开发对版本极其敏感,环境信息一旦丢失,后续排查成本会成倍增加。