From 4bafdf81dac78da99783dfcfbf34f634c0d1a949 Mon Sep 17 00:00:00 2001
From: wanxiaoli
Date: Fri, 7 Aug 2026 09:56:04 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81=E6=B3=A8?=
=?UTF-8?q?=E9=87=8A=EF=BC=8C=E5=8E=BB=E6=8E=89=E5=8F=AF=E8=83=BD=E6=9C=89?=
=?UTF-8?q?=E5=AE=89=E5=85=A8=E9=97=AE=E9=A2=98=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../yfd/business/css/build/package-info.java | 22 ++
.../css/common/exception/package-info.java | 21 ++
.../yfd/business/css/config/package-info.java | 21 ++
.../css/controller/AlgorithmController.java | 99 +++++-
.../controller/AlgorithmModelController.java | 321 ++++++------------
.../controller/CriticalDataController.java | 34 ++
.../css/controller/DeviceMetaController.java | 21 ++
.../css/controller/EventController.java | 43 +++
.../css/controller/HealthController.java | 11 +
.../css/controller/MaterialController.java | 54 +++
.../css/controller/ModelTrainController.java | 85 +++++
.../css/controller/ProjectController.java | 36 ++
.../css/controller/ScenarioController.java | 31 ++
.../controller/ScenarioResultController.java | 21 ++
.../business/css/controller/package-info.java | 29 ++
.../yfd/business/css/domain/package-info.java | 20 ++
.../yfd/business/css/dto/package-info.java | 20 ++
.../business/css/facade/SimDataFacade.java | 32 +-
.../yfd/business/css/facade/package-info.java | 19 ++
.../yfd/business/css/mapper/package-info.java | 20 ++
.../yfd/business/css/meta/package-info.java | 19 ++
.../yfd/business/css/model/package-info.java | 26 ++
.../com/yfd/business/css/package-info.java | 54 +++
.../business/css/security/package-info.java | 20 ++
.../css/service/AlgorithmModelService.java | 13 +
.../css/service/AlgorithmService.java | 8 +-
.../css/service/CriticalDataService.java | 39 +++
.../css/service/DeviceInferService.java | 32 ++
.../business/css/service/DeviceService.java | 48 +++
.../business/css/service/EventService.java | 6 +
.../business/css/service/MaterialService.java | 25 ++
.../css/service/ModelTrainService.java | 23 ++
.../business/css/service/ProjectService.java | 6 +
.../css/service/ScenarioResultService.java | 6 +
.../business/css/service/ScenarioService.java | 13 +-
.../css/service/SimulationService.java | 14 +-
.../css/service/TrainWebSocketService.java | 10 +
.../impl/AlgorithmModelServiceImpl.java | 15 +
.../service/impl/AlgorithmServiceImpl.java | 14 +
.../service/impl/CriticalDataServiceImpl.java | 23 ++
.../css/service/impl/DeviceServiceImpl.java | 25 ++
.../css/service/impl/EventServiceImpl.java | 6 +
.../css/service/impl/MaterialServiceImpl.java | 21 ++
.../service/impl/ModelTrainServiceImpl.java | 87 ++++-
.../css/service/impl/ProjectServiceImpl.java | 82 ++++-
.../impl/ScenarioResultServiceImpl.java | 6 +
.../css/service/impl/ScenarioServiceImpl.java | 6 +
.../service/impl/SimulationServiceImpl.java | 14 +-
.../css/service/impl/package-info.java | 29 ++
.../business/css/service/package-info.java | 27 ++
.../yfd/business/css/utils/package-info.java | 20 ++
.../system/controller/LoginController.java | 14 -
.../com/yfd/platform/utils/EncryptUtils.java | 100 ------
.../java/com/yfd/platform/utils/FileUtil.java | 60 ----
.../java/com/yfd/platform/utils/RsaUtils.java | 94 -----
55 files changed, 1465 insertions(+), 500 deletions(-)
create mode 100644 business-css/src/main/java/com/yfd/business/css/build/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/common/exception/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/config/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/controller/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/domain/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/dto/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/facade/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/mapper/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/meta/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/model/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/security/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/service/impl/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/service/package-info.java
create mode 100644 business-css/src/main/java/com/yfd/business/css/utils/package-info.java
delete mode 100644 framework/src/main/java/com/yfd/platform/utils/EncryptUtils.java
diff --git a/business-css/src/main/java/com/yfd/business/css/build/package-info.java b/business-css/src/main/java/com/yfd/business/css/build/package-info.java
new file mode 100644
index 0000000..98522d4
--- /dev/null
+++ b/business-css/src/main/java/com/yfd/business/css/build/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * 仿真数据构建(Build)相关能力。
+ *
+ * 该包用于将“项目拓扑/设备配置/事件/材料/关键参数”等多源输入组织成推演/计算可消费的结构化数据,
+ * 侧重于流程编排与数据组装,而非对外协议处理。
+ *
+ *
+ * - 输入:项目ID、场景配置、拓扑结构、设备与材料数据等。
+ * - 输出:推演上下文、推演请求体、结构化数据包等。
+ * - 约束:构建过程应保持确定性,避免引入与时间相关的隐式状态。
+ * - 健壮性:对缺失字段、非法引用、拓扑不一致等情况给出可定位错误。
+ *
+ *
+ * 设计原则:
+ *
+ *
+ * - 分阶段构建:先解析与归一化,再校验与补全,最后生成输出。
+ * - 只读输入:避免在构建阶段修改持久化实体对象,减少副作用。
+ * - 可测试:关键构建步骤保持可单元测试(输入→输出可预测)。
+ *
+ */
+package com.yfd.business.css.build;
diff --git a/business-css/src/main/java/com/yfd/business/css/common/exception/package-info.java b/business-css/src/main/java/com/yfd/business/css/common/exception/package-info.java
new file mode 100644
index 0000000..34c0949
--- /dev/null
+++ b/business-css/src/main/java/com/yfd/business/css/common/exception/package-info.java
@@ -0,0 +1,21 @@
+/**
+ * 业务异常定义。
+ *
+ * 用于表达业务处理过程中的可预期错误,区分于系统异常(NPE、网络故障、数据库不可用等)。
+ * 业务异常应具备明确语义,便于前端提示与测试用例覆盖。
+ *
+ *
+ * - 参数类错误:入参缺失、格式非法、越界、引用不存在等。
+ * - 状态类错误:对象状态不允许当前操作(例如任务状态机不允许跳转)。
+ * - 推演类错误:场景推演前置条件不满足、数据不一致、外部推演服务拒绝等。
+ * - 权限类错误:项目不可访问、资源无权限读写等(如需与安全框架集成)。
+ *
+ *
+ * 约定:
+ *
+ *
+ * - 异常消息:面向用户/测试可读,避免泄露敏感信息。
+ * - 异常类型:按场景区分类型,避免一个异常承担全部语义。
+ *
+ */
+package com.yfd.business.css.common.exception;
diff --git a/business-css/src/main/java/com/yfd/business/css/config/package-info.java b/business-css/src/main/java/com/yfd/business/css/config/package-info.java
new file mode 100644
index 0000000..b40cea0
--- /dev/null
+++ b/business-css/src/main/java/com/yfd/business/css/config/package-info.java
@@ -0,0 +1,21 @@
+/**
+ * Spring Boot 配置。
+ *
+ * 该包集中放置与运行时装配相关的配置类,例如:
+ *
+ *
+ * - MyBatis/MyBatis-Plus 配置:分页、类型处理器、拦截器等。
+ * - OpenAPI/Swagger 配置:接口文档分组、鉴权头部描述等。
+ * - RestTemplate/WebClient 配置:超时、拦截器、序列化策略等。
+ * - WebSocket 配置:消息代理、端点、跨域策略等。
+ *
+ *
+ * 约定:
+ *
+ *
+ * - 配置类仅负责 Bean 装配,不承载业务逻辑。
+ * - 外部可变参数(地址、密钥、阈值等)通过配置注入,不硬编码在源码。
+ * - 默认值要保守,避免因配置缺失导致系统启动后产生危险行为。
+ *
+ */
+package com.yfd.business.css.config;
diff --git a/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmController.java b/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmController.java
index d0ab464..a4ac7d3 100644
--- a/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmController.java
+++ b/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmController.java
@@ -19,23 +19,58 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.time.LocalDateTime;
+/**
+ * 算法字典管理接口。
+ *
+ * 提供算法字典的基础 CRUD、按算法类型/名称查询,以及算法启用/停用等管理能力。
+ *
+ *
+ * 字段约定:
+ *
+ *
+ * - status:算法状态标识,"1" 表示启用,"0" 表示停用。
+ * - modifier:最后修改人用户名,取自当前登录上下文。
+ *
+ */
@RestController
@RequestMapping("/algorithms")
@Tag(name = "算法接口", description = "算法字典的增删改查与搜索")
public class AlgorithmController {
+ /**
+ * 算法字典服务(MyBatis-Plus Service)。
+ */
@Autowired
private AlgorithmService algorithmService;
+
+ /**
+ * 当前用户信息服务,用于记录 modifier 等审计字段。
+ */
@Autowired
private IUserService userService;
+ /**
+ * 根据主键查询算法。
+ *
+ * @param id 算法主键
+ * @return 算法对象;不存在时返回 null
+ */
@GetMapping("/{id}")
@Operation(summary = "根据算法ID获取算法", description = "路径参数传入算法ID,返回算法对象")
public Algorithm getAlgorithmById(@PathVariable String id) {
return algorithmService.getById(id);
}
+ /**
+ * 根据算法类型查询算法。
+ *
+ * 当前实现返回满足条件的第一条记录(LIMIT 1)。
+ *
+ *
+ * @param type 算法类型(如 GPR)
+ * @return 算法对象;不存在时返回 null
+ */
@GetMapping("/type/{type}")
@Operation(summary = "根据算法类型获取算法", description = "路径参数传入算法类型(如GPR),返回算法对象")
public Algorithm getAlgorithmByType(@PathVariable String type) {
@@ -49,6 +84,15 @@ public class AlgorithmController {
@PreAuthorize("hasAuthority('algorithm:add')")
@PostMapping
@Operation(summary = "新增算法", description = "请求体传入算法对象,返回是否新增成功")
+ /**
+ * 新增算法。
+ *
+ * 写入审计字段:modifier、createdAt、updatedAt。
+ *
+ *
+ * @param algorithm 算法对象(由请求体提供)
+ * @return 是否新增成功
+ */
public boolean createAlgorithm(@RequestBody Algorithm algorithm) {
algorithm.setModifier(currentUsername());
algorithm.setCreatedAt(LocalDateTime.now());
@@ -60,6 +104,15 @@ public class AlgorithmController {
@PreAuthorize("hasAuthority('algorithm:update')")
@PutMapping
@Operation(summary = "修改算法", description = "请求体传入算法对象(需包含主键),返回是否修改成功")
+ /**
+ * 修改算法。
+ *
+ * 仅更新 updatedAt 与 modifier,其他字段由请求体携带并覆盖更新。
+ *
+ *
+ * @param algorithm 算法对象(需包含主键)
+ * @return 是否修改成功
+ */
public boolean updateAlgorithm(@RequestBody Algorithm algorithm) {
algorithm.setModifier(currentUsername());
algorithm.setUpdatedAt(LocalDateTime.now());
@@ -70,6 +123,12 @@ public class AlgorithmController {
@PreAuthorize("hasAuthority('algorithm:del')")
@DeleteMapping("/{id}")
@Operation(summary = "删除算法(单条)", description = "根据算法ID删除算法")
+ /**
+ * 删除单条算法记录。
+ *
+ * @param id 算法主键
+ * @return 是否删除成功
+ */
public boolean deleteAlgorithm(@PathVariable String id) {
return algorithmService.removeById(id);
}
@@ -78,6 +137,12 @@ public class AlgorithmController {
@PreAuthorize("hasAuthority('algorithm:del')")
@DeleteMapping
@Operation(summary = "删除算法(批量)", description = "请求体传入算法ID列表,批量删除算法")
+ /**
+ * 批量删除算法记录。
+ *
+ * @param ids 算法主键列表
+ * @return 是否删除成功
+ */
public boolean deleteAlgorithms(@RequestBody List ids) {
return algorithmService.removeByIds(ids);
}
@@ -86,6 +151,12 @@ public class AlgorithmController {
// @PreAuthorize("hasAuthority('algorithm:activate')")
@PostMapping("/activate")
@Operation(summary = "激活算法", description = "激活当前算法类型")
+ /**
+ * 启用算法(status=1)。
+ *
+ * @param algorithmId 算法主键
+ * @return 是否更新成功;算法不存在时返回 false
+ */
public boolean activate(@RequestParam String algorithmId) {
Algorithm algorithm = algorithmService.getById(algorithmId);
if (algorithm == null) return false;
@@ -100,6 +171,12 @@ public class AlgorithmController {
// @PreAuthorize("hasAuthority('algorithm:unactivate')")
@PostMapping("/unactivate")
@Operation(summary = "关闭算法", description = "关闭当前算法类型")
+ /**
+ * 停用算法(status=0)。
+ *
+ * @param algorithmId 算法主键
+ * @return 是否更新成功;算法不存在时返回 false
+ */
public boolean unactivate(@RequestParam String algorithmId) {
Algorithm algorithm = algorithmService.getById(algorithmId);
if (algorithm == null) return false;
@@ -110,10 +187,9 @@ public class AlgorithmController {
return algorithmService.updateById(algorithm);
}
- //获取激活的算法类型
/**
- * 获取所有激活的算法类型
- * 输出参数:激活的算法类型列表
+ * 获取所有启用状态的算法列表(status=1)。
+ *
* @return 激活的算法类型列表
*/
@GetMapping("/getActiveAlgorithms")
@@ -125,12 +201,11 @@ public class AlgorithmController {
}
/**
- * 根据算法名称搜索并分页返回
- * 输入参数:查询参数 name(算法名称关键词,可为空),pageNum(页码,默认1),pageSize(每页条数,默认10)
- * 输出参数:算法分页列表
+ * 根据算法名称搜索并分页返回。
+ *
* @param name 算法名称关键词(可为空)
- * @param pageNum 页码
- * @param pageSize 每页条数
+ * @param pageNum 页码(默认 1)
+ * @param pageSize 每页条数(默认 20)
* @return 算法分页列表
*/
@GetMapping("/search")
@@ -147,6 +222,14 @@ public class AlgorithmController {
return algorithmService.page(page, qw);
}
+ /**
+ * 获取当前登录用户名。
+ *
+ * 用于落库的 modifier 字段,若用户未登录或上下文解析失败,返回 "anonymous"。
+ *
+ *
+ * @return 当前用户名或 "anonymous"
+ */
private String currentUsername() {
try {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
diff --git a/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmModelController.java b/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmModelController.java
index a973245..1177177 100644
--- a/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmModelController.java
+++ b/business-css/src/main/java/com/yfd/business/css/controller/AlgorithmModelController.java
@@ -3,9 +3,7 @@ package com.yfd.business.css.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.business.css.domain.AlgorithmModel;
-import com.yfd.business.css.domain.Algorithm;
import com.yfd.business.css.service.AlgorithmModelService;
-import com.yfd.business.css.service.AlgorithmService;
import com.yfd.platform.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -18,35 +16,49 @@ import com.yfd.platform.annotation.Log;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.core.type.TypeReference;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.net.URI;
-import java.time.Duration;
-import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.HashMap;
-import java.util.UUID;
import java.time.LocalDateTime;
import java.util.List;
+/**
+ * 算法模型版本管理接口。
+ *
+ * 提供算法模型版本的查询、分页筛选、当前版本获取、版本激活/切换以及删除等管理能力。
+ *
+ *
+ * 关键约定:
+ *
+ *
+ * - 模型分组维度:algorithmType + deviceType + materialType。
+ * - 当前版本标识:isCurrent=1 表示当前激活版本。
+ * - materialType 兼容:Mixed 与 MIX 视为同一类。
+ *
+ */
@RestController
@RequestMapping("/algorithm-models")
@Tag(name = "算法模型接口", description = "算法模型版本的增删改查、查询当前版本与在线训练")
public class AlgorithmModelController {
+ /**
+ * 算法模型服务(MyBatis-Plus Service)。
+ */
@Autowired
private AlgorithmModelService algorithmModelService;
+
+ /**
+ * 当前用户信息服务,用于记录 modifier 等审计字段。
+ */
@Autowired
private IUserService userService;
- @Autowired
- private AlgorithmService algorithmService;
- @Autowired
- private ObjectMapper objectMapper;
+ /**
+ * 根据主键查询模型版本。
+ *
+ * @param id 模型主键
+ * @return 模型版本对象;不存在时返回 null
+ */
@GetMapping("/{id}")
@Operation(summary = "根据模型ID获取模型版本", description = "路径参数传入模型ID,返回模型版本对象")
public AlgorithmModel getById(@PathVariable String id) {
@@ -57,6 +69,15 @@ public class AlgorithmModelController {
// @PreAuthorize("hasAuthority('algorithmModel:add')")
// @PostMapping
@Operation(summary = "新增模型版本", description = "请求体传入模型版本对象,返回是否新增成功")
+ /**
+ * 新增模型版本。
+ *
+ * 当前方法仅负责落库与审计字段写入;接口映射若被关闭(@PostMapping 注释),则不会对外提供入口。
+ *
+ *
+ * @param model 模型版本对象
+ * @return 是否新增成功
+ */
public boolean create(@RequestBody AlgorithmModel model) {
model.setModifier(currentUsername());
model.setCreatedAt(LocalDateTime.now());
@@ -68,6 +89,15 @@ public class AlgorithmModelController {
// @PreAuthorize("hasAuthority('algorithmModel:update')")
// @PutMapping
@Operation(summary = "修改模型版本", description = "请求体传入模型版本对象(需包含主键),返回是否修改成功")
+ /**
+ * 修改模型版本。
+ *
+ * 当前方法仅负责落库与审计字段写入;接口映射若被关闭(@PutMapping 注释),则不会对外提供入口。
+ *
+ *
+ * @param model 模型版本对象(需包含主键)
+ * @return 是否修改成功
+ */
public boolean update(@RequestBody AlgorithmModel model) {
model.setModifier(currentUsername());
model.setUpdatedAt(LocalDateTime.now());
@@ -78,6 +108,12 @@ public class AlgorithmModelController {
@PreAuthorize("hasAuthority('algorithmModel:del')")
@DeleteMapping("/{id}")
@Operation(summary = "删除模型版本(单条)", description = "根据模型ID删除模型版本")
+ /**
+ * 删除单条模型版本记录。
+ *
+ * @param id 模型主键
+ * @return 是否删除成功
+ */
public boolean delete(@PathVariable String id) {
return algorithmModelService.removeById(id);
}
@@ -86,11 +122,28 @@ public class AlgorithmModelController {
@PreAuthorize("hasAuthority('algorithmModel:del')")
@DeleteMapping
@Operation(summary = "删除模型版本(批量)", description = "请求体传入模型ID列表,批量删除模型版本")
+ /**
+ * 批量删除模型版本记录。
+ *
+ * @param ids 模型主键列表
+ * @return 是否删除成功
+ */
public boolean deleteBatch(@RequestBody List ids) {
return algorithmModelService.deleteBatchWithCheck(ids);
}
- //返回:该算法+设备类型+材料类型的版本列表
+ /**
+ * 查询模型版本列表(分页)。
+ *
+ * @param algorithmType 算法类型
+ * @param deviceType 设备类型
+ * @param materialType 材料类型(支持 Mixed/MIX 兼容)
+ * @param versionTag 版本号
+ * @param isCurrent 是否为当前版本(1/0)
+ * @param pageNum 页码(默认 1)
+ * @param pageSize 每页条数(默认 20)
+ * @return 模型版本分页结果
+ */
@GetMapping("/search")
@Operation(summary = "查询模型版本列表", description = "按算法类型、设备类型与材料类型过滤并分页返回模型版本")
public Page search(@RequestParam(required = false) String algorithmType,
@@ -118,6 +171,17 @@ public class AlgorithmModelController {
return algorithmModelService.page(page, qw);
}
+ /**
+ * 获取模型版本下拉选项。
+ *
+ * 返回包含 options(value=模型ID,label=版本号)与 currentModelId(当前激活模型ID)的结构,便于前端直接使用。
+ *
+ *
+ * @param algorithmType 算法类型
+ * @param deviceType 设备类型
+ * @param materialType 材料类型(可选)
+ * @return 选项数据
+ */
@GetMapping("/options")
@Operation(summary = "获取模型版本选项列表", description = "用于界面下拉选择:按算法类型与设备类型返回模型版本列表(value=模型ID,label=版本号),并返回当前激活模型ID")
public Map options(@RequestParam String algorithmType,
@@ -158,7 +222,14 @@ public class AlgorithmModelController {
return out;
}
- //返回:该算法+设备类型+材料类型的当前激活版本
+ /**
+ * 获取当前激活版本(is_current=1)。
+ *
+ * @param algorithmType 算法类型
+ * @param deviceType 设备类型
+ * @param materialType 材料类型(可选)
+ * @return 当前激活模型版本;不存在时返回 null
+ */
@GetMapping("/current")
@Operation(summary = "获取当前激活版本", description = "根据算法类型、设备类型与材料类型,返回 is_current=1 的模型版本")
public AlgorithmModel getCurrent(@RequestParam String algorithmType,
@@ -184,6 +255,15 @@ public class AlgorithmModelController {
@PreAuthorize("hasAuthority('algorithmModel:activate')")
@PostMapping("/activate")
@Operation(summary = "激活模型版本", description = "将目标模型版本设为当前,并将同组(算法+设备+材料)其他版本设为非当前")
+ /**
+ * 激活指定模型版本。
+ *
+ * 激活时会将同组(algorithmType+deviceType+materialType)其他版本置为非当前(isCurrent=0),再将指定版本置为当前。
+ *
+ *
+ * @param algorithmModelId 模型主键
+ * @return 是否更新成功;模型不存在时返回 false
+ */
public boolean activate(@RequestParam String algorithmModelId) {
AlgorithmModel model = algorithmModelService.getById(algorithmModelId);
if (model == null) return false;
@@ -212,148 +292,12 @@ public class AlgorithmModelController {
return algorithmModelService.updateById(model);
}
- @Log(value = "在线训练(Excel)", module = "算法模型管理")
- // 在线训练(Excel 数据集)
- // @PostMapping("/train/excel")
- @Operation(summary = "在线训练(Excel)", description = "传入算法类型、设备类型与Excel路径,训练完成新增模型版本记录,可选激活")
- public Map trainExcel(@RequestBody Map body) {
- String algorithmType = str(body.get("algorithm_type"));
- String deviceType = str(body.get("device_type"));
- String materialType = normalizeMaterialType(str(body.getOrDefault("material_type", "")));
- String datasetPath = str(body.get("dataset_path"));
- String modelDir = str(body.getOrDefault("model_dir", ""));
- boolean activate = bool(body.getOrDefault("activate", false));
- String featureMapSnapshot = toJson(body.get("feature_map_snapshot"));
- if (isBlank(algorithmType) || isBlank(deviceType) || isBlank(datasetPath)) {
- return Map.of("code", 1, "msg", "algorithm_type/device_type/dataset_path 必填");
- }
- Algorithm algo = getAlgorithmByType(algorithmType);
- if (algo == null || isBlank(algo.getTrainBaseUrl())) {
- return Map.of("code", 1, "msg", "算法或训练URL未配置");
- }
- String baseUrl = algo.getTrainBaseUrl();
- if (baseUrl != null && baseUrl.endsWith("/")) {
- baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
- }
- String url = baseUrl + "/v1/train/" + deviceType;
- Map payload = new HashMap<>();
- payload.put("dataset_path", datasetPath);
- if (!isBlank(modelDir)) payload.put("model_dir", modelDir);
- Map resp = httpPostJson(url, payload);
- if (resp == null) return Map.of("code", 1, "msg", "训练接口无响应");
- int code = 0;
- Object codeObj = resp.get("code");
- if (codeObj instanceof Number) {
- code = ((Number) codeObj).intValue();
- } else if (codeObj instanceof String) {
- try {
- code = Integer.parseInt((String) codeObj);
- } catch (NumberFormatException ignored) {
- code = 1;
- }
- }
- if (code != 0) return Map.of("code", 1, "msg", "训练失败: " + str(resp.get("msg")));
- Map data = castMap(resp.get("data"));
- String modelPath = str(data.get("model_path"));
- String metrics = toJson(data.get("metrics"));
- AlgorithmModel model = new AlgorithmModel();
- model.setAlgorithmModelId(UUID.randomUUID().toString());
- model.setAlgorithmType(algorithmType);
- model.setDeviceType(deviceType);
- model.setMaterialType(materialType);
- model.setVersionTag(genVersionTag());
- model.setModelPath(modelPath);
- model.setFeatureMapSnapshot(isBlank(featureMapSnapshot) ? "{}" : featureMapSnapshot);
- model.setMetrics(metrics);
- model.setTrainedAt(LocalDateTime.now());
- model.setIsCurrent(activate ? 1 : 0);
- model.setCreatedAt(LocalDateTime.now());
- model.setUpdatedAt(LocalDateTime.now());
- model.setModifier(currentUsername());
- if (activate) {
- QueryWrapper qw = new QueryWrapper<>();
- qw.eq("algorithm_type", algorithmType).eq("device_type", deviceType);
- if (!isBlank(materialType)) {
- if ("Mixed".equals(materialType)) {
- qw.in("material_type", List.of("Mixed", "MIX"));
- } else {
- qw.eq("material_type", materialType);
- }
- } else {
- qw.and(wrapper -> wrapper.isNull("material_type").or().eq("material_type", ""));
- }
- AlgorithmModel upd = new AlgorithmModel();
- upd.setIsCurrent(0);
- algorithmModelService.update(upd, qw);
- }
- algorithmModelService.save(model);
- return Map.of("code", 0, "msg", "训练成功", "data", model);
- }
-
- @Log(value = "在线训练(样本)", module = "算法模型管理")
- // 在线训练(样本集合)
- // @PostMapping("/train/samples")
- @Operation(summary = "在线训练(样本集合)", description = "传入算法类型、设备类型与样本集,训练完成新增模型版本记录,可选激活")
- public Map trainSamples(@RequestBody Map body) {
- String algorithmType = str(body.get("algorithm_type"));
- String deviceType = str(body.get("device_type"));
- String materialType = normalizeMaterialType(str(body.getOrDefault("material_type", "")));
- Object samples = body.get("samples"); // 期望为 List
+ *
+ * @param a 算法对象
+ */
private void normalizeJsonFields(Algorithm a) {
if (a == null) return;
a.setInputParams(blankToDefaultJson(a.getInputParams(), "{}"));
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java
index 158cbb0..22a00e5 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java
@@ -37,13 +37,36 @@ import java.util.Collections;
import java.io.ByteArrayOutputStream;
import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 临界数据服务实现。
+ *
+ * 提供临界数据的 Excel 导入、校验、导出与模板生成能力,并在导入过程中做字段解析与数据规整。
+ *
+ *
+ * 设计要点:
+ *
+ *
+ * - 导入支持 xls/xlsx;V2 提供“先校验后导入”的交互方式。
+ * - 对数值/公式单元格使用 DataFormatter + FormulaEvaluator 进行兼容读取。
+ * - 解析失败信息以结构化 errors 列表返回给前端,便于定位问题行。
+ *
+ */
@Service
@Slf4j
public class CriticalDataServiceImpl
extends ServiceImpl
implements CriticalDataService {
+
+ /**
+ * JSON 解析器,用于处理扩展字段与自定义属性的解析。
+ */
@Resource
private ObjectMapper objectMapper;
+
+ /**
+ * 当前用户信息服务,用于写入 modifier 等审计字段。
+ */
@Resource
private IUserService userService;
@Override
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/DeviceServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/DeviceServiceImpl.java
index 039b513..3c36a9a 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/DeviceServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/DeviceServiceImpl.java
@@ -37,15 +37,40 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
+/**
+ * 设备服务实现。
+ *
+ * 提供设备的导入导出(含 V2 校验与模板)、以及设备新增/更新等能力,并对设备尺寸等字段按 schema 做解析与规整。
+ *
+ *
+ * 设计要点:
+ *
+ *
+ * - 导入支持 xls/xlsx;V2 提供“先校验后导入”的交互方式。
+ * - deviceSizeSchemaRegistry 用于按 deviceType 获取尺寸字段元数据,以统一导入/导出/校验口径。
+ *
+ */
@Slf4j
@Service
public class DeviceServiceImpl
extends ServiceImpl
implements DeviceService {
+
+ /**
+ * JSON 解析器,用于处理扩展字段与自定义属性的解析。
+ */
@Resource
private ObjectMapper objectMapper;
+
+ /**
+ * 当前用户信息服务,用于写入 modifier 等审计字段。
+ */
@Resource
private IUserService userService;
+
+ /**
+ * 设备尺寸 schema 注册表,用于按设备类型解析/校验尺寸字段。
+ */
@Resource
private DeviceSizeSchemaRegistry deviceSizeSchemaRegistry;
@Override
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/EventServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/EventServiceImpl.java
index 868f7a7..b391871 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/EventServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/EventServiceImpl.java
@@ -7,6 +7,12 @@ import com.yfd.business.css.service.EventService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+/**
+ * 事件服务实现。
+ *
+ * 事件数据主要由上层控制器按情景维度进行读写与权限校验;此处提供基于 MyBatis-Plus 的基础 CRUD 能力。
+ *
+ */
@Slf4j
@Service
public class EventServiceImpl
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/MaterialServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/MaterialServiceImpl.java
index 606ff8a..c279c56 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/MaterialServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/MaterialServiceImpl.java
@@ -35,13 +35,34 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+/**
+ * 物料服务实现。
+ *
+ * 提供物料的 Excel 导入导出、模板生成,以及物料新增/更新的业务语义处理(如 materialId 自动生成)。
+ *
+ *
+ * 设计要点:
+ *
+ *
+ * - 导入支持 xls/xlsx,通过表头映射进行字段解析。
+ * - custom_attrs 字段以 JSON 形式保存,需要做合法性校验与空值规整。
+ *
+ */
@Slf4j
@Service
public class MaterialServiceImpl
extends ServiceImpl
implements MaterialService {
+
+ /**
+ * JSON 解析器,用于处理自定义属性等 JSON 字段。
+ */
@Resource
private ObjectMapper objectMapper;
+
+ /**
+ * 当前用户信息服务,用于写入 modifier 等审计字段。
+ */
@Resource
private IUserService userService;
@Override
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/ModelTrainServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/ModelTrainServiceImpl.java
index dc2baad..2416224 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/ModelTrainServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/ModelTrainServiceImpl.java
@@ -15,6 +15,7 @@ import com.yfd.business.css.service.ModelTrainService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@@ -23,6 +24,8 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
@@ -53,6 +56,31 @@ import java.util.UUID;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
+/**
+ * 模型训练任务服务实现。
+ *
+ * 该类负责训练数据集上传与解析、训练任务创建与提交、与外部 Python 训练服务交互、
+ * 以及训练任务状态流转与超时回收等能力。
+ *
+ *
+ * 关键流程:
+ *
+ *
+ * - 数据集上传:接收 MultipartFile,将文件落盘并返回可追溯路径。
+ * - 数据集检查:解析表头/字段并返回给前端,用于配置训练参数。
+ * - 任务提交:创建训练任务,初始化状态并触发异步训练调用。
+ * - 容量控制:限制 Training 并发上限与 Pending 排队上限。
+ * - 超时回收:定时扫描超时的 Training 任务并置为失败,防止容量被长期占用。
+ *
+ *
+ * 约束与注意事项:
+ *
+ *
+ * - 路径通过配置注入,避免环境差异导致不可写目录。
+ * - 外部返回字段需要做健壮解析,避免 null/空字符串/非数字导致异常。
+ * - 回调更新需要具备幂等语义,避免重复回调造成状态覆盖。
+ *
+ */
@Slf4j
@Service
public class ModelTrainServiceImpl extends ServiceImpl implements ModelTrainService {
@@ -74,6 +102,10 @@ public class ModelTrainServiceImpl extends ServiceImpl
+ * 文件将按日期目录分组保存,文件名使用 UUID,避免并发上传冲突。
+ *
+ *
+ * - 入参校验:上传文件不能为空。
+ * - 路径解析:支持相对路径配置,运行时转换为绝对路径。
+ * - 目录创建:目录不存在时创建目录,并处理并发创建的情况。
+ *
+ *
+ * @param file 上传文件
+ * @return 保存后的绝对路径
+ */
@Override
public String uploadDataset(MultipartFile file) {
if (file.isEmpty()) {
@@ -129,6 +175,16 @@ public class ModelTrainServiceImpl extends ServiceImpl
+ * 该方法用于前端在配置训练参数时选择输入特征列/输出列等字段。
+ * 当前支持 CSV 与 Excel(xls/xlsx)两类格式,并对不支持的格式返回明确错误语义。
+ *
+ *
+ * @param datasetPath 数据集文件路径(绝对路径)
+ * @return 列名列表
+ */
@Override
public List parseDatasetColumns(String datasetPath) {
if (datasetPath == null || datasetPath.isBlank()) {
@@ -148,6 +204,20 @@ public class ModelTrainServiceImpl extends ServiceImpl
+ * 适用于“一步上传并预检”的页面交互,返回结构包含:
+ *
+ *
+ * - path:保存后的数据集路径
+ * - columns:解析出的列名列表
+ * - warnings:字段与内容的告警信息(用于提示潜在配置错误)
+ *
+ *
+ * @param file 上传文件
+ * @return 预检结果
+ */
@Override
public Map uploadAndInspectDataset(MultipartFile file) {
String path = uploadDataset(file);
@@ -183,12 +253,25 @@ public class ModelTrainServiceImpl extends ServiceImpl self.asyncCallTrain(task));
return task.getTaskId();
}
+ private void runAfterCommit(Runnable runnable) {
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
+ @Override
+ public void afterCommit() {
+ runnable.run();
+ }
+ });
+ return;
+ }
+ runnable.run();
+ }
+
@Override
public Map checkCapacity() {
long training = countActiveTraining();
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java
index 6dcc17c..c9a445d 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java
@@ -51,6 +51,30 @@ import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
import java.math.BigDecimal;
+/**
+ * 项目域核心服务实现。
+ *
+ * 该类聚合了项目相关的高频业务能力,覆盖“项目基础信息”“拓扑解析与校验”“设备执行顺序解析”
+ * “画布视图数据组织”“推演初始化与运行”“工程数据 Excel 导入导出”等场景。
+ *
+ *
+ * 主要能力边界:
+ *
+ *
+ * - 数据读取:通过 Project/Device/Material/Scenario/Event 等服务与 Mapper 获取所需数据。
+ * - 结构解析:解析项目 topology JSON,生成节点/边与线性执行计划,并输出问题列表。
+ * - 推演编排:组织推演输入上下文,计算设备顺序与材料注入信息,输出推演可用的数据结构。
+ * - 工程数据:支持工程 Excel 的导入/导出,用于项目初始化、备份与批量维护。
+ *
+ *
+ * 运行与质量约束:
+ *
+ *
+ * - 健壮性:对 JSON 字段缺失、空字符串、非法引用等情况给出明确问题列表或异常语义。
+ * - 一致性:涉及级联删除/批量导入时,需要保证项目内相关实体的一致性与可追溯性。
+ * - 性能:导入导出与解析逻辑避免一次性构造超大字符串,必要处做长度截断与分段处理。
+ *
+ */
@Slf4j
@Service
public class ProjectServiceImpl
@@ -78,6 +102,19 @@ public class ProjectServiceImpl
this.deviceDataParser = deviceDataParser;
}
+ /**
+ * 导出全部项目数据到 Excel(xlsx)。
+ *
+ * 主要用于后台管理侧的项目清单导出,字段包含项目编号、名称、描述、拓扑文本与时间字段等。
+ *
+ *
+ * - 排序:按创建时间倒序输出。
+ * - 长度限制:拓扑字段受 Excel 单元格长度限制,超长文本会被截断并追加省略号。
+ * - 异常语义:导出失败抛出运行时异常,交由上层统一异常处理机制返回。
+ *
+ *
+ * @return Excel 二进制内容
+ */
@Override
public byte[] exportAllProjectsExcel() {
log.info("exportAllProjectsExcel start");
@@ -113,16 +150,26 @@ public class ProjectServiceImpl
if (s == null) return "";
int max = 32767;
if (s.length() <= max) return s;
- if (max <= 3) return s.substring(0, max);
return s.substring(0, max - 3) + "...";
}
- @Override
/**
- * 解析指定项目的拓扑结构,生成节点、边与线性计算计划
+ * 解析指定项目的拓扑结构,生成节点、边与线性计算计划。
+ *
+ * topology 期望为 JSON 字符串,内部包含设备列表与连接关系等结构。
+ * 解析结果将包含:
+ *
+ *
+ * - nodes:拓扑节点列表。
+ * - edges:拓扑边列表。
+ * - plans:线性执行计划(用于后续计算顺序/推演编排)。
+ * - issues:解析过程中发现的问题列表(例如字段缺失、引用不存在等)。
+ *
+ *
* @param projectId 项目ID
* @return TopologyParseResult
*/
+ @Override
public TopologyParseResult parseTopology(String projectId) {
log.info("parseTopology start projectId={}", projectId);
try {
@@ -386,6 +433,20 @@ public class ProjectServiceImpl
return t;
}
+ /**
+ * 按 topology 中的设备出现顺序解析设备列表。
+ *
+ * 与直接按数据库字段排序不同,该方法以 topology JSON 中 devices 数组的顺序为准,
+ * 并将其映射为对应的设备实体列表。
+ *
+ *
+ * - 当项目不存在或 topology 为空时返回空列表。
+ * - 当某些 deviceId 在数据库中不存在时,会自动跳过缺失设备。
+ *
+ *
+ * @param projectId 项目ID
+ * @return 设备列表(保持 topology 顺序)
+ */
@Override
public List parseDeviceOrder(String projectId) {
log.info("parseDeviceOrder start projectId={}", projectId);
@@ -419,12 +480,21 @@ public class ProjectServiceImpl
}
}
- @Override
/**
- * 提取画布视图所需数据(设备、管线、边界、显示配置)
+ * 提取画布视图所需数据(设备、管线、边界、显示配置)。
+ *
+ * 用于前端建模/编辑页面的初始化展示,返回结构为 Map,按前端协议组织多个子对象:
+ *
+ *
+ * - 基础信息:项目信息、拓扑基础字段。
+ * - 实体集合:设备、材料、事件等(按需要提供)。
+ * - 展示配置:画布边界、布局与扩展字段(按拓扑内容解析)。
+ *
+ *
* @param projectId 项目ID
- * @return Map 视图对象
+ * @return 画布视图对象
*/
+ @Override
public Map parseCanvasView(String projectId) {
log.info("parseCanvasView start projectId={}", projectId);
try {
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioResultServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioResultServiceImpl.java
index 5871fb8..966ed52 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioResultServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioResultServiceImpl.java
@@ -7,6 +7,12 @@ import com.yfd.business.css.service.ScenarioResultService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+/**
+ * 情景结果服务实现。
+ *
+ * 结果数据由仿真/推理流程写入,本类提供基于 MyBatis-Plus 的基础 CRUD 能力与统一的数据访问入口。
+ *
+ */
@Slf4j
@Service
public class ScenarioResultServiceImpl
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioServiceImpl.java
index 3b0b1e7..ab45de2 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/ScenarioServiceImpl.java
@@ -7,6 +7,12 @@ import com.yfd.business.css.service.ScenarioService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+/**
+ * 情景服务实现。
+ *
+ * 提供情景相关的基础 CRUD 能力,以及按情景 ID 获取算法类型等轻量查询能力。
+ *
+ */
@Slf4j
@Service
public class ScenarioServiceImpl
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/SimulationServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/SimulationServiceImpl.java
index 808cd84..56b3047 100644
--- a/business-css/src/main/java/com/yfd/business/css/service/impl/SimulationServiceImpl.java
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/SimulationServiceImpl.java
@@ -8,9 +8,21 @@ import org.springframework.stereotype.Service;
import java.time.Instant;
+/**
+ * 仿真服务实现(占位实现)。
+ *
+ * 当前实现用于打通接口链路与日志观测,尚未接入真实的仿真引擎计算逻辑。
+ *
+ */
@Slf4j
@Service
public class SimulationServiceImpl implements SimulationService {
+ /**
+ * 执行一次仿真并返回结果。
+ *
+ * @param request 仿真请求参数
+ * @return 仿真结果
+ */
@Override
public SimulationResult runSimulation(SimulationRequest request) {
log.info("SimulationServiceImpl runSimulation start request={}", request);
@@ -23,4 +35,4 @@ public class SimulationServiceImpl implements SimulationService {
log.info("SimulationServiceImpl runSimulation finish status={}", result.getStatus());
return result;
}
-}
\ No newline at end of file
+}
diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/package-info.java b/business-css/src/main/java/com/yfd/business/css/service/impl/package-info.java
new file mode 100644
index 0000000..a918944
--- /dev/null
+++ b/business-css/src/main/java/com/yfd/business/css/service/impl/package-info.java
@@ -0,0 +1,29 @@
+/**
+ * Service 实现层。
+ *
+ * 该包包含领域服务的具体实现,承载主要业务规则与流程编排,典型职责:
+ *
+ *
+ * - 业务规则落地:状态机、容量控制、参数校验、对象关联关系处理等。
+ * - 事务边界:在必要处声明事务,确保写操作一致性。
+ * - 外部调用:调用推演/训练等外部服务时,负责请求组装、返回解析与容错。
+ * - 数据访问:通过 Mapper 层完成持久化读写,不直接拼接 SQL。
+ *
+ *
+ * 质量与安全约束:
+ *
+ *
+ * - 健壮性:对空值、空集合、外部返回字段做防御性处理,避免 NPE。
+ * - 一致性:写入前校验引用存在性,避免产生孤儿数据与不一致关联。
+ * - 幂等性:对外部回调/重复提交等场景具备幂等保护(如按任务ID去重)。
+ * - 敏感信息:日志不记录口令、token、密钥等敏感字段。
+ *
+ *
+ * 性能约定:
+ *
+ *
+ * - 批量操作:大数据量导出/查询优先使用分页与批处理,避免一次性加载过多数据。
+ * - 长耗时任务:推演/训练等应走任务化机制并提供状态回调与超时回收。
+ *
+ */
+package com.yfd.business.css.service.impl;
diff --git a/business-css/src/main/java/com/yfd/business/css/service/package-info.java b/business-css/src/main/java/com/yfd/business/css/service/package-info.java
new file mode 100644
index 0000000..d3e5bf8
--- /dev/null
+++ b/business-css/src/main/java/com/yfd/business/css/service/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * Service(领域服务)接口层。
+ *
+ * 该包定义后端核心业务能力的接口边界,是 Controller 与数据访问层之间的“业务语义层”。
+ *
+ *
+ * - 接口表达业务语义:方法名与入参/出参体现领域含义,而非表字段操作。
+ * - 事务语义在实现层落地:接口侧强调“做什么”,实现侧强调“如何做”。
+ * - 幂等与一致性:对外接口尽量保持幂等与可预期错误语义。
+ *
+ *
+ * 典型服务域:
+ *
+ *
+ * - 项目/场景:拓扑解析、推演输入准备、结果查询等。
+ * - 设备/事件/材料:基础数据维护、解析与结构化转换。
+ * - 训练任务:提交、容量控制、状态流转与回调处理。
+ *
+ *
+ * 约定:
+ *
+ *
+ * - 接口不要依赖 Web 层对象(HttpServletRequest 等)。
+ * - 接口返回值尽量明确,避免 Object/Map 泛化导致契约不清。
+ *
+ */
+package com.yfd.business.css.service;
diff --git a/business-css/src/main/java/com/yfd/business/css/utils/package-info.java b/business-css/src/main/java/com/yfd/business/css/utils/package-info.java
new file mode 100644
index 0000000..86576c1
--- /dev/null
+++ b/business-css/src/main/java/com/yfd/business/css/utils/package-info.java
@@ -0,0 +1,20 @@
+/**
+ * 业务工具类。
+ *
+ * 该包用于放置与 business-css 业务强相关的工具能力,例如:
+ *
+ *
+ * - 数据解析:对设备数据、属性字段、拓扑结构等进行解析与归一化。
+ * - 转换与拼装:将 Domain/DTO/Model 在不同层之间做结构化转换。
+ * - 校验辅助:对复杂字段格式、引用关系、一致性约束做统一校验。
+ *
+ *
+ * 约定:
+ *
+ *
+ * - 工具类不应持有全局可变状态,避免并发与复用风险。
+ * - 与框架通用工具(framework 模块)区分,避免重复实现通用能力。
+ * - 异常提示应可定位输入问题,便于测试与排障。
+ *
+ */
+package com.yfd.business.css.utils;
diff --git a/framework/src/main/java/com/yfd/platform/system/controller/LoginController.java b/framework/src/main/java/com/yfd/platform/system/controller/LoginController.java
index 4091a0a..8cc8a00 100644
--- a/framework/src/main/java/com/yfd/platform/system/controller/LoginController.java
+++ b/framework/src/main/java/com/yfd/platform/system/controller/LoginController.java
@@ -73,20 +73,6 @@ public class LoginController {
user.getPassword());
- // 是否需要验证码不需要改成false
- boolean hascode = false;//true;
- if (hascode) {
- // 查询验证码
- String code = webConfig.loginuserCache().get(user.getUuid());
- // 清除验证码
- webConfig.loginuserCache().remove(user.getUuid());
- if (StrUtil.isBlank(code)) {
- return ResponseResult.error("验证码不存在或已过期");
- }
- if (StrUtil.isBlank(user.getCode()) || !user.getCode().equalsIgnoreCase(code)) {
- return ResponseResult.error("验证码错误");
- }
- }
//如果认证通过了,使用userId生成token token存入ResponseResult返回
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(user.getUsername(),
diff --git a/framework/src/main/java/com/yfd/platform/utils/EncryptUtils.java b/framework/src/main/java/com/yfd/platform/utils/EncryptUtils.java
deleted file mode 100644
index 2ae2b26..0000000
--- a/framework/src/main/java/com/yfd/platform/utils/EncryptUtils.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2019-2020 Zheng Jie
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.yfd.platform.utils;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.DESKeySpec;
-import javax.crypto.spec.IvParameterSpec;
-import java.nio.charset.StandardCharsets;
-
-/**
- * 加密
- * @author
- * @date 2018-11-23
- */
-
-public class EncryptUtils {
-
- private static final String STR_PARAM = "Passw0rd";
-
- private static Cipher cipher;
-
- private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8));
-
- private static DESKeySpec getDesKeySpec(String source) throws Exception {
- if (source == null || source.length() == 0){
- return null;
- }
- cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
- String strKey = "Passw0rd";
- return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8));
- }
-
- /**
- * 对称加密
- */
- public static String desEncrypt(String source) throws Exception {
- DESKeySpec desKeySpec = getDesKeySpec(source);
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
- cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV);
- return byte2hex(
- cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase();
- }
-
- /**
- * 对称解密
- */
- public static String desDecrypt(String source) throws Exception {
- byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8));
- DESKeySpec desKeySpec = getDesKeySpec(source);
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
- cipher.init(Cipher.DECRYPT_MODE, secretKey, IV);
- byte[] retByte = cipher.doFinal(src);
- return new String(retByte);
- }
-
- private static String byte2hex(byte[] inStr) {
- String stmp;
- StringBuilder out = new StringBuilder(inStr.length * 2);
- for (byte b : inStr) {
- stmp = Integer.toHexString(b & 0xFF);
- if (stmp.length() == 1) {
- // 如果是0至F的单位字符串,则添加0
- out.append("0").append(stmp);
- } else {
- out.append(stmp);
- }
- }
- return out.toString();
- }
-
- private static byte[] hex2byte(byte[] b) {
- int size = 2;
- if ((b.length % size) != 0){
- throw new IllegalArgumentException("长度不是偶数");
- }
- byte[] b2 = new byte[b.length / 2];
- for (int n = 0; n < b.length; n += size) {
- String item = new String(b, n, 2);
- b2[n / 2] = (byte) Integer.parseInt(item, 16);
- }
- return b2;
- }
-}
diff --git a/framework/src/main/java/com/yfd/platform/utils/FileUtil.java b/framework/src/main/java/com/yfd/platform/utils/FileUtil.java
index 6940aee..bc7ff25 100644
--- a/framework/src/main/java/com/yfd/platform/utils/FileUtil.java
+++ b/framework/src/main/java/com/yfd/platform/utils/FileUtil.java
@@ -38,7 +38,6 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
-import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -285,61 +284,6 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
}
}
- /**
- * 判断两个文件是否相同
- */
- public static boolean check(File file1, File file2) {
- String img1Md5 = getMd5(file1);
- String img2Md5 = getMd5(file2);
- return img1Md5.equals(img2Md5);
- }
-
- /**
- * 判断两个文件是否相同
- */
- public static boolean check(String file1Md5, String file2Md5) {
- return file1Md5.equals(file2Md5);
- }
-
- private static byte[] getByte(File file) {
- // 得到文件长度
- byte[] b = new byte[(int) file.length()];
- try {
- InputStream in = new FileInputStream(file);
- try {
- System.out.println(in.read(b));
- } catch (IOException e) {
- log.error(e.getMessage(), e);
- }
- } catch (FileNotFoundException e) {
- log.error(e.getMessage(), e);
- return null;
- }
- return b;
- }
-
- private static String getMd5(byte[] bytes) {
- // 16进制字符
- char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
- try {
- MessageDigest mdTemp = MessageDigest.getInstance("MD5");
- mdTemp.update(bytes);
- byte[] md = mdTemp.digest();
- int j = md.length;
- char[] str = new char[j * 2];
- int k = 0;
- // 移位 输出字符串
- for (byte byte0 : md) {
- str[k++] = hexDigits[byte0 >>> 4 & 0xf];
- str[k++] = hexDigits[byte0 & 0xf];
- }
- return new String(str);
- } catch (Exception e) {
- log.error(e.getMessage(), e);
- }
- return null;
- }
-
/**
* 下载文件
*
@@ -391,8 +335,4 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
fis.close();
}
- public static String getMd5(File file) {
- return getMd5(getByte(file));
- }
-
}
diff --git a/framework/src/main/java/com/yfd/platform/utils/RsaUtils.java b/framework/src/main/java/com/yfd/platform/utils/RsaUtils.java
index 6638ac7..20d7674 100644
--- a/framework/src/main/java/com/yfd/platform/utils/RsaUtils.java
+++ b/framework/src/main/java/com/yfd/platform/utils/RsaUtils.java
@@ -4,8 +4,6 @@ import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@@ -16,57 +14,6 @@ import java.security.spec.X509EncodedKeySpec;
**/
public class RsaUtils {
- private static final String SRC = "123456";
-
- public static void main(String[] args) throws Exception {
- System.out.println("\n");
- RsaKeyPair keyPair = generateKeyPair();
- System.out.println("公钥:" + keyPair.getPublicKey());
- System.out.println("私钥:" + keyPair.getPrivateKey());
- System.out.println("\n");
- test1(keyPair);
- System.out.println("\n");
- test2(keyPair);
- System.out.println("\n");
- }
-
- /**
- * 公钥加密私钥解密
- */
- private static void test1(RsaKeyPair keyPair) throws Exception {
- System.out.println("***************** 公钥加密私钥解密开始 *****************");
- String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC);
- String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
- System.out.println("加密前:" + RsaUtils.SRC);
- System.out.println("加密后:" + text1);
- System.out.println("解密后:" + text2);
- if (RsaUtils.SRC.equals(text2)) {
- System.out.println("解密字符串和原始字符串一致,解密成功");
- } else {
- System.out.println("解密字符串和原始字符串不一致,解密失败");
- }
- System.out.println("***************** 公钥加密私钥解密结束 *****************");
- }
-
- /**
- * 私钥加密公钥解密
- * @throws Exception /
- */
- private static void test2(RsaKeyPair keyPair) throws Exception {
- System.out.println("***************** 私钥加密公钥解密开始 *****************");
- String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC);
- String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
- System.out.println("加密前:" + RsaUtils.SRC);
- System.out.println("加密后:" + text1);
- System.out.println("解密后:" + text2);
- if (RsaUtils.SRC.equals(text2)) {
- System.out.println("解密字符串和原始字符串一致,解密成功");
- } else {
- System.out.println("解密字符串和原始字符串不一致,解密失败");
- }
- System.out.println("***************** 私钥加密公钥解密结束 *****************");
- }
-
/**
* 公钥解密
*
@@ -137,45 +84,4 @@ public class RsaUtils {
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
-
- /**
- * 构建RSA密钥对
- *
- * @return /
- * @throws NoSuchAlgorithmException /
- */
- public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(1024);
- KeyPair keyPair = keyPairGenerator.generateKeyPair();
- RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
- String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
- String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
- return new RsaKeyPair(publicKeyString, privateKeyString);
- }
-
-
- /**
- * RSA密钥对对象
- */
- public static class RsaKeyPair {
-
- private final String publicKey;
- private final String privateKey;
-
- public RsaKeyPair(String publicKey, String privateKey) {
- this.publicKey = publicKey;
- this.privateKey = privateKey;
- }
-
- public String getPublicKey() {
- return publicKey;
- }
-
- public String getPrivateKey() {
- return privateKey;
- }
-
- }
}