7. Asset 服务
通过 client.asset() 访问。PlantPulse 资产模型的核心 —— 管理 Site > Area > Line > Equipment 的层级树。
ID 规则:必须使用
ASSET_前缀。类型代码A/L/M决定树的层级。详细内容参见 域 ID 规则。
7.1 方法一览
| 方法 | 返回类型 | HTTP | 端点 |
|---|---|---|---|
create(AssetRequestV5) | AssetResponseV5 或 null | POST | /api/v5/asset |
update(asset_id, AssetRequestV5) | AssetResponseV5 或 null | PUT | /api/v5/asset/{id} |
delete(asset_id) | boolean | DELETE | /api/v5/asset/{id} |
get(asset_id) | AssetResponseV5 或 null | GET | /api/v5/asset/{id} |
list() | List<AssetResponseV5> | GET | /api/v5/asset |
exists(asset_id) | boolean | GET | /api/v5/asset/{id}/exists |
Asset 服务专注于简化的 CRUD。树层级查询可使用 Path 服务 或客户端侧过滤(
list()后进行asset_type过滤)。
7.2 Asset Type 取值
| asset_type | 含义 |
|---|---|
A | Area(区域) |
L | Line(产线) |
M | Equipment(设备,Machine) |
7.3 AssetRequestV5 / AssetResponseV5
| 字段 | 类型 | 说明 |
|---|---|---|
asset_id | String | 资产 ID(PK,必须带 ASSET_) |
asset_name | String | 显示名称 |
parent_asset_id | String | 父资产 ID |
asset_order | String | 同级排序顺序 |
asset_type | String | A/L/M |
table_type | String | 设备分类(CNC、INJECTION 等) |
site_id | String | 所属站点 |
description | String | 说明 |
insert_date / update_date | String | (仅响应)时间 |
7.4 使用示例
创建 Area → Line → Equipment 树
import plantpulse.api.v5.dto.request.AssetRequestV5;
// 1) Area
AssetRequestV5 area = new AssetRequestV5();
area.setSite_id("SITE_DJ");
area.setParent_asset_id("SITE_DJ");
area.setAsset_id("ASSET_DJ_A_0001");
area.setAsset_name("조립구역");
area.setAsset_type("A");
client.asset().create(area);
// 2) Line
AssetRequestV5 line = new AssetRequestV5();
line.setSite_id("SITE_DJ");
line.setParent_asset_id("ASSET_DJ_A_0001");
line.setAsset_id("ASSET_DJ_L_0001");
line.setAsset_name("1번 조립 라인");
line.setAsset_type("L");
client.asset().create(line);
// 3) Equipment (CNC 머신)
AssetRequestV5 cnc = new AssetRequestV5();
cnc.setSite_id("SITE_DJ");
cnc.setParent_asset_id("ASSET_DJ_L_0001");
cnc.setAsset_id("ASSET_DJ_M_0001");
cnc.setAsset_name("CNC #1");
cnc.setAsset_type("M");
cnc.setTable_type("CNC");
cnc.setDescription("DMG MORI NLX-2500");
client.asset().create(cnc);
单条查询
import plantpulse.api.v5.dto.response.AssetResponseV5;
AssetResponseV5 cnc = client.asset().get("ASSET_DJ_M_0001");
if (cnc != null) {
System.out.println(cnc.getAsset_name() + " (" + cnc.getAsset_type() + ")");
System.out.println("부모: " + cnc.getParent_asset_id());
}
全部列表 + 按类型过滤
V5 没有 listByType 方法,因此在客户端侧进行过滤。
import java.util.List;
import java.util.stream.Collectors;
List<AssetResponseV5> all = client.asset().list();
// Equipment만
List<AssetResponseV5> equipments = all.stream()
.filter(a -> "M".equals(a.getAsset_type()))
.collect(Collectors.toList());
// 대전공장의 Line만
List<AssetResponseV5> djLines = all.stream()
.filter(a -> "SITE_DJ".equals(a.getSite_id()))
.filter(a -> "L".equals(a.getAsset_type()))
.collect(Collectors.toList());
树重建(客户端侧)
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
// asset_id 인덱스
Map<String, AssetResponseV5> byId = new HashMap<>();
for (AssetResponseV5 a : client.asset().list()) {
byId.put(a.getAsset_id(), a);
}
// 부모-자식 매핑
Map<String, List<AssetResponseV5>> children = new HashMap<>();
for (AssetResponseV5 a : byId.values()) {
children
.computeIfAbsent(a.getParent_asset_id(), k -> new ArrayList<>())
.add(a);
}
// 사이트(SITE_DJ) 산하 트리 출력
printTree(children, "SITE_DJ", 0);
static void printTree(Map<String, List<AssetResponseV5>> children, String id, int depth) {
List<AssetResponseV5> kids = children.getOrDefault(id, List.of());
for (AssetResponseV5 c : kids) {
System.out.println(" ".repeat(depth) + c.getAsset_id() + " — " + c.getAsset_name());
printTree(children, c.getAsset_id(), depth + 1);
}
}
修改资产
AssetRequestV5 update = new AssetRequestV5();
update.setSite_id("SITE_DJ");
update.setParent_asset_id("ASSET_DJ_L_0001");
update.setAsset_id("ASSET_DJ_M_0001");
update.setAsset_name("CNC #1 (보수 후)");
update.setAsset_type("M");
update.setTable_type("CNC");
update.setDescription("2026-05-10 베어링 교체 완료");
client.asset().update("ASSET_DJ_M_0001", update);
删除资产
⚠️ 删除资产前,必须先删除该资产上连接的所有 Tag 与下级 Asset。
boolean ok = client.asset().delete("ASSET_DJ_M_OLD");
7.5 应用场景
场景 —— 站点的 Equipment 列表及各自的 Tag 数量
String siteId = "SITE_DJ";
List<AssetResponseV5> equipments = client.asset().list().stream()
.filter(a -> siteId.equals(a.getSite_id()))
.filter(a -> "M".equals(a.getAsset_type()))
.collect(Collectors.toList());
for (AssetResponseV5 eq : equipments) {
long tagCount = client.tag().countByAsset(eq.getAsset_id());
System.out.printf("%s — Tag %d개%n", eq.getAsset_name(), tagCount);
}
场景 —— 采集 Line 级 OEE 仪表板数据
// 1) Line 목록
List<AssetResponseV5> lines = client.asset().list().stream()
.filter(a -> "L".equals(a.getAsset_type()))
.filter(a -> "SITE_DJ".equals(a.getSite_id()))
.collect(Collectors.toList());
// 2) 각 Line 산하 Equipment 조회 → 자산 경로 → 작업지시 → KPI 집계
for (AssetResponseV5 line : lines) {
List<AssetResponseV5> machines = client.asset().list().stream()
.filter(a -> line.getAsset_id().equals(a.getParent_asset_id()))
.collect(Collectors.toList());
for (AssetResponseV5 m : machines) {
long now = System.currentTimeMillis();
// 현재 작업지시는 Order 서비스로 조회
// ...
}
}