Merge branch 'develop-business-css' of http://121.37.111.42:3000/ThbTech/JavaProjectRepo into develop-business-css
This commit is contained in:
commit
bd7292ccbe
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@ -7,13 +7,16 @@
|
||||
"hostName": "localhost",
|
||||
"port": "5005"
|
||||
},
|
||||
java
|
||||
|
||||
{
|
||||
"type": "java",
|
||||
"name": "CriticalScenarioApplication",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"mainClass": "com.yfd.business.css.CriticalScenarioApplication",
|
||||
"projectName": "business-css"
|
||||
"projectName": "business-css",
|
||||
"args": "",
|
||||
"envFile": "${workspaceFolder}/.env"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
|
||||
@ -51,6 +51,23 @@
|
||||
4. 增加 OpenAPI 文档与前端集成接口规范。
|
||||
5. 引入结果持久化与查询报表。
|
||||
|
||||
## 调试与开发指南
|
||||
|
||||
### Maven 命令行启动 + 远程调试
|
||||
|
||||
如果您偏好使用命令行启动,或者需要模拟特定的 Maven 环境,可采用以下方式:
|
||||
|
||||
1. **启动应用**:
|
||||
在终端中运行以下命令,该命令会以调试模式启动应用并监听 `5005` 端口(`suspend=n` 表示不等待调试器连接直接启动,如需等待可改为 `y`)。
|
||||
> 注意:PowerShell 中需要使用单引号包裹 JVM 参数,防止解析错误。
|
||||
|
||||
```bash
|
||||
mvn -DskipTests spring-boot:run -pl business-css '-Dspring-boot.run.jvmArguments=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005'
|
||||
```
|
||||
|
||||
2. **附加调试器**:
|
||||
应用启动后,转到 IDE 的 "运行和调试" (Run and Debug) 面板,选择 **"Attach to Remote Program(5005)"** 配置(需确保 `.vscode/launch.json` 中已存在相应配置),然后点击运行。IDE 将连接到正在运行的 Maven 进程,即可开始断点调试。
|
||||
|
||||
## 运维与配置
|
||||
- 端口默认 `8082`,环境覆盖通过 `application.yml` 与外部化配置。
|
||||
- 数据库连接按环境注入(dev/test/prod)。
|
||||
|
||||
@ -66,6 +66,13 @@
|
||||
<classifier>plain</classifier>
|
||||
</dependency>
|
||||
|
||||
<!-- 显式添加 MyBatis-Plus 依赖,确保测试环境类加载正确 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.5.6</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
package com.yfd.business.css.config;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ComponentScan(basePackages = {
|
||||
"com.yfd.business.css.controller"
|
||||
})
|
||||
@Import(OpenApiConfig.class)
|
||||
public class BusinessCssAutoConfiguration {
|
||||
}
|
||||
@ -14,9 +14,6 @@ import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilde
|
||||
import org.springdoc.core.models.GroupedOpenApi;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.io.IOException;
|
||||
|
||||
@ -41,9 +38,6 @@ public class OpenApiConfig {
|
||||
builder.deserializers(new LocalDateTimeDeserializer(fmt));
|
||||
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
builder.serializationInclusion(JsonInclude.Include.ALWAYS);
|
||||
builder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.NONE);
|
||||
builder.visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY);
|
||||
builder.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
||||
SimpleModule module = new SimpleModule();
|
||||
module.setSerializerModifier(new BeanSerializerModifier() {
|
||||
@Override
|
||||
|
||||
@ -11,11 +11,15 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import java.util.List;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/algorithms")
|
||||
@Tag(name = "算法接口", description = "算法字典的增删改查与搜索")
|
||||
public class AlgorithmController {
|
||||
|
||||
@Autowired
|
||||
@ -25,11 +29,13 @@ public class AlgorithmController {
|
||||
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "根据算法ID获取算法", description = "路径参数传入算法ID,返回算法对象")
|
||||
public Algorithm getAlgorithmById(@PathVariable String id) {
|
||||
return algorithmService.getById(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "新增算法", description = "请求体传入算法对象,返回是否新增成功")
|
||||
public boolean createAlgorithm(@RequestBody Algorithm algorithm) {
|
||||
algorithm.setModifier(currentUsername());
|
||||
algorithm.setCreatedAt(LocalDateTime.now());
|
||||
@ -38,6 +44,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "修改算法", description = "请求体传入算法对象(需包含主键),返回是否修改成功")
|
||||
public boolean updateAlgorithm(@RequestBody Algorithm algorithm) {
|
||||
algorithm.setModifier(currentUsername());
|
||||
algorithm.setUpdatedAt(LocalDateTime.now());
|
||||
@ -45,15 +52,57 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除算法(单条)", description = "根据算法ID删除算法")
|
||||
public boolean deleteAlgorithm(@PathVariable String id) {
|
||||
return algorithmService.removeById(id);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
@Operation(summary = "删除算法(批量)", description = "请求体传入算法ID列表,批量删除算法")
|
||||
public boolean deleteAlgorithms(@RequestBody List<String> ids) {
|
||||
return algorithmService.removeByIds(ids);
|
||||
}
|
||||
|
||||
//算法类型激活
|
||||
@PostMapping("/activate")
|
||||
@Operation(summary = "激活算法", description = "激活当前算法类型")
|
||||
public boolean activate(@RequestParam String algorithmId) {
|
||||
Algorithm algorithm = algorithmService.getById(algorithmId);
|
||||
if (algorithm == null) return false;
|
||||
// 先将当前算法类型激活
|
||||
algorithm.setStatus("1");
|
||||
algorithm.setModifier(currentUsername());
|
||||
algorithm.setUpdatedAt(LocalDateTime.now());
|
||||
return algorithmService.updateById(algorithm);
|
||||
}
|
||||
|
||||
//算法类型关闭
|
||||
@PostMapping("/unactivate")
|
||||
@Operation(summary = "关闭算法", description = "关闭当前算法类型")
|
||||
public boolean unactivate(@RequestParam String algorithmId) {
|
||||
Algorithm algorithm = algorithmService.getById(algorithmId);
|
||||
if (algorithm == null) return false;
|
||||
// 先将当前算法类型激活
|
||||
algorithm.setStatus("0");
|
||||
algorithm.setModifier(currentUsername());
|
||||
algorithm.setUpdatedAt(LocalDateTime.now());
|
||||
return algorithmService.updateById(algorithm);
|
||||
}
|
||||
|
||||
//获取激活的算法类型
|
||||
/**
|
||||
* 获取所有激活的算法类型
|
||||
* 输出参数:激活的算法类型列表
|
||||
* @return 激活的算法类型列表
|
||||
*/
|
||||
@GetMapping("/getActiveAlgorithms")
|
||||
@Operation(summary = "获取激活的算法类型", description = "返回所有激活的算法类型")
|
||||
public List<Algorithm> getActiveAlgorithms() {
|
||||
QueryWrapper<Algorithm> qw = new QueryWrapper<>();
|
||||
qw.eq("status", "1");
|
||||
return algorithmService.list(qw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据算法名称搜索并分页返回
|
||||
* 输入参数:查询参数 name(算法名称关键词,可为空),pageNum(页码,默认1),pageSize(每页条数,默认10)
|
||||
@ -64,6 +113,7 @@ public class AlgorithmController {
|
||||
* @return 算法分页列表
|
||||
*/
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "搜索算法并分页返回", description = "按名称关键词模糊查询,返回分页结果")
|
||||
public Page<Algorithm> searchAlgorithms(@RequestParam(required = false) String name,
|
||||
@RequestParam(defaultValue = "1") long pageNum,
|
||||
@RequestParam(defaultValue = "20") long pageSize) {
|
||||
|
||||
@ -3,7 +3,9 @@ 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.*;
|
||||
@ -11,24 +13,46 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
|
||||
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;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/algorithm-models")
|
||||
@Tag(name = "算法模型接口", description = "算法模型版本的增删改查、查询当前版本与在线训练")
|
||||
public class AlgorithmModelController {
|
||||
|
||||
@Autowired
|
||||
private AlgorithmModelService algorithmModelService;
|
||||
@Autowired
|
||||
private IUserService userService;
|
||||
@Autowired
|
||||
private AlgorithmService algorithmService;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "根据模型ID获取模型版本", description = "路径参数传入模型ID,返回模型版本对象")
|
||||
public AlgorithmModel getById(@PathVariable String id) {
|
||||
return algorithmModelService.getById(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "新增模型版本", description = "请求体传入模型版本对象,返回是否新增成功")
|
||||
public boolean create(@RequestBody AlgorithmModel model) {
|
||||
model.setModifier(currentUsername());
|
||||
model.setCreatedAt(LocalDateTime.now());
|
||||
@ -37,6 +61,7 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "修改模型版本", description = "请求体传入模型版本对象(需包含主键),返回是否修改成功")
|
||||
public boolean update(@RequestBody AlgorithmModel model) {
|
||||
model.setModifier(currentUsername());
|
||||
model.setUpdatedAt(LocalDateTime.now());
|
||||
@ -44,24 +69,31 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除模型版本(单条)", description = "根据模型ID删除模型版本")
|
||||
public boolean delete(@PathVariable String id) {
|
||||
return algorithmModelService.removeById(id);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
@Operation(summary = "删除模型版本(批量)", description = "请求体传入模型ID列表,批量删除模型版本")
|
||||
public boolean deleteBatch(@RequestBody List<String> ids) {
|
||||
return algorithmModelService.removeByIds(ids);
|
||||
}
|
||||
|
||||
//返回:该算法+设备类型的版本列表
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "查询模型版本列表", description = "按算法类型与设备类型过滤并分页返回模型版本")
|
||||
public Page<AlgorithmModel> search(@RequestParam(required = false) String algorithmType,
|
||||
@RequestParam(required = false) String deviceType,
|
||||
@RequestParam(required = false) String versionTag,
|
||||
@RequestParam(required = false) String isCurrent,
|
||||
@RequestParam(defaultValue = "1") long pageNum,
|
||||
@RequestParam(defaultValue = "20") long pageSize) {
|
||||
QueryWrapper<AlgorithmModel> qw = new QueryWrapper<>();
|
||||
if (algorithmType != null && !algorithmType.isEmpty()) qw.eq("algorithm_type", algorithmType);
|
||||
if (deviceType != null && !deviceType.isEmpty()) qw.eq("device_type", deviceType);
|
||||
if (versionTag != null && !versionTag.isEmpty()) qw.eq("version_tag", versionTag);
|
||||
if (isCurrent != null && !isCurrent.isEmpty()) qw.eq("is_current", isCurrent);
|
||||
qw.orderByDesc("updated_at");
|
||||
Page<AlgorithmModel> page = new Page<>(pageNum, pageSize, true);
|
||||
return algorithmModelService.page(page, qw);
|
||||
@ -69,6 +101,7 @@ public class AlgorithmModelController {
|
||||
|
||||
//返回:该算法+设备类型的当前激活版本
|
||||
@GetMapping("/current")
|
||||
@Operation(summary = "获取当前激活版本", description = "根据算法类型与设备类型,返回 is_current=1 的模型版本")
|
||||
public AlgorithmModel getCurrent(@RequestParam String algorithmType,
|
||||
@RequestParam String deviceType) {
|
||||
QueryWrapper<AlgorithmModel> qw = new QueryWrapper<>();
|
||||
@ -81,6 +114,7 @@ public class AlgorithmModelController {
|
||||
|
||||
//版本激活
|
||||
@PostMapping("/activate")
|
||||
@Operation(summary = "激活模型版本", description = "将目标模型版本设为当前,并将同组其他版本设为非当前")
|
||||
public boolean activate(@RequestParam String algorithmModelId) {
|
||||
AlgorithmModel model = algorithmModelService.getById(algorithmModelId);
|
||||
if (model == null) return false;
|
||||
@ -98,15 +132,122 @@ public class AlgorithmModelController {
|
||||
return algorithmModelService.updateById(model);
|
||||
}
|
||||
|
||||
//在线训练
|
||||
// 在线训练(Excel 数据集)
|
||||
@PostMapping("/train/excel")
|
||||
@Operation(summary = "在线训练(Excel)", description = "传入算法类型、设备类型与Excel路径,训练完成新增模型版本记录,可选激活")
|
||||
public Map<String, Object> trainExcel(@RequestBody Map<String, Object> body) {
|
||||
String algorithmType = str(body.get("algorithm_type"));
|
||||
String deviceType = str(body.get("device_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<String, Object> payload = new HashMap<>();
|
||||
payload.put("dataset_path", datasetPath);
|
||||
if (!isBlank(modelDir)) payload.put("model_dir", modelDir);
|
||||
Map<String, Object> 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<String, Object> 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.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<AlgorithmModel> qw = new QueryWrapper<>();
|
||||
qw.eq("algorithm_type", algorithmType).eq("device_type", deviceType);
|
||||
AlgorithmModel upd = new AlgorithmModel();
|
||||
upd.setIsCurrent(0);
|
||||
algorithmModelService.update(upd, qw);
|
||||
}
|
||||
algorithmModelService.save(model);
|
||||
return Map.of("code", 0, "msg", "训练成功", "data", model);
|
||||
}
|
||||
|
||||
@PostMapping("/train")
|
||||
public boolean train(@RequestParam String algorithmModelId) {
|
||||
AlgorithmModel model = algorithmModelService.getById(algorithmModelId);
|
||||
if (model == null) return false;
|
||||
// 调用训练接口
|
||||
// ...
|
||||
return true;
|
||||
// 在线训练(样本集合)
|
||||
@PostMapping("/train/samples")
|
||||
@Operation(summary = "在线训练(样本集合)", description = "传入算法类型、设备类型与样本集,训练完成新增模型版本记录,可选激活")
|
||||
public Map<String, Object> trainSamples(@RequestBody Map<String, Object> body) {
|
||||
String algorithmType = str(body.get("algorithm_type"));
|
||||
String deviceType = str(body.get("device_type"));
|
||||
Object samples = body.get("samples"); // 期望为 List<Map>,由前端提供
|
||||
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) || samples == null) {
|
||||
return Map.of("code", 1, "msg", "algorithm_type/device_type/samples 必填");
|
||||
}
|
||||
Algorithm algo = getAlgorithmByType(algorithmType);
|
||||
if (algo == null || isBlank(algo.getTrainBaseUrl())) {
|
||||
return Map.of("code", 1, "msg", "算法或训练URL未配置");
|
||||
}
|
||||
String url = "";//trimSlash(algo.getTrainBaseUrl()) + "/v1/train/" + deviceType + "/from-samples";
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("samples", samples);
|
||||
if (!isBlank(modelDir)) payload.put("model_dir", modelDir);
|
||||
Map<String, Object> resp = httpPostJson(url, payload);
|
||||
if (resp == null) return Map.of("code", 1, "msg", "训练接口无响应");
|
||||
int code = 0;//intVal(resp.get("code"));
|
||||
if (code != 0) return Map.of("code", 1, "msg", "训练失败: " + str(resp.get("msg")));
|
||||
Map<String, Object> 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.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<AlgorithmModel> qw = new QueryWrapper<>();
|
||||
qw.eq("algorithm_type", algorithmType).eq("device_type", deviceType);
|
||||
AlgorithmModel upd = new AlgorithmModel();
|
||||
upd.setIsCurrent(0);
|
||||
algorithmModelService.update(upd, qw);
|
||||
}
|
||||
algorithmModelService.save(model);
|
||||
return Map.of("code", 0, "msg", "训练成功", "data", model);
|
||||
}
|
||||
|
||||
|
||||
@ -121,4 +262,55 @@ public class AlgorithmModelController {
|
||||
return "anonymous";
|
||||
}
|
||||
}
|
||||
|
||||
private Algorithm getAlgorithmByType(String algorithmType) {
|
||||
QueryWrapper<Algorithm> qw = new QueryWrapper<>();
|
||||
qw.eq("algorithm_type", algorithmType);
|
||||
return algorithmService.getOne(qw);
|
||||
}
|
||||
|
||||
private Map<String, Object> httpPostJson(String url, Object payload) {
|
||||
try {
|
||||
String json = objectMapper.writeValueAsString(payload);
|
||||
HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build();
|
||||
HttpRequest req = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.header("Content-Type", "application/json")
|
||||
.timeout(Duration.ofSeconds(30))
|
||||
.POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8))
|
||||
.build();
|
||||
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
if (res.statusCode() >= 200 && res.statusCode() < 300) {
|
||||
return objectMapper.readValue(res.body(), new TypeReference<Map<String, Object>>() {});
|
||||
}
|
||||
return Map.of("code", 1, "msg", "HTTP " + res.statusCode());
|
||||
} catch (Exception e) {
|
||||
return Map.of("code", 1, "msg", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String genVersionTag() {
|
||||
return "v" + LocalDateTime.now().toString().replace(":", "-");
|
||||
}
|
||||
private String str(Object v) { return v == null ? "" : String.valueOf(v); }
|
||||
private boolean isBlank(String s) { return s == null || s.trim().isEmpty(); }
|
||||
private boolean bool(Object v) {
|
||||
if (v instanceof Boolean) return (Boolean) v;
|
||||
String s = str(v).toLowerCase();
|
||||
return "true".equals(s) || "1".equals(s) || "yes".equals(s);
|
||||
}
|
||||
private String toJson(Object v) {
|
||||
try {
|
||||
if (v == null) return null;
|
||||
if (v instanceof String) return (String) v;
|
||||
return objectMapper.writeValueAsString(v);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> castMap(Object v) {
|
||||
if (v instanceof Map) return (Map<String, Object>) v;
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,6 +285,21 @@ public class ProjectController {
|
||||
));
|
||||
}
|
||||
|
||||
//输入模拟数据,调用推理接口,得到推理结果并写入结果表
|
||||
@PostMapping("/simulation/run")
|
||||
@Operation(summary = "运行项目模拟", description = "输入模拟数据,调用推理接口,得到推理结果并写入结果表")
|
||||
public ResponseEntity<Map<String, Object>> runSimulation(@RequestParam @Parameter(description = "项目ID", required = true) String projectId,
|
||||
@RequestParam @Parameter(description = "情景ID", required = true) String scenarioId,
|
||||
@RequestBody(required = false) Map<String, Object> params) {
|
||||
var res = projectService.runSimulation(projectId, scenarioId, params == null ? Map.of() : params);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"code", 0,
|
||||
"msg", "运行完成",
|
||||
"data", res
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -9,57 +9,80 @@ import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 算法配置信息表
|
||||
* 存储算法的基本配置、参数和状态信息
|
||||
*/
|
||||
@Data
|
||||
@TableName("algorithm")
|
||||
public class Algorithm implements Serializable {
|
||||
|
||||
/** 序列化版本号 */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 算法ID - 主键,UUID生成 */
|
||||
@TableId(value = "algorithm_id", type = IdType.ASSIGN_UUID)
|
||||
private String algorithmId;
|
||||
|
||||
/** 算法类型 */
|
||||
@TableField("algorithm_type")
|
||||
private String algorithmType;
|
||||
|
||||
/** 算法名称 */
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
/** 算法描述 */
|
||||
@TableField("description")
|
||||
private String description;
|
||||
|
||||
/** 算法版本 - 版本号,例如v1.0 */
|
||||
@TableField("version")
|
||||
private String version;
|
||||
|
||||
/** 算法原理说明 */
|
||||
@TableField("principle")
|
||||
private String principle;
|
||||
|
||||
/** 调用参数 - 以JSON存储参数名称、类型、默认值等 */
|
||||
@TableField("input_params")
|
||||
private String inputParams;
|
||||
|
||||
/** 输出参数 - 以JSON存储参数名称、类型、说明等 */
|
||||
@TableField("output_params")
|
||||
private String outputParams;
|
||||
|
||||
/** 推理URL */
|
||||
@TableField("infer_base_url")
|
||||
private String inferBaseUrl;
|
||||
|
||||
/** 训练URL */
|
||||
@TableField("train_base_url")
|
||||
private String trainBaseUrl;
|
||||
|
||||
/** 支持设备类型 - JSON格式 */
|
||||
@TableField("supported_device_types")
|
||||
private String supportedDeviceTypes;
|
||||
|
||||
/** 默认超参 - JSON格式 */
|
||||
@TableField("default_hyper_params")
|
||||
private String defaultHyperParams;
|
||||
|
||||
/** 激活状态 - 1:激活;0:关闭 */
|
||||
@TableField("status")
|
||||
private String status;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField("updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/** 最后修改人 */
|
||||
@TableField("modifier")
|
||||
private String modifier;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -7,45 +7,65 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备临界数据表
|
||||
* 存储设备的临界数据信息,包括几何参数、材料特性和k_eff值
|
||||
*/
|
||||
@Data
|
||||
@TableName("critical_data")
|
||||
public class CriticalData implements Serializable {
|
||||
|
||||
/** 序列化版本号 */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 临界数据主键 */
|
||||
@TableId(value = "critical_id", type = IdType.ASSIGN_UUID)
|
||||
private String criticalId;
|
||||
|
||||
/** 设备类型 */
|
||||
@TableField("device_type")
|
||||
private String deviceType;
|
||||
|
||||
/** 等效直径 */
|
||||
@TableField("diameter")
|
||||
private BigDecimal diameter;
|
||||
|
||||
/** 等效高度 */
|
||||
@TableField("height")
|
||||
private BigDecimal height;
|
||||
|
||||
/** 核材料浓度(U 或 Pu) */
|
||||
@TableField("fissile_concentration")
|
||||
private BigDecimal fissileConcentration;
|
||||
|
||||
/** 同位素丰度(铀富集度 或 Pu-240 占比) */
|
||||
@TableField("isotopic_abundance")
|
||||
private BigDecimal isotopicAbundance;
|
||||
|
||||
/** 扩展物理/算法特征 - JSON格式 */
|
||||
@TableField("extra_features")
|
||||
private String extraFeatures;
|
||||
|
||||
/** 对应 k_eff 值 */
|
||||
@TableField("keff_value")
|
||||
private BigDecimal keffValue;
|
||||
|
||||
/** 属性状态 - JSON格式 */
|
||||
@TableField("attr_state")
|
||||
private String attrState;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/** 最后更新时间 */
|
||||
@TableField("updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
/** 最后修改人 */
|
||||
@TableField("modifier")
|
||||
private String modifier;
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -32,11 +31,9 @@ public class Project implements Serializable {
|
||||
private String topology;
|
||||
|
||||
@TableField("created_at")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@TableField("updated_at")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@TableField("modifier")
|
||||
|
||||
@ -11,6 +11,6 @@ public class EventAttrParseResult {
|
||||
private Map<String, String> target;
|
||||
private String unit;
|
||||
private List<EventAttrSegment> segments;
|
||||
private List<Map<String, Object>> schedule; // optional derived ramp/step
|
||||
private List<Map<String, Object>> schedule;
|
||||
private List<String> issues;
|
||||
}
|
||||
@ -10,6 +10,6 @@ public class TopoEdge {
|
||||
private String toEntityType;
|
||||
private String toEntityId;
|
||||
private String toProperty;
|
||||
private Double coefficient;
|
||||
private Long delayMs;
|
||||
private double coefficient;
|
||||
private long delayMs;
|
||||
}
|
||||
@ -8,11 +8,11 @@ import java.util.Map;
|
||||
@Data
|
||||
public class TopologyParseResult {
|
||||
private String projectId;
|
||||
private Integer deviceCount;
|
||||
private Integer nodeCount;
|
||||
private Integer edgeCount;
|
||||
private List<TopoNode> nodes;
|
||||
private List<TopoEdge> edges;
|
||||
private List<Map<String, Object>> plans;
|
||||
private List<String> issues;
|
||||
private int deviceCount;
|
||||
private int nodeCount;
|
||||
private int edgeCount;
|
||||
}
|
||||
@ -2,8 +2,7 @@ package com.yfd.business.css.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yfd.business.css.domain.AlgorithmModel;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface AlgorithmModelMapper extends BaseMapper<AlgorithmModel> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.yfd.business.css.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class DeviceStepInfo {
|
||||
private String deviceId;
|
||||
private String deviceType;
|
||||
private Map<String, Object> properties;
|
||||
private int step;
|
||||
private int time;
|
||||
|
||||
public DeviceStepInfo() {}
|
||||
|
||||
public DeviceStepInfo(String deviceId, String deviceType, Map<String, Object> properties,int step,int time) {
|
||||
this.deviceId = deviceId;
|
||||
this.deviceType = deviceType;
|
||||
this.properties = properties;
|
||||
this.step = step;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
// Getter和Setter方法
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, Object> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public int getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public void setStep(int step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
public int getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(int time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceStepInfo{" +
|
||||
"deviceId='" + deviceId + '\'' +
|
||||
", deviceType='" + deviceType + '\'' +
|
||||
", properties=" + properties +
|
||||
", step=" + step +
|
||||
", time=" + time +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.yfd.business.css.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class InferRequest {
|
||||
private String modelDir;
|
||||
private String deviceType;
|
||||
private List<Map<String, Object>> batch;
|
||||
private Map<String, Object> features;
|
||||
private Map<String, Object> meta;
|
||||
|
||||
public InferRequest() {}
|
||||
|
||||
// Getter和Setter方法
|
||||
public String getModelDir() { return modelDir; }
|
||||
public void setModelDir(String modelDir) { this.modelDir = modelDir; }
|
||||
public String getDeviceType() { return deviceType; }
|
||||
public void setDeviceType(String deviceType) { this.deviceType = deviceType; }
|
||||
public List<Map<String, Object>> getBatch() { return batch; }
|
||||
public void setBatch(List<Map<String, Object>> batch) { this.batch = batch; }
|
||||
public Map<String, Object> getFeatures() { return features; }
|
||||
public void setFeatures(Map<String, Object> features) { this.features = features; }
|
||||
public Map<String, Object> getMeta() { return meta; }
|
||||
public void setMeta(Map<String, Object> meta) { this.meta = meta; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InferRequest{" +
|
||||
"modelDir='" + modelDir + '\'' +
|
||||
", deviceType='" + deviceType + '\'' +
|
||||
", batch=" + batch +
|
||||
", features=" + features +
|
||||
", meta=" + meta +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.yfd.business.css.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class InferResponse {
|
||||
private int code;
|
||||
private String msg;
|
||||
private InferData data;
|
||||
|
||||
public static class InferData {
|
||||
private List<InferItem> items;
|
||||
private Map<String, Object> meta;
|
||||
private Map<String, Object> features;
|
||||
private BigDecimal keff;
|
||||
|
||||
// Getter和Setter方法
|
||||
public List<InferItem> getItems() { return items; }
|
||||
public void setItems(List<InferItem> items) { this.items = items; }
|
||||
public Map<String, Object> getMeta() { return meta; }
|
||||
public void setMeta(Map<String, Object> meta) { this.meta = meta; }
|
||||
public Map<String, Object> getFeatures() { return features; }
|
||||
public void setFeatures(Map<String, Object> features) { this.features = features; }
|
||||
public BigDecimal getKeff() { return keff; }
|
||||
public void setKeff(BigDecimal keff) { this.keff = keff; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InferData{" +
|
||||
"items=" + items +
|
||||
", meta=" + meta +
|
||||
", features=" + features +
|
||||
", keff=" + keff +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class InferItem {
|
||||
private Map<String, Object> meta;
|
||||
private Map<String, Object> features;
|
||||
private BigDecimal keff;
|
||||
|
||||
// Getter和Setter方法
|
||||
public Map<String, Object> getMeta() { return meta; }
|
||||
public void setMeta(Map<String, Object> meta) { this.meta = meta; }
|
||||
public Map<String, Object> getFeatures() { return features; }
|
||||
public void setFeatures(Map<String, Object> features) { this.features = features; }
|
||||
public BigDecimal getKeff() { return keff; }
|
||||
public void setKeff(BigDecimal keff) { this.keff = keff; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InferItem{" +
|
||||
"meta=" + meta +
|
||||
", features=" + features +
|
||||
", keff=" + keff +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
// Getter和Setter方法
|
||||
public int getCode() { return code; }
|
||||
public void setCode(int code) { this.code = code; }
|
||||
public String getMsg() { return msg; }
|
||||
public void setMsg(String msg) { this.msg = msg; }
|
||||
public InferData getData() { return data; }
|
||||
public void setData(InferData data) { this.data = data; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InferResponse{" +
|
||||
"code=" + code +
|
||||
", msg='" + msg + '\'' +
|
||||
", data=" + data +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@ -4,4 +4,14 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yfd.business.css.domain.AlgorithmModel;
|
||||
|
||||
public interface AlgorithmModelService extends IService<AlgorithmModel> {
|
||||
|
||||
/**
|
||||
* 根据算法类型、设备类型,获取当前激活的模型路径
|
||||
*
|
||||
* @param algorithmType 算法类型(如GPR/MLP/FastRBF)
|
||||
* @param deviceType 设备类型(如CylindricalTank/AnnularTank)
|
||||
* @return 激活版本的模型文件路径,如果不存在则返回null
|
||||
*/
|
||||
String getCurrentModelPath(String algorithmType, String deviceType) ;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,175 @@
|
||||
package com.yfd.business.css.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.yfd.business.css.domain.ScenarioResult;
|
||||
import com.yfd.business.css.model.DeviceStepInfo;
|
||||
import com.yfd.business.css.model.InferRequest;
|
||||
import com.yfd.business.css.model.InferResponse;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
@Service
|
||||
public class DeviceInferService {
|
||||
@Value("${python.api.url:http://localhost:8000}")
|
||||
private String pythonInferUrl;
|
||||
|
||||
@Resource
|
||||
private ScenarioService scenarioService;
|
||||
@Resource
|
||||
private AlgorithmModelService algorithmModelService;
|
||||
@Resource
|
||||
private ScenarioResultService scenarioResultService;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
public void processDeviceInference(String projectId, String scenarioId,
|
||||
Map<String, List<DeviceStepInfo>> groupedDevices) {
|
||||
// 遍历每个设备类型,调用对应的模型进行推理
|
||||
for (Map.Entry<String, List<DeviceStepInfo>> entry : groupedDevices.entrySet()) {
|
||||
String deviceType = entry.getKey();
|
||||
// algorithmType通过scenarioId获取
|
||||
String algorithmType = scenarioService.getAlgorithmType(scenarioId);
|
||||
if (algorithmType == null) {
|
||||
throw new IllegalArgumentException("场景 " + scenarioId + " 未配置算法类型");
|
||||
}
|
||||
|
||||
//modelPath根据模型类型、设备类型,从algorithm_model获取活动的model_path
|
||||
String modelPath = algorithmModelService.getCurrentModelPath(algorithmType, deviceType);
|
||||
System.out.println("modelPath="+modelPath);
|
||||
if (modelPath == null) {
|
||||
throw new IllegalArgumentException("未配置 " + algorithmType + " 模型路径");
|
||||
}
|
||||
List<DeviceStepInfo> devices = entry.getValue();
|
||||
System.out.println("devices="+devices);
|
||||
// 校验设备数据是否完整
|
||||
if (devices == null || devices.isEmpty()) {
|
||||
throw new IllegalArgumentException("设备数据为空,无法进行模拟");
|
||||
}
|
||||
|
||||
// 封装推理请求
|
||||
InferRequest request = buildInferenceRequest(deviceType,devices,modelPath);
|
||||
System.out.println("request="+request);
|
||||
|
||||
// 调用Python推理服务
|
||||
InferResponse response = infer(request);
|
||||
System.out.println("推理服务返回结果: " + response);
|
||||
|
||||
// 处理推理结果
|
||||
if (response != null && response.getCode() == 0) {
|
||||
// 重新构建InferResponse对象示例
|
||||
// 1. 从response获取数据
|
||||
int code = response.getCode();
|
||||
String msg = response.getMsg();
|
||||
InferResponse.InferData originalData = response.getData();
|
||||
|
||||
// 2. 重新构建InferData
|
||||
InferResponse.InferData newData = new InferResponse.InferData();
|
||||
newData.setItems(originalData.getItems());
|
||||
newData.setMeta(originalData.getMeta());
|
||||
newData.setFeatures(originalData.getFeatures());
|
||||
newData.setKeff(originalData.getKeff());
|
||||
|
||||
// 3. 构建新的InferResponse
|
||||
InferResponse reconstructedResponse = new InferResponse();
|
||||
reconstructedResponse.setCode(code);
|
||||
reconstructedResponse.setMsg(msg);
|
||||
reconstructedResponse.setData(newData);
|
||||
|
||||
System.out.println("重新构建的response: " + reconstructedResponse);
|
||||
|
||||
// 使用重新构建的response处理结果
|
||||
processInferenceResults(projectId, scenarioId, deviceType, devices, reconstructedResponse);
|
||||
} else {
|
||||
throw new RuntimeException("推理服务调用失败: " + (response != null ? response.getMsg() : "未知错误"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InferRequest buildInferenceRequest(String deviceType,List<DeviceStepInfo> devices,String modelPath) {
|
||||
InferRequest request = new InferRequest();
|
||||
request.setModelDir(modelPath); // 设置模型路径
|
||||
request.setDeviceType(deviceType);
|
||||
|
||||
// 构建批量推理数据
|
||||
List<Map<String, Object>> batchData = new ArrayList<>();
|
||||
for (DeviceStepInfo device : devices) {
|
||||
Map<String, Object> deviceData = new HashMap<>();
|
||||
deviceData.put("features", device.getProperties());
|
||||
deviceData.put("meta", buildDeviceMeta(device));
|
||||
batchData.add(deviceData);
|
||||
}
|
||||
|
||||
// 设置批量数据到请求中
|
||||
request.setBatch(batchData);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildDeviceMeta(DeviceStepInfo device) {
|
||||
Map<String, Object> meta = new HashMap<>();
|
||||
meta.put("deviceId", device.getDeviceId());
|
||||
meta.put("deviceType", device.getDeviceType());
|
||||
meta.put("step", device.getStep());
|
||||
meta.put("time", device.getTime());
|
||||
return meta;
|
||||
}
|
||||
|
||||
private void processInferenceResults(String projectId, String scenarioId, String deviceType,
|
||||
List<DeviceStepInfo> devices, InferResponse response) {
|
||||
// 处理推理结果,例如写入数据库
|
||||
List<InferResponse.InferItem> items = response.getData().getItems();
|
||||
List<ScenarioResult> inferenceResults = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
InferResponse.InferItem item = items.get(i);
|
||||
//DeviceStepInfo device = devices.get(i);
|
||||
|
||||
ScenarioResult result = new ScenarioResult();
|
||||
//result.put("projectId", projectId);
|
||||
result.setScenarioId(scenarioId);
|
||||
//result.put("deviceType", deviceType);
|
||||
result.setDeviceId((String) item.getMeta().get("deviceId"));
|
||||
result.setKeffValue(item.getKeff());
|
||||
// 将 Map<String,Object> 转为 JSON 字符串后再设置
|
||||
try {
|
||||
Map<String, Object> features = item.getFeatures();
|
||||
String featuresJson = objectMapper.writeValueAsString(features);
|
||||
result.setAttrState(featuresJson);
|
||||
} catch (Exception e) {
|
||||
result.setAttrState("{}");
|
||||
}
|
||||
//result.put("meta", item.getMeta());
|
||||
result.setStep((Integer) item.getMeta().get("time"));
|
||||
|
||||
inferenceResults.add(result);
|
||||
}
|
||||
|
||||
|
||||
scenarioResultService.saveBatch(inferenceResults);
|
||||
System.out.println("保存推理结果: " + inferenceResults.size() + " 条记录");
|
||||
}
|
||||
|
||||
// 合并的Python推理调用方法
|
||||
public InferResponse infer(InferRequest request) {
|
||||
String url = pythonInferUrl + "/v1/infer" ;
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
HttpEntity<InferRequest> entity = new HttpEntity<>(request, headers);
|
||||
ResponseEntity<InferResponse> response = restTemplate.postForEntity(url, entity, InferResponse.class);
|
||||
return response.getBody();
|
||||
}
|
||||
}
|
||||
@ -35,4 +35,13 @@ public interface ProjectService extends IService<Project> {
|
||||
|
||||
java.util.List<java.util.Map<String, Object>> parseDeviceOrderWithMaterials(String projectId);
|
||||
|
||||
/**
|
||||
* 运行项目模拟
|
||||
* @param projectId 项目ID
|
||||
* @param scenarioId 情景ID
|
||||
* @param params 模拟参数
|
||||
* @return 模拟结果
|
||||
*/
|
||||
java.util.Map<String, Object> runSimulation(String projectId, String scenarioId, java.util.Map<String, Object> params);
|
||||
|
||||
}
|
||||
|
||||
@ -4,4 +4,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yfd.business.css.domain.Scenario;
|
||||
|
||||
public interface ScenarioService extends IService<Scenario> {
|
||||
//根据场景id,获取算法类型
|
||||
String getAlgorithmType(String scenarioId);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.yfd.business.css.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yfd.business.css.domain.AlgorithmModel;
|
||||
import com.yfd.business.css.mapper.AlgorithmModelMapper;
|
||||
@ -8,4 +9,14 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AlgorithmModelServiceImpl extends ServiceImpl<AlgorithmModelMapper, AlgorithmModel> implements AlgorithmModelService {
|
||||
|
||||
@Override
|
||||
public String getCurrentModelPath(String algorithmType, String deviceType) {
|
||||
QueryWrapper<AlgorithmModel> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("algorithm_type", algorithmType)
|
||||
.eq("device_type", deviceType)
|
||||
.eq("is_current", 1); // 当前激活版本
|
||||
AlgorithmModel model = getOne(queryWrapper);
|
||||
return model != null ? model.getModelPath() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ import org.springframework.stereotype.Service;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.yfd.business.css.domain.Device;
|
||||
import com.yfd.business.css.domain.Material;
|
||||
@ -17,6 +19,9 @@ import com.yfd.business.css.domain.ScenarioResult;
|
||||
import com.yfd.business.css.service.DeviceService;
|
||||
import com.yfd.business.css.service.MaterialService;
|
||||
import com.yfd.business.css.service.ScenarioService;
|
||||
import com.yfd.business.css.service.DeviceInferService;
|
||||
import com.yfd.business.css.utils.DeviceDataParser;
|
||||
import com.yfd.business.css.model.DeviceStepInfo;
|
||||
import com.yfd.business.css.service.EventService;
|
||||
import com.yfd.business.css.service.ScenarioResultService;
|
||||
import com.yfd.business.css.dto.TopologyParseResult;
|
||||
@ -31,8 +36,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
@ -55,6 +59,15 @@ public class ProjectServiceImpl
|
||||
private EventService eventService;
|
||||
@Resource
|
||||
private ScenarioResultService scenarioResultService;
|
||||
@Resource
|
||||
private DeviceInferService deviceInferService;
|
||||
// 通过构造函数注入DeviceDataParser
|
||||
@SuppressWarnings("unused")
|
||||
private final DeviceDataParser deviceDataParser;
|
||||
|
||||
public ProjectServiceImpl(DeviceDataParser deviceDataParser) {
|
||||
this.deviceDataParser = deviceDataParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] exportAllProjectsExcel() {
|
||||
@ -1221,4 +1234,59 @@ public class ProjectServiceImpl
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//运行项目模拟
|
||||
@Override
|
||||
public java.util.Map<String, Object> runSimulation(String projectId, String scenarioId, java.util.Map<String, Object> params) {
|
||||
//1. 校验项目是否存在
|
||||
Project project = this.getOne(new LambdaQueryWrapper<Project>().eq(Project::getProjectId, projectId));
|
||||
if (project == null) throw new IllegalArgumentException("项目不存在");
|
||||
//2. 校验情景是否存在
|
||||
Scenario scenario = scenarioService.getOne(new LambdaQueryWrapper<Scenario>().eq(Scenario::getScenarioId, scenarioId));
|
||||
if (scenario == null) throw new IllegalArgumentException("情景不存在");
|
||||
//获取该情景对应的算法类型
|
||||
String algorithmType = scenario.getAlgorithmType();
|
||||
if (algorithmType == null) throw new IllegalArgumentException("情景未指定算法类型");
|
||||
//3. 校验模拟参数是否完整
|
||||
if (params == null || params.isEmpty()) throw new IllegalArgumentException("模拟参数不能为空");
|
||||
//4. 解析模拟参数,生成模拟数据
|
||||
// 使用 Jackson 将 Map 转为 JSON 字符串
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
String jsonParams;
|
||||
try {
|
||||
jsonParams = objectMapper.writeValueAsString(params);
|
||||
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
|
||||
throw new RuntimeException("模拟参数序列化失败", e);
|
||||
}
|
||||
// 解析并按设备类型分组,后续批量推理将依赖此结果
|
||||
System.out.println("projectId="+projectId);
|
||||
System.out.println("scenarioId="+scenarioId);
|
||||
System.out.println("params="+params);
|
||||
System.out.println("jsonParams="+jsonParams);
|
||||
|
||||
jsonParams ="{\"data\":{\"frames\":[{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":160.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":160.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":20.0,\"u_enrichment\":0.01,\"height\":20.0,\"u_concentration\":20.0}},\"step\":0,\"time\":0},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":170.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":170.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":50.0,\"u_enrichment\":0.01,\"height\":50.0,\"u_concentration\":20.0}},\"step\":1,\"time\":2},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":180.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":180.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":70.0,\"u_enrichment\":0.01,\"height\":70.0,\"u_concentration\":20.0}},\"step\":2,\"time\":4},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":190.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":190.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":100.0,\"u_enrichment\":0.01,\"height\":100.0,\"u_concentration\":20.0}},\"step\":3,\"time\":6},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":200.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":200.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":120.0,\"u_enrichment\":0.01,\"height\":120.0,\"u_concentration\":20.0}},\"step\":4,\"time\":8},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":210.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":210.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":150.0,\"u_enrichment\":0.01,\"height\":150.0,\"u_concentration\":20.0}},\"step\":5,\"time\":10},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":220.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":220.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":200.0,\"u_enrichment\":0.01,\"height\":200.0,\"u_concentration\":20.0}},\"step\":6,\"time\":12},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":230.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":230.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":220.0,\"u_enrichment\":0.01,\"height\":220.0,\"u_concentration\":20.0}},\"step\":7,\"time\":14},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":240.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":240.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":250.0,\"u_enrichment\":0.01,\"height\":250.0,\"u_concentration\":20.0}},\"step\":8,\"time\":16},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":250.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":250.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":300.0,\"u_enrichment\":0.01,\"height\":300.0,\"u_concentration\":20.0}},\"step\":9,\"time\":18}],\"generated\":{\"snapshots\":20,\"events\":2},\"projectId\":\"proj-0001-uuid\",\"scenarioId\":\"scen-001-uuid\",\"issues\":[]}}";
|
||||
|
||||
Map<String, List<DeviceStepInfo>> groupedDevices = DeviceDataParser.parseAndGroupDeviceData(jsonParams);
|
||||
if (groupedDevices == null || groupedDevices.isEmpty()) {
|
||||
throw new IllegalArgumentException("解析后的设备数据为空,无法进行模拟");
|
||||
}
|
||||
|
||||
// 输出结果
|
||||
for (Map.Entry<String, List<DeviceStepInfo>> entry : groupedDevices.entrySet()) {
|
||||
System.out.println("Device Type: " + entry.getKey());
|
||||
for (DeviceStepInfo device : entry.getValue()) {
|
||||
System.out.println(" " + device);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
//6. 调用模型进行推理
|
||||
deviceInferService.processDeviceInference(projectId, scenarioId, groupedDevices);
|
||||
|
||||
|
||||
//var res = inferenceService.runInference(projectId, scenarioId, params);
|
||||
//5. 写入结果表
|
||||
//scenarioResultMapper.insertBatch(res);
|
||||
return Map.of();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,4 +10,12 @@ import org.springframework.stereotype.Service;
|
||||
public class ScenarioServiceImpl
|
||||
extends ServiceImpl<ScenarioMapper, Scenario>
|
||||
implements ScenarioService {
|
||||
@Override
|
||||
public String getAlgorithmType(String scenarioId) {
|
||||
Scenario scenario = baseMapper.selectById(scenarioId);
|
||||
if (scenario == null) {
|
||||
return null;
|
||||
}
|
||||
return scenario.getAlgorithmType();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,150 @@
|
||||
package com.yfd.business.css.utils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.yfd.business.css.model.DeviceStepInfo;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Component // 添加注解
|
||||
public class DeviceDataParser {
|
||||
|
||||
|
||||
|
||||
public static Map<String, List<DeviceStepInfo>> parseAndGroupDeviceData(String jsonData) {
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode rootNode = mapper.readTree(jsonData);
|
||||
JsonNode framesNode = rootNode.get("data").get("frames");
|
||||
|
||||
List<DeviceStepInfo> allDevices = new ArrayList<>();
|
||||
|
||||
for (JsonNode frameNode : framesNode) {
|
||||
int step = frameNode.get("step").asInt();
|
||||
int time = frameNode.get("time").asInt();
|
||||
JsonNode devicesNode = frameNode.get("devices");
|
||||
|
||||
Iterator<Map.Entry<String, JsonNode>> devices = devicesNode.fields();
|
||||
while (devices.hasNext()) {
|
||||
Map.Entry<String, JsonNode> deviceEntry = devices.next();
|
||||
String deviceId = deviceEntry.getKey();
|
||||
JsonNode deviceInfo = deviceEntry.getValue();
|
||||
|
||||
String deviceType = deviceInfo.get("deviceType").asText();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
|
||||
Iterator<Map.Entry<String, JsonNode>> fields = deviceInfo.fields();
|
||||
while (fields.hasNext()) {
|
||||
Map.Entry<String, JsonNode> field = fields.next();
|
||||
String fieldName = field.getKey();
|
||||
JsonNode fieldValue = field.getValue();
|
||||
|
||||
if (!"deviceType".equals(fieldName)) {
|
||||
if (fieldValue.isDouble() || fieldValue.isFloat()) {
|
||||
properties.put(fieldName, fieldValue.asDouble());
|
||||
} else if (fieldValue.isInt()) {
|
||||
properties.put(fieldName, fieldValue.asInt());
|
||||
} else {
|
||||
properties.put(fieldName, fieldValue.asText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allDevices.add(new DeviceStepInfo(deviceId, deviceType, properties, step, time));
|
||||
}
|
||||
}
|
||||
|
||||
// 按设备类型分组
|
||||
return allDevices.stream()
|
||||
.collect(Collectors.groupingBy(DeviceStepInfo::getDeviceType));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// String jsonData = "{\n" +
|
||||
// " \"data\": {\n" +
|
||||
// " \"frames\": [\n" +
|
||||
// " {\n" +
|
||||
// " \"devices\": {\n" +
|
||||
// " \"dev-003-uuid\": {\n" +
|
||||
// " \"deviceType\": \"AnnularTank\",\n" +
|
||||
// " \"diameter\": 160.0,\n" +
|
||||
// " \"pu_isotope\": 0.13,\n" +
|
||||
// " \"pu_concentration\": 20.0,\n" +
|
||||
// " \"height\": 160.0\n" +
|
||||
// " },\n" +
|
||||
// " \"dev-002-uuid\": {\n" +
|
||||
// " \"deviceType\": \"CylindricalTank\",\n" +
|
||||
// " \"diameter\": 20.0,\n" +
|
||||
// " \"u_enrichment\": 0.01,\n" +
|
||||
// " \"height\": 20.0,\n" +
|
||||
// " \"u_concentration\": 20.0\n" +
|
||||
// " }\n" +
|
||||
// " },\n" +
|
||||
// " \"step\": 0,\n" +
|
||||
// " \"time\": 0\n" +
|
||||
// " },\n" +
|
||||
// " {\n" +
|
||||
// " \"devices\": {\n" +
|
||||
// " \"dev-003-uuid\": {\n" +
|
||||
// " \"deviceType\": \"AnnularTank\",\n" +
|
||||
// " \"diameter\": 170.0,\n" +
|
||||
// " \"pu_isotope\": 0.13,\n" +
|
||||
// " \"pu_concentration\": 20.0,\n" +
|
||||
// " \"height\": 170.0\n" +
|
||||
// " },\n" +
|
||||
// " \"dev-002-uuid\": {\n" +
|
||||
// " \"deviceType\": \"CylindricalTank\",\n" +
|
||||
// " \"diameter\": 50.0,\n" +
|
||||
// " \"u_enrichment\": 0.01,\n" +
|
||||
// " \"height\": 50.0,\n" +
|
||||
// " \"u_concentration\": 20.0\n" +
|
||||
// " }\n" +
|
||||
// " },\n" +
|
||||
// " \"step\": 1,\n" +
|
||||
// " \"time\": 2\n" +
|
||||
// " },\n" +
|
||||
// " {\n" +
|
||||
// " \"devices\": {\n" +
|
||||
// " \"dev-003-uuid\": {\n" +
|
||||
// " \"deviceType\": \"AnnularTank\",\n" +
|
||||
// " \"diameter\": 180.0,\n" +
|
||||
// " \"pu_isotope\": 0.13,\n" +
|
||||
// " \"pu_concentration\": 20.0,\n" +
|
||||
// " \"height\": 180.0\n" +
|
||||
// " },\n" +
|
||||
// " \"dev-002-uuid\": {\n" +
|
||||
// " \"deviceType\": \"CylindricalTank\",\n" +
|
||||
// " \"diameter\": 70.0,\n" +
|
||||
// " \"u_enrichment\": 0.01,\n" +
|
||||
// " \"height\": 70.0,\n" +
|
||||
// " \"u_concentration\": 20.0\n" +
|
||||
// " }\n" +
|
||||
// " },\n" +
|
||||
// " \"step\": 2,\n" +
|
||||
// " \"time\": 4\n" +
|
||||
// " }\n" +
|
||||
// " ]\n" +
|
||||
// " }\n" +
|
||||
// "}";
|
||||
// String jsonData = "{\"data\":{\"frames\":[{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":160.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":160.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":20.0,\"u_enrichment\":0.01,\"height\":20.0,\"u_concentration\":20.0}},\"step\":0,\"time\":0},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":170.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":170.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":50.0,\"u_enrichment\":0.01,\"height\":50.0,\"u_concentration\":20.0}},\"step\":1,\"time\":2},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":180.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":180.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":70.0,\"u_enrichment\":0.01,\"height\":70.0,\"u_concentration\":20.0}},\"step\":2,\"time\":4},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":190.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":190.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":100.0,\"u_enrichment\":0.01,\"height\":100.0,\"u_concentration\":20.0}},\"step\":3,\"time\":6},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":200.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":200.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":120.0,\"u_enrichment\":0.01,\"height\":120.0,\"u_concentration\":20.0}},\"step\":4,\"time\":8},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":210.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":210.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":150.0,\"u_enrichment\":0.01,\"height\":150.0,\"u_concentration\":20.0}},\"step\":5,\"time\":10},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":220.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":220.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":200.0,\"u_enrichment\":0.01,\"height\":200.0,\"u_concentration\":20.0}},\"step\":6,\"time\":12},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":230.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":230.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":220.0,\"u_enrichment\":0.01,\"height\":220.0,\"u_concentration\":20.0}},\"step\":7,\"time\":14},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":240.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":240.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":250.0,\"u_enrichment\":0.01,\"height\":250.0,\"u_concentration\":20.0}},\"step\":8,\"time\":16},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":250.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":250.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":300.0,\"u_enrichment\":0.01,\"height\":300.0,\"u_concentration\":20.0}},\"step\":9,\"time\":18}],\"generated\":{\"snapshots\":20,\"events\":2},\"projectId\":\"proj-0001-uuid\",\"scenarioId\":\"scen-001-uuid\",\"issues\":[]}}";
|
||||
String jsonData = "{\"data\":{\"frames\":[{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":160.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":160.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":20.0,\"u_enrichment\":0.01,\"height\":20.0,\"u_concentration\":20.0}},\"step\":0,\"time\":0},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":170.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":170.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":50.0,\"u_enrichment\":0.01,\"height\":50.0,\"u_concentration\":20.0}},\"step\":1,\"time\":2},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":180.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":180.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":70.0,\"u_enrichment\":0.01,\"height\":70.0,\"u_concentration\":20.0}},\"step\":2,\"time\":4},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":190.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":190.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":100.0,\"u_enrichment\":0.01,\"height\":100.0,\"u_concentration\":20.0}},\"step\":3,\"time\":6},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":200.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":200.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":120.0,\"u_enrichment\":0.01,\"height\":120.0,\"u_concentration\":20.0}},\"step\":4,\"time\":8},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":210.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":210.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":150.0,\"u_enrichment\":0.01,\"height\":150.0,\"u_concentration\":20.0}},\"step\":5,\"time\":10},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":220.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":220.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":200.0,\"u_enrichment\":0.01,\"height\":200.0,\"u_concentration\":20.0}},\"step\":6,\"time\":12},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":230.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":230.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":220.0,\"u_enrichment\":0.01,\"height\":220.0,\"u_concentration\":20.0}},\"step\":7,\"time\":14},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":240.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":240.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":250.0,\"u_enrichment\":0.01,\"height\":250.0,\"u_concentration\":20.0}},\"step\":8,\"time\":16},{\"devices\":{\"dev-003-uuid\":{\"deviceType\":\"AnnularTank\",\"diameter\":250.0,\"pu_isotope\":0.13,\"pu_concentration\":20.0,\"height\":250.0},\"dev-002-uuid\":{\"deviceType\":\"CylindricalTank\",\"diameter\":300.0,\"u_enrichment\":0.01,\"height\":300.0,\"u_concentration\":20.0}},\"step\":9,\"time\":18}],\"generated\":{\"snapshots\":20,\"events\":2},\"projectId\":\"proj-0001-uuid\",\"scenarioId\":\"scen-001-uuid\",\"issues\":[]}} ";
|
||||
System.out.println("jsonData="+jsonData);
|
||||
Map<String, List<DeviceStepInfo>> groupedDevices = parseAndGroupDeviceData(jsonData);
|
||||
|
||||
// 输出结果
|
||||
for (Map.Entry<String, List<DeviceStepInfo>> entry : groupedDevices.entrySet()) {
|
||||
System.out.println("Device Type: " + entry.getKey());
|
||||
for (DeviceStepInfo device : entry.getValue()) {
|
||||
System.out.println(" " + device);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
com.yfd.business.css.config.BusinessCssAutoConfiguration
|
||||
@ -27,3 +27,6 @@ logging:
|
||||
level:
|
||||
root: INFO
|
||||
|
||||
python:
|
||||
api:
|
||||
url: http://localhost:8000
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
server:
|
||||
port: 8091
|
||||
spring:
|
||||
application:
|
||||
name: business-css
|
||||
datasource:
|
||||
driver-class-name: org.h2.Driver
|
||||
url: jdbc:h2:mem:cssdb;MODE=MySQL;DB_CLOSE_DELAY=-1
|
||||
username: sa
|
||||
password:
|
||||
sql:
|
||||
init:
|
||||
mode: never
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
cache-enabled: false
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: assign_uuid
|
||||
@ -69,9 +69,7 @@ public class SimulationInitTest {
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
String initBody = "{\"startTime\":0,\"endTime\":18,\"step\":2}";
|
||||
String initResp = mockMvc.perform(MockMvcRequestBuilders.post("/projects/simulation/init")
|
||||
.param("projectId", projectId)
|
||||
.param("scenarioId", scenarioId)
|
||||
String initResp = mockMvc.perform(MockMvcRequestBuilders.post("/projects/" + projectId + "/scenarios/" + scenarioId + "/simulation/init")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(initBody))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
@ -97,9 +95,7 @@ public class SimulationInitTest {
|
||||
String projectId = "proj-0001-uuid";
|
||||
String scenarioId = "scen-001-uuid";
|
||||
String initBody = "{\"startTime\":0,\"endTime\":10,\"step\":2}";
|
||||
String initResp = mockMvc.perform(MockMvcRequestBuilders.post("/projects/simulation/init")
|
||||
.param("projectId", projectId)
|
||||
.param("scenarioId", scenarioId)
|
||||
String initResp = mockMvc.perform(MockMvcRequestBuilders.post("/projects/" + projectId + "/scenarios/" + scenarioId + "/simulation/init")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(initBody))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
@ -118,35 +114,4 @@ public class SimulationInitTest {
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value(0))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.data.records").isArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initSimulation_returnData() throws Exception {
|
||||
String projectId = "proj-0001-uuid";
|
||||
String scenarioId = "scen-001-uuid";
|
||||
String initBody = "{\"startTime\":0,\"endTime\":12,\"step\":3}";
|
||||
String initResp = mockMvc.perform(MockMvcRequestBuilders.post("/projects/simulation/init")
|
||||
.param("projectId", projectId)
|
||||
.param("scenarioId", scenarioId)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(initBody))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
System.out.println("initResp=" + initResp);
|
||||
JsonNode initNode = objectMapper.readTree(initResp).path("data");
|
||||
int eventsCount = initNode.path("generated").path("events").asInt();
|
||||
int snapshotsCount = initNode.path("generated").path("snapshots").asInt();
|
||||
System.out.println("eventsCount=" + eventsCount + ", snapshotsCount=" + snapshotsCount);
|
||||
String resultResp = mockMvc.perform(MockMvcRequestBuilders.get("/scenario-results/by-scenario")
|
||||
.param("scenarioId", scenarioId)
|
||||
.param("pageNum", "1")
|
||||
.param("pageSize", "20"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
System.out.println("resultResp=" + resultResp);
|
||||
JsonNode resultNode = objectMapper.readTree(resultResp).path("data").path("records");
|
||||
Assertions.assertTrue(resultNode.isArray());
|
||||
System.out.println("recordsSize=" + resultNode.size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import com.yfd.platform.config.bean.LoginProperties;
|
||||
import com.yfd.platform.exception.AccessDeniedHandExcetion;
|
||||
import com.yfd.platform.exception.AuthenticationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -19,6 +20,9 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
// 1. 注入配置项,默认为 false
|
||||
@Value("${security.dev.permit:false}")
|
||||
private boolean devPermit;
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
@ -50,8 +54,12 @@ public class SecurityConfig {
|
||||
http
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/user/login").anonymous()
|
||||
.authorizeHttpRequests(auth -> {
|
||||
// 如果配置为 true,则允许所有请求
|
||||
if (devPermit) {
|
||||
auth.anyRequest().permitAll();
|
||||
} else {
|
||||
auth.requestMatchers("/user/login").anonymous()
|
||||
.requestMatchers("/user/code").permitAll()
|
||||
.requestMatchers(HttpMethod.GET,
|
||||
"/*.html",
|
||||
@ -73,8 +81,9 @@ public class SecurityConfig {
|
||||
"/avatar/**",
|
||||
"/systemurl/**",
|
||||
"/api/imageserver/upload").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.anyRequest().authenticated();
|
||||
}
|
||||
})
|
||||
.cors(cors -> {});
|
||||
|
||||
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
@ -31,3 +31,4 @@ springdoc:
|
||||
swagger-ui:
|
||||
enabled: true
|
||||
path: /swagger-ui.html
|
||||
|
||||
|
||||
335
logs/business-css.log
Normal file
335
logs/business-css.log
Normal file
@ -0,0 +1,335 @@
|
||||
2026-01-05T15:20:12.027+08:00 INFO 2372 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 2372 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:20:12.029+08:00 INFO 2372 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:20:14.178+08:00 INFO 2372 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:20:14.194+08:00 INFO 2372 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:20:14.195+08:00 INFO 2372 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:20:14.331+08:00 INFO 2372 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:20:14.331+08:00 INFO 2372 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2255 ms
|
||||
2026-01-05T15:20:14.623+08:00 WARN 2372 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mybatisConfig': Injection of resource dependencies failed
|
||||
2026-01-05T15:20:14.628+08:00 INFO 2372 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:20:14.682+08:00 INFO 2372 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:20:14.708+08:00 ERROR 2372 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
A component required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T15:23:04.333+08:00 INFO 11384 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 11384 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:23:04.336+08:00 INFO 11384 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:23:06.304+08:00 INFO 11384 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:23:06.321+08:00 INFO 11384 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:23:06.321+08:00 INFO 11384 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:23:06.436+08:00 INFO 11384 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:23:06.437+08:00 INFO 11384 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2056 ms
|
||||
2026-01-05T15:23:06.709+08:00 WARN 11384 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'algorithmController' defined in file [E:\projectJava\JavaProjectRepo\business-css\target\classes\com\yfd\business\css\controller\AlgorithmController.class]: Post-processing of merged bean definition failed
|
||||
2026-01-05T15:23:06.713+08:00 INFO 11384 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:23:06.758+08:00 INFO 11384 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:23:06.779+08:00 ERROR 11384 --- [business-css] [main] o.s.boot.SpringApplication : Application run failed
|
||||
|
||||
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'algorithmController' defined in file [E:\projectJava\JavaProjectRepo\business-css\target\classes\com\yfd\business\css\controller\AlgorithmController.class]: Post-processing of merged bean definition failed
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:577) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:962) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at com.yfd.business.css.CriticalScenarioApplication.main(CriticalScenarioApplication.java:27) ~[classes/:na]
|
||||
Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.yfd.business.css.controller.AlgorithmController] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@5e481248]
|
||||
at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:757) ~[spring-core-6.1.8.jar:6.1.8]
|
||||
at org.springframework.util.ReflectionUtils.doWithLocalFields(ReflectionUtils.java:689) ~[spring-core-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.buildResourceMetadata(CommonAnnotationBeanPostProcessor.java:431) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.findResourceMetadata(CommonAnnotationBeanPostProcessor.java:412) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(CommonAnnotationBeanPostProcessor.java:312) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:1085) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:574) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
... 15 common frames omitted
|
||||
Caused by: java.lang.NoClassDefFoundError: com/yfd/platform/system/service/IUserService
|
||||
at java.base/java.lang.Class.getDeclaredFields0(Native Method) ~[na:na]
|
||||
at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3299) ~[na:na]
|
||||
at java.base/java.lang.Class.getDeclaredFields(Class.java:2373) ~[na:na]
|
||||
at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:752) ~[spring-core-6.1.8.jar:6.1.8]
|
||||
... 21 common frames omitted
|
||||
Caused by: java.lang.ClassNotFoundException: com.yfd.platform.system.service.IUserService
|
||||
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[na:na]
|
||||
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na]
|
||||
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) ~[na:na]
|
||||
... 25 common frames omitted
|
||||
|
||||
2026-01-05T15:23:25.835+08:00 INFO 10632 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 10632 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:23:25.837+08:00 INFO 10632 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:23:27.674+08:00 INFO 10632 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:23:27.693+08:00 INFO 10632 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:23:27.694+08:00 INFO 10632 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:23:27.807+08:00 INFO 10632 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:23:27.808+08:00 INFO 10632 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1929 ms
|
||||
2026-01-05T15:23:28.080+08:00 WARN 10632 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'algorithmController' defined in file [E:\projectJava\JavaProjectRepo\business-css\target\classes\com\yfd\business\css\controller\AlgorithmController.class]: Post-processing of merged bean definition failed
|
||||
2026-01-05T15:23:28.084+08:00 INFO 10632 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:23:28.130+08:00 INFO 10632 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:23:28.150+08:00 ERROR 10632 --- [business-css] [main] o.s.boot.SpringApplication : Application run failed
|
||||
|
||||
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'algorithmController' defined in file [E:\projectJava\JavaProjectRepo\business-css\target\classes\com\yfd\business\css\controller\AlgorithmController.class]: Post-processing of merged bean definition failed
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:577) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:962) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.0.jar:3.3.0]
|
||||
at com.yfd.business.css.CriticalScenarioApplication.main(CriticalScenarioApplication.java:27) ~[classes/:na]
|
||||
Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.yfd.business.css.controller.AlgorithmController] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@5e481248]
|
||||
at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:757) ~[spring-core-6.1.8.jar:6.1.8]
|
||||
at org.springframework.util.ReflectionUtils.doWithLocalFields(ReflectionUtils.java:689) ~[spring-core-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.buildResourceMetadata(CommonAnnotationBeanPostProcessor.java:431) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.findResourceMetadata(CommonAnnotationBeanPostProcessor.java:412) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(CommonAnnotationBeanPostProcessor.java:312) ~[spring-context-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:1085) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:574) ~[spring-beans-6.1.8.jar:6.1.8]
|
||||
... 15 common frames omitted
|
||||
Caused by: java.lang.NoClassDefFoundError: com/yfd/platform/system/service/IUserService
|
||||
at java.base/java.lang.Class.getDeclaredFields0(Native Method) ~[na:na]
|
||||
at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3299) ~[na:na]
|
||||
at java.base/java.lang.Class.getDeclaredFields(Class.java:2373) ~[na:na]
|
||||
at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:752) ~[spring-core-6.1.8.jar:6.1.8]
|
||||
... 21 common frames omitted
|
||||
Caused by: java.lang.ClassNotFoundException: com.yfd.platform.system.service.IUserService
|
||||
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[na:na]
|
||||
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na]
|
||||
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) ~[na:na]
|
||||
... 25 common frames omitted
|
||||
|
||||
2026-01-05T15:29:34.916+08:00 INFO 30416 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 30416 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:29:34.919+08:00 INFO 30416 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:29:36.946+08:00 INFO 30416 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:29:36.976+08:00 INFO 30416 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:29:36.976+08:00 INFO 30416 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:29:37.100+08:00 INFO 30416 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:29:37.101+08:00 INFO 30416 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2130 ms
|
||||
2026-01-05T15:29:37.366+08:00 WARN 30416 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mybatisConfig': Unsatisfied dependency expressed through field 'mybatisPlusInterceptor': No qualifying bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
|
||||
2026-01-05T15:29:37.370+08:00 INFO 30416 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:29:37.410+08:00 INFO 30416 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:29:37.431+08:00 ERROR 30416 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Field mybatisPlusInterceptor in com.yfd.business.css.config.MybatisConfig required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
The injection point has the following annotations:
|
||||
- @org.springframework.beans.factory.annotation.Autowired(required=true)
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T15:29:50.820+08:00 INFO 6636 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 6636 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:29:50.823+08:00 INFO 6636 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:29:52.756+08:00 INFO 6636 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:29:52.771+08:00 INFO 6636 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:29:52.771+08:00 INFO 6636 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:29:52.914+08:00 INFO 6636 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:29:52.915+08:00 INFO 6636 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2049 ms
|
||||
2026-01-05T15:29:53.173+08:00 WARN 6636 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mybatisConfig': Unsatisfied dependency expressed through field 'mybatisPlusInterceptor': No qualifying bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
|
||||
2026-01-05T15:29:53.177+08:00 INFO 6636 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:29:53.222+08:00 INFO 6636 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:29:53.244+08:00 ERROR 6636 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Field mybatisPlusInterceptor in com.yfd.business.css.config.MybatisConfig required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
The injection point has the following annotations:
|
||||
- @org.springframework.beans.factory.annotation.Autowired(required=true)
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T15:30:03.576+08:00 INFO 22176 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 22176 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:30:03.579+08:00 INFO 22176 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:30:05.318+08:00 INFO 22176 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:30:05.330+08:00 INFO 22176 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:30:05.330+08:00 INFO 22176 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:30:05.460+08:00 INFO 22176 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:30:05.461+08:00 INFO 22176 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1836 ms
|
||||
2026-01-05T15:30:05.727+08:00 WARN 22176 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mybatisConfig': Unsatisfied dependency expressed through field 'mybatisPlusInterceptor': No qualifying bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
|
||||
2026-01-05T15:30:05.730+08:00 INFO 22176 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:30:05.764+08:00 INFO 22176 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:30:05.782+08:00 ERROR 22176 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Field mybatisPlusInterceptor in com.yfd.business.css.config.MybatisConfig required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
The injection point has the following annotations:
|
||||
- @org.springframework.beans.factory.annotation.Autowired(required=true)
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T15:32:03.378+08:00 INFO 9616 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 9616 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:32:03.381+08:00 INFO 9616 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:32:05.424+08:00 INFO 9616 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:32:05.445+08:00 INFO 9616 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:32:05.446+08:00 INFO 9616 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:32:05.578+08:00 INFO 9616 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:32:05.579+08:00 INFO 9616 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2158 ms
|
||||
2026-01-05T15:32:05.864+08:00 WARN 9616 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mybatisConfig': Unsatisfied dependency expressed through field 'mybatisPlusInterceptor': No qualifying bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
|
||||
2026-01-05T15:32:05.868+08:00 INFO 9616 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:32:05.918+08:00 INFO 9616 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:32:05.943+08:00 ERROR 9616 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Field mybatisPlusInterceptor in com.yfd.business.css.config.MybatisConfig required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
The injection point has the following annotations:
|
||||
- @org.springframework.beans.factory.annotation.Autowired(required=true)
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T15:34:01.386+08:00 INFO 18712 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 18712 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T15:34:01.389+08:00 INFO 18712 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T15:34:03.377+08:00 INFO 18712 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T15:34:03.392+08:00 INFO 18712 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T15:34:03.393+08:00 INFO 18712 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T15:34:03.536+08:00 INFO 18712 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T15:34:03.537+08:00 INFO 18712 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2109 ms
|
||||
2026-01-05T15:34:03.793+08:00 WARN 18712 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mybatisConfig': Unsatisfied dependency expressed through field 'mybatisPlusInterceptor': No qualifying bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
|
||||
2026-01-05T15:34:03.797+08:00 INFO 18712 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T15:34:03.838+08:00 INFO 18712 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T15:34:03.860+08:00 ERROR 18712 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Field mybatisPlusInterceptor in com.yfd.business.css.config.MybatisConfig required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
The injection point has the following annotations:
|
||||
- @org.springframework.beans.factory.annotation.Autowired(required=true)
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T17:30:52.702+08:00 INFO 27432 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 27432 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T17:30:52.705+08:00 INFO 27432 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T17:30:54.802+08:00 INFO 27432 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T17:30:54.815+08:00 INFO 27432 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T17:30:54.816+08:00 INFO 27432 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T17:30:54.951+08:00 INFO 27432 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T17:30:54.952+08:00 INFO 27432 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2206 ms
|
||||
2026-01-05T17:30:55.307+08:00 WARN 27432 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mybatisConfig': Injection of resource dependencies failed
|
||||
2026-01-05T17:30:55.310+08:00 INFO 27432 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T17:30:55.353+08:00 INFO 27432 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T17:30:55.377+08:00 ERROR 27432 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
A component required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
2026-01-05T17:31:24.083+08:00 INFO 24748 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : Starting CriticalScenarioApplication using Java 17.0.17 with PID 24748 (E:\projectJava\JavaProjectRepo\business-css\target\classes started by Admin in E:\projectJava\JavaProjectRepo)
|
||||
2026-01-05T17:31:24.086+08:00 INFO 24748 --- [business-css] [main] c.y.b.css.CriticalScenarioApplication : The following 2 profiles are active: "framework", "business"
|
||||
2026-01-05T17:31:25.999+08:00 INFO 24748 --- [business-css] [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8090 (http)
|
||||
2026-01-05T17:31:26.013+08:00 INFO 24748 --- [business-css] [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2026-01-05T17:31:26.013+08:00 INFO 24748 --- [business-css] [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.24]
|
||||
2026-01-05T17:31:26.151+08:00 INFO 24748 --- [business-css] [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-01-05T17:31:26.152+08:00 INFO 24748 --- [business-css] [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2022 ms
|
||||
2026-01-05T17:31:26.407+08:00 WARN 24748 --- [business-css] [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mybatisConfig': Injection of resource dependencies failed
|
||||
2026-01-05T17:31:26.410+08:00 INFO 24748 --- [business-css] [main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
|
||||
2026-01-05T17:31:26.452+08:00 INFO 24748 --- [business-css] [main] .s.b.a.l.ConditionEvaluationReportLogger :
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2026-01-05T17:31:26.480+08:00 ERROR 24748 --- [business-css] [main] o.s.b.d.LoggingFailureAnalysisReporter :
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
A component required a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' that could not be found.
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider defining a bean of type 'com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor' in your configuration.
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>aliyunmaven</id>
|
||||
<name>Aliyun Maven</name>
|
||||
<mirrorOf>central</mirrorOf>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>aliyun</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<url>https://repo.maven.apache.org/maven2</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>central</id>
|
||||
<url>https://repo.maven.apache.org/maven2</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
<activeProfiles>
|
||||
<activeProfile>aliyun</activeProfile>
|
||||
</activeProfiles>
|
||||
</settings>
|
||||
1
python-ml/__init__.py
Normal file
1
python-ml/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
|
||||
72
python-ml/app.py
Normal file
72
python-ml/app.py
Normal file
@ -0,0 +1,72 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import os
|
||||
try:
|
||||
from .service import train_one_type, infer_one, infer_batch, train_one_type_from_samples
|
||||
except ImportError:
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
from service import train_one_type, infer_one, infer_batch, train_one_type_from_samples
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def ensure_model_dir(device_type, model_dir):
|
||||
root = model_dir if model_dir else os.path.join("models", device_type)
|
||||
return root
|
||||
|
||||
@app.post("/v1/train/<device_type>")
|
||||
def train(device_type):
|
||||
data = request.get_json(force=True)
|
||||
dataset_path = data.get("dataset_path")
|
||||
model_dir = data.get("model_dir")
|
||||
if not dataset_path or not os.path.exists(dataset_path):
|
||||
return jsonify({"code": 1, "msg": "dataset_path not found"}), 400
|
||||
out_dir = ensure_model_dir(device_type, model_dir)
|
||||
res = train_one_type(device_type, dataset_path, out_dir)
|
||||
return jsonify({"code": 0, "msg": "ok", "data": res})
|
||||
|
||||
@app.post("/v1/train/<device_type>/from-samples")
|
||||
def train_from_samples(device_type):
|
||||
data = request.get_json(force=True)
|
||||
samples = data.get("samples")
|
||||
model_dir = data.get("model_dir")
|
||||
if not samples or len(samples) == 0:
|
||||
return jsonify({"code": 1, "msg": "samples required"}), 400
|
||||
feats = []
|
||||
labels = []
|
||||
for s in samples:
|
||||
feats.append(s.get("features"))
|
||||
labels.append(s.get("label"))
|
||||
out_dir = ensure_model_dir(device_type, model_dir)
|
||||
res = train_one_type_from_samples(device_type, feats, labels, out_dir)
|
||||
return jsonify({"code": 0, "msg": "ok", "data": res})
|
||||
|
||||
@app.post("/v1/infer/<device_type>/keff")
|
||||
def infer(device_type):
|
||||
data = request.get_json(force=True)
|
||||
model_dir = data.get("model_dir")
|
||||
out_dir = ensure_model_dir(device_type, model_dir)
|
||||
batch = data.get("batch")
|
||||
features = data.get("features")
|
||||
meta = data.get("meta") or {}
|
||||
if batch and len(batch) > 0:
|
||||
feats_list = []
|
||||
metas = []
|
||||
for s in batch:
|
||||
if isinstance(s, dict) and "features" in s:
|
||||
feats_list.append(s["features"])
|
||||
metas.append(s.get("meta") or {})
|
||||
else:
|
||||
feats_list.append(s)
|
||||
metas.append({})
|
||||
ys = infer_batch(device_type, feats_list, out_dir)
|
||||
items = []
|
||||
for i, y in enumerate(ys):
|
||||
items.append({"meta": metas[i], "features": feats_list[i], "keff": y})
|
||||
return jsonify({"code": 0, "msg": "ok", "data": {"items": items}})
|
||||
if not features:
|
||||
return jsonify({"code": 1, "msg": "features required"}), 400
|
||||
y = infer_one(device_type, features, out_dir)
|
||||
return jsonify({"code": 0, "msg": "ok", "data": {"meta": meta, "features": features, "keff": y}})
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
||||
149
python-ml/service.py
Normal file
149
python-ml/service.py
Normal file
@ -0,0 +1,149 @@
|
||||
import os
|
||||
import time
|
||||
import pickle
|
||||
import numpy as np
|
||||
from sklearn.pipeline import Pipeline
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.gaussian_process import GaussianProcessRegressor
|
||||
from sklearn.gaussian_process.kernels import RBF, RationalQuadratic, ConstantKernel, WhiteKernel
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, max_error
|
||||
try:
|
||||
from .type_config import load_from_excel, features_to_vector
|
||||
except ImportError:
|
||||
from type_config import load_from_excel, features_to_vector
|
||||
|
||||
"""
|
||||
训练与推理服务方法
|
||||
- build_gpr_model: 构建 GPR 模型
|
||||
- build_pipeline: 构建包含标准化与模型的 Pipeline
|
||||
- compute_metrics: 计算评估指标
|
||||
- train_one_type: 按设备类型训练并保存模型
|
||||
- infer_one: 单条推理
|
||||
- infer_batch: 批量推理
|
||||
"""
|
||||
|
||||
RANDOM_STATE = 42
|
||||
TEST_SIZE = 0.2
|
||||
|
||||
def build_gpr_model():
|
||||
"""构建高斯过程回归模型,含复合核与输出中心化"""
|
||||
kernel = ConstantKernel(1.0) * (0.7 * RBF(1.0) + 0.3 * RationalQuadratic(1.0, 1.0)) + WhiteKernel(1e-5)
|
||||
return GaussianProcessRegressor(kernel=kernel, alpha=0.0, n_restarts_optimizer=5, normalize_y=True, random_state=RANDOM_STATE)
|
||||
|
||||
def build_pipeline():
|
||||
"""构建训练/推理管线:输入标准化 + 模型"""
|
||||
return Pipeline([("scaler", StandardScaler()), ("model", build_gpr_model())])
|
||||
|
||||
def compute_metrics(y_true, y_pred):
|
||||
"""计算回归误差指标:RMSE/MAE/R2/maxe"""
|
||||
return {
|
||||
"rmse": float(np.sqrt(mean_squared_error(y_true, y_pred))),
|
||||
"mae": float(mean_absolute_error(y_true, y_pred)),
|
||||
"r2": float(r2_score(y_true, y_pred)),
|
||||
"maxe": float(max_error(y_true, y_pred))
|
||||
}
|
||||
|
||||
def train_one_type(device_type, dataset_path, model_dir):
|
||||
"""按设备类型训练模型并保存 Pipeline,返回指标与耗时"""
|
||||
X, y = load_from_excel(device_type, dataset_path)
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)
|
||||
pipe = build_pipeline()
|
||||
pipe.fit(X_train, y_train)
|
||||
X_all = np.vstack([X_train, X_test])
|
||||
y_all = np.concatenate([y_train, y_test])
|
||||
t0 = time.time()
|
||||
pred_all = pipe.predict(X_all)
|
||||
t1 = time.time()
|
||||
os.makedirs(model_dir, exist_ok=True)
|
||||
model_path = os.path.join(model_dir, "pipeline.pkl")
|
||||
with open(model_path, "wb") as f:
|
||||
pickle.dump(pipe, f)
|
||||
return {"metrics": compute_metrics(y_all, pred_all), "infer_batch_time_sec": float(t1 - t0), "model_path": model_path}
|
||||
|
||||
def infer_one(device_type, features, model_dir):
|
||||
"""加载 Pipeline,按设备类型将特征映射为向量并进行单条推理"""
|
||||
model_path = os.path.join(model_dir, "pipeline.pkl")
|
||||
with open(model_path, "rb") as f:
|
||||
pipe = pickle.load(f)
|
||||
X = features_to_vector(device_type, features)
|
||||
y = pipe.predict(X)
|
||||
return float(y[0])
|
||||
|
||||
def infer_batch(device_type, features_list, model_dir):
|
||||
"""加载 Pipeline,批量将特征映射为向量并进行推理"""
|
||||
model_path = os.path.join(model_dir, "pipeline.pkl")
|
||||
with open(model_path, "rb") as f:
|
||||
pipe = pickle.load(f)
|
||||
Xs = []
|
||||
for feat in features_list:
|
||||
Xs.append(features_to_vector(device_type, feat))
|
||||
X = np.vstack(Xs)
|
||||
ys = pipe.predict(X)
|
||||
return [float(v) for v in ys]
|
||||
|
||||
def train_one_type_from_samples(device_type, features_list, labels, model_dir):
|
||||
"""按设备类型基于样本集合训练模型并保存 Pipeline"""
|
||||
Xs = []
|
||||
for feat in features_list:
|
||||
Xs.append(features_to_vector(device_type, feat))
|
||||
X = np.vstack(Xs)
|
||||
y = np.array(labels, dtype=float)
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)
|
||||
pipe = build_pipeline()
|
||||
pipe.fit(X_train, y_train)
|
||||
X_all = np.vstack([X_train, X_test])
|
||||
y_all = np.concatenate([y_train, y_test])
|
||||
t0 = time.time()
|
||||
pred_all = pipe.predict(X_all)
|
||||
t1 = time.time()
|
||||
os.makedirs(model_dir, exist_ok=True)
|
||||
model_path = os.path.join(model_dir, "pipeline.pkl")
|
||||
with open(model_path, "wb") as f:
|
||||
pickle.dump(pipe, f)
|
||||
return {"metrics": compute_metrics(y_all, pred_all), "infer_batch_time_sec": float(t1 - t0), "model_path": model_path}
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = os.getcwd()
|
||||
tasks = [
|
||||
("cylindrical_tank", os.path.join(root, "circle.xlsx"), os.path.join(root, "models", "cylindrical_tank")),
|
||||
("ring_tank", os.path.join(root, "ring.xlsx"), os.path.join(root, "models", "ring_tank"))
|
||||
]
|
||||
results = {}
|
||||
for dt, ds, md in tasks:
|
||||
if not os.path.exists(ds):
|
||||
print(f"[skip] dataset not found: {ds}")
|
||||
continue
|
||||
res = train_one_type(dt, ds, md)
|
||||
results[dt] = res
|
||||
print(f"[train] {dt} -> {res}")
|
||||
sample_cyl = {"直径": 160, "高度": 160, "铀浓度": 20, "铀富集度": 0.01}
|
||||
cyl_dir = os.path.join(root, "models", "cylindrical_tank")
|
||||
if os.path.exists(os.path.join(cyl_dir, "pipeline.pkl")):
|
||||
y_cyl = infer_one("cylindrical_tank", sample_cyl, cyl_dir)
|
||||
print(f"[infer] cylindrical_tank keff={y_cyl}")
|
||||
sample_ring = {"外径": 70, "高度": 70, "Pu浓度": 40, "Pu240占比": 0.05}
|
||||
ring_dir = os.path.join(root, "models", "ring_tank")
|
||||
if os.path.exists(os.path.join(ring_dir, "pipeline.pkl")):
|
||||
y_ring = infer_one("ring_tank", sample_ring, ring_dir)
|
||||
print(f"[infer] ring_tank keff={y_ring}")
|
||||
|
||||
def main():
|
||||
tasks = [
|
||||
("cylindrical_tank", "circle.xlsx", os.path.join("models", "cylindrical_tank")),
|
||||
("ring_tank", "ring.xlsx", os.path.join("models", "ring_tank"))
|
||||
]
|
||||
results = {}
|
||||
for t, path, out in tasks:
|
||||
res = train_one_type(t, path, out)
|
||||
results[t] = res
|
||||
print({"train_results": results})
|
||||
sample_cyl = {"直径": 160, "高度": 160, "铀浓度": 20, "铀富集度": 0.01}
|
||||
y_cyl = infer_one("cylindrical_tank", sample_cyl, os.path.join("models", "cylindrical_tank"))
|
||||
sample_ring = {"外径": 70, "高度": 70, "Pu浓度": 40, "Pu240占比": 0.05}
|
||||
y_ring = infer_one("ring_tank", sample_ring, os.path.join("models", "ring_tank"))
|
||||
print({"infer_examples": {"cylindrical_tank": {"features": sample_cyl, "keff": y_cyl},
|
||||
"ring_tank": {"features": sample_ring, "keff": y_ring}}})
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
90
python-ml/type_config.py
Normal file
90
python-ml/type_config.py
Normal file
@ -0,0 +1,90 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
def cfg_cylindrical():
|
||||
return {
|
||||
"cols": ["diameter", "height", "fissile_concentration", "isotopic_abundance"],
|
||||
"label": "keff",
|
||||
"aliases": {
|
||||
"直径": "diameter",
|
||||
"高度": "height",
|
||||
"铀浓度": "fissile_concentration",
|
||||
"U浓度": "fissile_concentration",
|
||||
"铀富集度": "isotopic_abundance",
|
||||
"U富集度": "isotopic_abundance",
|
||||
# 兼容旧英文键
|
||||
"u_concentration": "fissile_concentration",
|
||||
"u_enrichment": "isotopic_abundance"
|
||||
}
|
||||
}
|
||||
|
||||
def cfg_ring():
|
||||
return {
|
||||
"cols": ["diameter", "height", "fissile_concentration", "isotopic_abundance"],
|
||||
"label": "keff",
|
||||
"aliases": {
|
||||
"外径": "diameter",
|
||||
"高度": "height",
|
||||
"Pu浓度": "fissile_concentration",
|
||||
"Pu240占比": "isotopic_abundance",
|
||||
# 兼容旧英文键
|
||||
"pu_concentration": "fissile_concentration",
|
||||
"pu_isotope": "isotopic_abundance"
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_CONFIG = {
|
||||
"CylindricalTank": cfg_cylindrical(),
|
||||
"AnnularTank": cfg_ring()
|
||||
}
|
||||
|
||||
def feature_names(device_type):
|
||||
cfg = TYPE_CONFIG[device_type]
|
||||
base = cfg["cols"]
|
||||
if device_type in ("CylindricalTank", "AnnularTank"):
|
||||
derived = [f"{base[0]}*{base[1]}", f"{base[2]}*{base[3]}"]
|
||||
return base + derived
|
||||
return base
|
||||
|
||||
def derive_features(device_type, X):
|
||||
if device_type in ("CylindricalTank", "AnnularTank"):
|
||||
return np.hstack([X, (X[:, 0] * X[:, 1]).reshape(-1, 1), (X[:, 2] * X[:, 3]).reshape(-1, 1)])
|
||||
return X
|
||||
|
||||
def _resolve_col(df, key, aliases):
|
||||
if key in df.columns:
|
||||
return df[key].values
|
||||
for a, k in aliases.items():
|
||||
if k == key and a in df.columns:
|
||||
return df[a].values
|
||||
raise KeyError(key)
|
||||
|
||||
def load_from_excel(device_type, path):
|
||||
cfg = TYPE_CONFIG[device_type]
|
||||
df = pd.read_excel(path)
|
||||
cols = cfg["cols"]
|
||||
aliases = cfg.get("aliases", {})
|
||||
arrs = []
|
||||
for k in cols:
|
||||
v = _resolve_col(df, k, aliases)
|
||||
arrs.append(v.astype(float))
|
||||
X = np.vstack(arrs).T
|
||||
y = df[cfg["label"]].values.astype(float) if cfg["label"] in df.columns else df[cfg["label"]].values.astype(float)
|
||||
Xd = derive_features(device_type, X)
|
||||
return Xd, y
|
||||
|
||||
def features_to_vector(device_type, features):
|
||||
cfg = TYPE_CONFIG[device_type]
|
||||
aliases = cfg.get("aliases", {})
|
||||
vals = []
|
||||
for k in cfg["cols"]:
|
||||
v = features.get(k)
|
||||
if v is None:
|
||||
for a, ck in aliases.items():
|
||||
if ck == k and a in features:
|
||||
v = features[a]
|
||||
break
|
||||
vals.append(float(v))
|
||||
X = np.array(vals, dtype=float).reshape(1, -1)
|
||||
Xd = derive_features(device_type, X)
|
||||
return Xd
|
||||
52
python_ml/type_config.py
Normal file
52
python_ml/type_config.py
Normal file
@ -0,0 +1,52 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
"""
|
||||
类型配置与特征管线
|
||||
职责:
|
||||
- 为不同 device_type 定义输入列与 label 名称
|
||||
- 提供特征衍生(原始列→模型向量)
|
||||
- 支持从 Excel 加载与将字典特征映射为向量
|
||||
"""
|
||||
|
||||
def cfg_cylindrical():
|
||||
return {
|
||||
"cols": ["直径", "高度", "铀浓度", "铀富集度"],
|
||||
"label": "keff"
|
||||
}
|
||||
|
||||
def cfg_ring():
|
||||
return {
|
||||
"cols": ["外径", "高度", "Pu浓度", "Pu240占比"],
|
||||
"label": "keff"
|
||||
}
|
||||
|
||||
TYPE_CONFIG = {
|
||||
"cylindrical_tank": cfg_cylindrical(),
|
||||
"ring_tank": cfg_ring()
|
||||
}
|
||||
|
||||
def derive_features(device_type, X):
|
||||
if device_type == "cylindrical_tank":
|
||||
return np.hstack([X, (X[:, 0] * X[:, 1]).reshape(-1, 1), (X[:, 2] * X[:, 3]).reshape(-1, 1)])
|
||||
if device_type == "ring_tank":
|
||||
return np.hstack([X, (X[:, 0] * X[:, 1]).reshape(-1, 1), (X[:, 2] * X[:, 3]).reshape(-1, 1)])
|
||||
return X
|
||||
|
||||
def load_from_excel(device_type, path):
|
||||
cfg = TYPE_CONFIG[device_type]
|
||||
df = pd.read_excel(path)
|
||||
X = df[cfg["cols"]].values.astype(float)
|
||||
y = df[cfg["label"]].values.astype(float)
|
||||
Xd = derive_features(device_type, X)
|
||||
return Xd, y
|
||||
|
||||
def features_to_vector(device_type, features):
|
||||
cfg = TYPE_CONFIG[device_type]
|
||||
vals = []
|
||||
for k in cfg["cols"]:
|
||||
v = features.get(k)
|
||||
vals.append(float(v))
|
||||
X = np.array(vals, dtype=float).reshape(1, -1)
|
||||
Xd = derive_features(device_type, X)
|
||||
return Xd
|
||||
@ -1,4 +0,0 @@
|
||||
@echo off
|
||||
set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot"
|
||||
set "PATH=%JAVA_HOME%\bin;%PATH%"
|
||||
mvn %*
|
||||
Loading…
Reference in New Issue
Block a user