refactor(security): 清理 security-biz 中旧的 vsp 文件,更新测试
- 删除 security-biz/integration/vsp/ 旧目录(已迁移至 ops-biz/infrastructure/vsp/) - 更新 SecurityOrderEventListenerVspTest import 路径 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp;
|
||||
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSendCardReqDTO;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSyncStatusReqDTO;
|
||||
|
||||
public interface VspNotifyClient {
|
||||
|
||||
/**
|
||||
* 发送企微工单卡片
|
||||
*
|
||||
* @param req 卡片内容
|
||||
*/
|
||||
void sendCard(VspSendCardReqDTO req);
|
||||
|
||||
/**
|
||||
* 同步工单状态到 vsp-service
|
||||
*
|
||||
* @param req 状态信息
|
||||
*/
|
||||
void syncStatus(VspSyncStatusReqDTO req);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp;
|
||||
|
||||
import com.viewsh.module.ops.security.integration.vsp.config.VspNotifyProperties;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspResponseDTO;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSendCardReqDTO;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSyncStatusReqDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class VspNotifyClientImpl implements VspNotifyClient {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final VspNotifyProperties properties;
|
||||
|
||||
public VspNotifyClientImpl(@Qualifier("vspRestTemplate") RestTemplate restTemplate,
|
||||
VspNotifyProperties properties) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCard(VspSendCardReqDTO req) {
|
||||
if (!properties.isEnabled()) return;
|
||||
String url = properties.getBaseUrl() + "/api/wechat/notify/send-card";
|
||||
executeWithRetry(url, req, "sendCard", req.getOrderId(), req.getAlarmId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncStatus(VspSyncStatusReqDTO req) {
|
||||
if (!properties.isEnabled()) return;
|
||||
String url = properties.getBaseUrl() + "/api/wechat/notify/sync-status";
|
||||
executeWithRetry(url, req, "syncStatus", req.getOrderId(), req.getAlarmId());
|
||||
}
|
||||
|
||||
private void executeWithRetry(String url, Object req,
|
||||
String action, String orderId, String alarmId) {
|
||||
for (int i = 0; i <= properties.getMaxRetry(); i++) {
|
||||
try {
|
||||
VspResponseDTO resp = restTemplate.postForObject(url, req, VspResponseDTO.class);
|
||||
if (resp != null && resp.isSuccess()) {
|
||||
log.info("[{}] vsp通知成功, orderId={}, alarmId={}", action, orderId, alarmId);
|
||||
return;
|
||||
}
|
||||
// 业务失败不重试
|
||||
log.warn("[{}] vsp返回失败: code={}, msg={}, orderId={}",
|
||||
action, resp != null ? resp.getCode() : null,
|
||||
resp != null ? resp.getMsg() : null, orderId);
|
||||
return;
|
||||
} catch (RestClientException e) {
|
||||
if (i < properties.getMaxRetry()) {
|
||||
log.warn("[{}] 第{}次调用失败, orderId={}, 将重试",
|
||||
action, i + 1, orderId);
|
||||
} else {
|
||||
log.error("[{}] 调用vsp失败, 重试耗尽, orderId={}, alarmId={}",
|
||||
action, orderId, alarmId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp.config;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(VspNotifyProperties.class)
|
||||
public class VspNotifyConfig {
|
||||
|
||||
@Bean("vspRestTemplate")
|
||||
public RestTemplate vspRestTemplate(VspNotifyProperties properties) {
|
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(properties.getConnectTimeout());
|
||||
factory.setReadTimeout(properties.getReadTimeout());
|
||||
RestTemplate restTemplate = new RestTemplate(factory);
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "viewsh.ops.vsp-notify")
|
||||
public class VspNotifyProperties {
|
||||
/** 是否启用 vsp 通知 */
|
||||
private boolean enabled = true;
|
||||
/** vsp-service 基础 URL */
|
||||
private String baseUrl = "http://124.221.55.225:8000";
|
||||
/** 连接超时(ms) */
|
||||
private int connectTimeout = 5000;
|
||||
/** 读取超时(ms) */
|
||||
private int readTimeout = 10000;
|
||||
/** 最大重试次数(网络异常时) */
|
||||
private int maxRetry = 2;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class VspResponseDTO {
|
||||
private Integer code;
|
||||
private String msg;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return code != null && code == 0;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class VspSendCardReqDTO {
|
||||
/** 关联告警ID */
|
||||
private String alarmId;
|
||||
/** 工单ID */
|
||||
private String orderId;
|
||||
/** 接收人企微 userId 列表 */
|
||||
private List<String> userIds;
|
||||
/** 卡片标题(告警类型) */
|
||||
private String title;
|
||||
/** 区域名称 */
|
||||
private String areaName;
|
||||
/** 摄像头名称 */
|
||||
private String cameraName;
|
||||
/** 告警时间,格式 MM-dd HH:mm */
|
||||
private String eventTime;
|
||||
/** 告警级别(0紧急 1重要 2普通 3轻微) */
|
||||
private Integer level;
|
||||
/** 告警截图URL */
|
||||
private String snapshotUrl;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class VspSyncStatusReqDTO {
|
||||
/** 关联告警ID */
|
||||
private String alarmId;
|
||||
/** 工单ID */
|
||||
private String orderId;
|
||||
/** 工单状态 */
|
||||
private String status;
|
||||
/** 操作人企微 userId */
|
||||
private String operator;
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
}
|
||||
@@ -10,11 +10,11 @@ import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||
import com.viewsh.module.ops.infrastructure.log.recorder.EventLogRecorder;
|
||||
import com.viewsh.module.ops.security.dal.dataobject.workorder.OpsOrderSecurityExtDO;
|
||||
import com.viewsh.module.ops.security.dal.mysql.workorder.OpsOrderSecurityExtMapper;
|
||||
import com.viewsh.module.ops.security.integration.vsp.VspNotifyClient;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSendCardReqDTO;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSyncStatusReqDTO;
|
||||
import com.viewsh.module.ops.infrastructure.vsp.VspNotifyClient;
|
||||
import com.viewsh.module.ops.infrastructure.vsp.dto.VspSendCardReqDTO;
|
||||
import com.viewsh.module.ops.infrastructure.vsp.dto.VspSyncStatusReqDTO;
|
||||
import com.viewsh.module.ops.service.area.OpsBusAreaService;
|
||||
import com.viewsh.module.ops.controller.admin.area.vo.OpsBusAreaRespVO;
|
||||
import com.viewsh.module.ops.dal.dataobject.vo.area.OpsBusAreaRespVO;
|
||||
import com.viewsh.module.system.api.social.SocialUserApi;
|
||||
import com.viewsh.module.system.api.social.dto.SocialUserRespDTO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
package com.viewsh.module.ops.security.integration.vsp;
|
||||
|
||||
import com.viewsh.module.ops.security.integration.vsp.config.VspNotifyProperties;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspResponseDTO;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSendCardReqDTO;
|
||||
import com.viewsh.module.ops.security.integration.vsp.dto.VspSyncStatusReqDTO;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* VspNotifyClientImpl 单元测试
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class VspNotifyClientImplTest {
|
||||
|
||||
@Mock
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
private VspNotifyProperties properties;
|
||||
|
||||
private VspNotifyClientImpl client;
|
||||
|
||||
private static final String BASE_URL = "http://localhost:8000";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
properties = new VspNotifyProperties();
|
||||
properties.setEnabled(true);
|
||||
properties.setBaseUrl(BASE_URL);
|
||||
properties.setMaxRetry(2);
|
||||
client = new VspNotifyClientImpl(restTemplate, properties);
|
||||
}
|
||||
|
||||
// ==================== sendCard 测试 ====================
|
||||
|
||||
@Test
|
||||
void sendCard_success() {
|
||||
VspSendCardReqDTO req = buildSendCardReq();
|
||||
|
||||
VspResponseDTO resp = new VspResponseDTO();
|
||||
resp.setCode(0);
|
||||
resp.setMsg("ok");
|
||||
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(VspResponseDTO.class)))
|
||||
.thenReturn(resp);
|
||||
|
||||
// 执行
|
||||
client.sendCard(req);
|
||||
|
||||
// 验证只调用一次
|
||||
verify(restTemplate, times(1)).postForObject(
|
||||
eq(BASE_URL + "/api/wechat/notify/send-card"),
|
||||
eq(req),
|
||||
eq(VspResponseDTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendCard_retryOnNetworkError() {
|
||||
VspSendCardReqDTO req = buildSendCardReq();
|
||||
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(VspResponseDTO.class)))
|
||||
.thenThrow(new RestClientException("Connection refused"));
|
||||
|
||||
// 执行
|
||||
client.sendCard(req);
|
||||
|
||||
// maxRetry=2,总共调用 1 + 2 = 3 次
|
||||
verify(restTemplate, times(3)).postForObject(
|
||||
eq(BASE_URL + "/api/wechat/notify/send-card"),
|
||||
eq(req),
|
||||
eq(VspResponseDTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendCard_noRetryOnBusinessError() {
|
||||
VspSendCardReqDTO req = buildSendCardReq();
|
||||
|
||||
VspResponseDTO resp = new VspResponseDTO();
|
||||
resp.setCode(-1);
|
||||
resp.setMsg("业务失败");
|
||||
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(VspResponseDTO.class)))
|
||||
.thenReturn(resp);
|
||||
|
||||
// 执行
|
||||
client.sendCard(req);
|
||||
|
||||
// 业务失败不重试,只调用一次
|
||||
verify(restTemplate, times(1)).postForObject(anyString(), any(), eq(VspResponseDTO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendCard_disabled() {
|
||||
properties.setEnabled(false);
|
||||
|
||||
VspSendCardReqDTO req = buildSendCardReq();
|
||||
|
||||
// 执行
|
||||
client.sendCard(req);
|
||||
|
||||
// 未启用时不调用 RestTemplate
|
||||
verify(restTemplate, never()).postForObject(anyString(), any(), any());
|
||||
}
|
||||
|
||||
// ==================== syncStatus 测试 ====================
|
||||
|
||||
@Test
|
||||
void syncStatus_success() {
|
||||
VspSyncStatusReqDTO req = VspSyncStatusReqDTO.builder()
|
||||
.alarmId("alarm-001")
|
||||
.orderId("10001")
|
||||
.status("confirmed")
|
||||
.operator("wechat_user_1")
|
||||
.remark("确认接单")
|
||||
.build();
|
||||
|
||||
VspResponseDTO resp = new VspResponseDTO();
|
||||
resp.setCode(0);
|
||||
resp.setMsg("ok");
|
||||
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(VspResponseDTO.class)))
|
||||
.thenReturn(resp);
|
||||
|
||||
// 执行
|
||||
client.syncStatus(req);
|
||||
|
||||
// 验证使用 sync-status URL
|
||||
verify(restTemplate, times(1)).postForObject(
|
||||
eq(BASE_URL + "/api/wechat/notify/sync-status"),
|
||||
eq(req),
|
||||
eq(VspResponseDTO.class));
|
||||
}
|
||||
|
||||
// ==================== 辅助方法 ====================
|
||||
|
||||
private VspSendCardReqDTO buildSendCardReq() {
|
||||
return VspSendCardReqDTO.builder()
|
||||
.alarmId("alarm-001")
|
||||
.orderId("10001")
|
||||
.userIds(List.of("wechat_user_1"))
|
||||
.title("入侵告警")
|
||||
.areaName("A栋大堂")
|
||||
.cameraName("大堂摄像头")
|
||||
.eventTime("03-24 10:00")
|
||||
.level(1)
|
||||
.snapshotUrl("http://example.com/snapshot.jpg")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user