package com.estate.expert.admin.component.fuzzy; import com.estate.expert.admin.utils.json.CustomFloatDeserializer; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; /** * 模糊层次分析法(FAHP)评估API调用组件 * *

该组件负责与外部模糊评估API进行通信,发送评估请求并处理响应结果。 * 主要用于建筑工程安全风险评估、多因素决策分析等场景。

* *

主要功能:

* * *

技术特点:

* * * @author daisy * @since 2023/10/29 */ @Slf4j @Component public class FuzzyApiComponent { /** * 模糊评估API的远程服务地址 * */ // private static final String FUZZY_EVALUATION_API_URL = "http://47.93.28.249:8081/api/Fuzzy_evaluation"; @Value("${fuzzy.api.url}") private static final String FUZZY_EVALUATION_API_URL = "http://localhost:5000/api/Fuzzy_evaluation"; /** * HTTP客户端模板 * *

用于发送HTTP请求到模糊评估API服务。 * Spring RestTemplate提供了便捷的HTTP客户端功能。

*/ RestTemplate restTemplate = new RestTemplate(); /** * 获取配置了自定义反序列化器的ObjectMapper * * @return 配置好的ObjectMapper实例 */ public static ObjectMapper getObjectMapper() { ObjectMapper mapper = new ObjectMapper(); // 允许非标准数值格式,如NaN、Infinity等 mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true); SimpleModule module = new SimpleModule(); // 注册自定义Float反序列化器 module.addDeserializer(Float.class, new CustomFloatDeserializer()); mapper.registerModule(module); return mapper; } /** * 调用模糊评估API进行风险评估 * *

该方法向远程模糊评估服务发送POST请求,传递评估参数并接收评估结果。 * 包含完整的错误处理和日志记录机制。

* *

处理流程:

*
    *
  1. 设置HTTP请求头(Content-Type: application/json)
  2. *
  3. 封装请求实体
  4. *
  5. 发送POST请求到模糊评估API
  6. *
  7. 检查响应状态码
  8. *
  9. 解析响应JSON为FuzzyApiResponse对象
  10. *
  11. 处理异常情况并返回默认响应
  12. *
* *

异常处理:

* * * @param bo 模糊评估请求参数,包含评估所需的所有数据 * @return FuzzyApiResponse 评估结果,包含风险得分、权重、一致性指标等 * * @see FuzzyApiRequest 请求参数说明 * @see FuzzyApiResponse 响应结果说明 */ public FuzzyApiResponse call(FuzzyApiRequest bo) { // 设置HTTP请求头,指定内容类型为JSON HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // 封装请求实体,包含请求参数和请求头 HttpEntity requestEntity = new HttpEntity<>(bo, headers); log.info("发送模糊评估请求: {}", bo); try { // 发送POST请求到模糊评估API ResponseEntity response = restTemplate.exchange( FUZZY_EVALUATION_API_URL, HttpMethod.POST, requestEntity, String.class ); // 检查响应状态码 if (response.getStatusCode().is2xxSuccessful()) { String responseBody = response.getBody(); log.info("模糊评估API响应成功: {}", responseBody); // 检查响应体是否为空 if (StringUtils.isNotBlank(responseBody)) { // 使用自定义ObjectMapper解析JSON响应 return getObjectMapper().readValue(responseBody, FuzzyApiResponse.class); } else { log.warn("模糊评估API返回空响应体"); } } else { log.error("模糊评估API请求失败,HTTP状态码: {}", response.getStatusCode()); } } catch (Exception e) { // 记录详细的异常信息,包括堆栈跟踪 log.error("模糊评估API调用异常: {}", ExceptionUtils.getStackTrace(e)); } // 异常情况下返回空的响应对象 return new FuzzyApiResponse(); } /** * 测试方法 - 多因素综合评估示例 * *

该方法演示了如何使用模糊评估API进行多因素综合风险评估。 * 适用于复杂的工程安全评估场景,如整个项目的综合安全风险评估。

* */ public static void main(String[] args) { // 创建模糊评估请求对象 FuzzyApiRequest bo = new FuzzyApiRequest(); FuzzyApiComponent component = new FuzzyApiComponent(); // 设置评估因素数量 bo.setN(18); // 设置评估因素名称数组 bo.setIndex(new String[]{"临时消防", "基坑工程", "悬挑式脚手架", "扣件式模板支架", "承插型钢管支模架", "文明施工", "施工机具", "施工用电", "有限空间作业", "盘扣式模板支架", "盘扣式落地钢管脚手架(双排、满堂)", "落地式扣件钢管脚手架(双排、满堂)", "轮扣式模板支架", "轮扣式落地钢管脚手架(双排、满堂)", "附着式升降脚手架", "附着式脚手架", "高处作业", "高处作业吊篮"}); // 设置隶属度矩阵(18×5) // 每行表示一个因素在5个风险等级上的隶属度分布 // 列含义:[可忽略风险, 低风险, 中等风险, 高风险, 不可接受风险] bo.setMembership_data(new float[][]{ {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 临时消防 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 基坑工程 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 悬挑式脚手架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 扣件式模板支架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 承插型钢管支模架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 文明施工 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 施工机具 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 施工用电 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 有限空间作业 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 盘扣式模板支架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 盘扣式落地钢管脚手架(双排、满堂) {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 落地式扣件钢管脚手架(双排、满堂) {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 轮扣式模板支架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 轮扣式落地钢管脚手架(双排、满堂) {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 附着式升降脚手架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 附着式脚手架 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f}, // 高处作业 {0.6917f, 0.2917f, 0.0166f, 0.0f, 0.0f} // 高处作业吊篮 }); // 设置两两比较矩阵(18×18) // 当前设置为所有因素同等重要(值为1.0) // 实际使用时需要根据专家判断设置不同的重要性比值 bo.setCompare_matrix_data(new float[][]{ {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f} }); // 设置专家数量 bo.setNum_experts(1); // 记录请求参数 log.info("模糊评估请求参数: {}", bo); // 调用模糊评估API var resp = component.call(bo); // 记录评估结果 log.info("模糊评估结果: {}", resp); } }