Browse Source

feat: 新增盐源ws接口(通过AlarmPublisher发送ws)

yanyuan
yinhuaiwei 1 month ago
parent
commit
6aaae83f4f
18 changed files with 472 additions and 8 deletions
  1. +4
    -0
      inspect-base/inspect-base-core/src/main/java/com/inspect/base/core/web/domain/AjaxResult.java
  2. +1
    -2
      inspect-common/inspect-common-security/src/main/java/com/inspect/common/security/handler/GlobalExceptionHandler.java
  3. +10
    -1
      inspect-main/inspect-main-api/pom.xml
  4. +35
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/config/RabbitMQConfig.java
  5. +10
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/constant/YanyuanConstants.java
  6. +62
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/controller/AlarmController.java
  7. +17
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/domain/AlarmMessage.java
  8. +12
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/domain/ApiResult.java
  9. +12
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/domain/AuthTokenData.java
  10. +17
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/enums/AlarmCategory.java
  11. +14
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/enums/MessageType.java
  12. +15
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/enums/SystemCode.java
  13. +15
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/props/AppProperties.java
  14. +37
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/service/AlarmConsumer.java
  15. +26
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/service/AlarmPublisher.java
  16. +41
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/service/ExtAuthService.java
  17. +139
    -0
      inspect-main/inspect-main-api/src/main/java/com/inspect/api/websocket/AlarmWsConnection.java
  18. +5
    -5
      inspect-main/inspect-main-start/src/main/resources/bootstrap.yaml

+ 4
- 0
inspect-base/inspect-base-core/src/main/java/com/inspect/base/core/web/domain/AjaxResult.java View File

@ -63,6 +63,10 @@ public class AjaxResult extends HashMap<String, Object> {
return new AjaxResult(code, msg, null);
}
public static AjaxResult error(int code, String msg, Object data) {
return new AjaxResult(code, msg, data);
}
public static AjaxResult fail(Integer code, String msg, Object data) {
return new AjaxResult(code, msg, data);
}


+ 1
- 2
inspect-common/inspect-common-security/src/main/java/com/inspect/common/security/handler/GlobalExceptionHandler.java View File

@ -13,7 +13,6 @@ import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ -51,7 +50,7 @@ public class GlobalExceptionHandler {
public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request) {
log.error(e.getMessage(), e);
Integer code = e.getCode();
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
return StringUtils.isNotNull(code) ? AjaxResult.error(code, "服务器异常,请稍后再试", e.getMessage()) : AjaxResult.error("服务器异常,请稍后再试", e.getMessage());
}
@ExceptionHandler({RuntimeException.class})


+ 10
- 1
inspect-main/inspect-main-api/pom.xml View File

@ -22,7 +22,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@ -32,6 +31,16 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- WebSocket + STOMP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.inspect</groupId>
<artifactId>inspect-base-core</artifactId>


+ 35
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/config/RabbitMQConfig.java View File

@ -0,0 +1,35 @@
package com.inspect.api.config;
import com.inspect.api.constant.YanyuanConstants;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
@Bean
public TopicExchange alarmExchange() {
return new TopicExchange(YanyuanConstants.EXCHANGE, true, false);
}
@Bean("alarmQueue")
public Queue alarmQueue() {
return new Queue(YanyuanConstants.QUEUE, true);
}
@Bean
public Binding alarmBinding() {
return BindingBuilder.bind(alarmQueue()).to(alarmExchange()).with(YanyuanConstants.EXCHANGE);
}
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}

+ 10
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/constant/YanyuanConstants.java View File

@ -0,0 +1,10 @@
package com.inspect.api.constant;
public class YanyuanConstants {
private YanyuanConstants() {}
public static final String EXCHANGE = "alarm.exchange";
public static final String QUEUE = "alarm.queue";
public static final String ROUTING_KEY = "alarm.routing-key";
}

+ 62
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/controller/AlarmController.java View File

@ -0,0 +1,62 @@
package com.inspect.api.controller;
import com.inspect.api.domain.AlarmMessage;
import com.inspect.api.domain.ApiResult;
import com.inspect.api.domain.AuthTokenData;
import com.inspect.api.enums.AlarmCategory;
import com.inspect.api.enums.MessageType;
import com.inspect.api.enums.SystemCode;
import com.inspect.api.service.AlarmPublisher;
import com.inspect.api.service.ExtAuthService;
import com.inspect.base.core.web.controller.BaseController;
import com.inspect.base.core.web.domain.AjaxResult;
import com.inspect.base.core.web.page.TableDataInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/v1/api/alarm")
public class AlarmController extends BaseController {
private final ExtAuthService extAuthService;
private final AlarmPublisher alarmPublisher;
public AlarmController(ExtAuthService extAuthService, AlarmPublisher alarmPublisher) {
this.extAuthService = extAuthService;
this.alarmPublisher = alarmPublisher;
}
@PostMapping("/history")
@ResponseBody
public TableDataInfo list(AlarmMessage alarmMessage) {
startPage();
List<AlarmMessage> list = new ArrayList<>();
list.add(AlarmMessage.builder()
.messageType(MessageType.ALARM.getCode())
.alarmCategory(AlarmCategory.APPEARANCE_DEFECT.getCode())
.systemCode(SystemCode.PATROL.getCode())
.build());
// List<AlarmMessage> list = jobLogService.selectJobLogList(jobLog);
return getDataTable(list);
}
@GetMapping("/getToken")
public AjaxResult getToken(String clientId, String clientSecret) {
ApiResult<AuthTokenData> result = extAuthService.getAuthToken(clientId, clientSecret);
log.info("Result={}", result);
return AjaxResult.success(result.getData());
}
@PostMapping("/push")
@ResponseBody
public AjaxResult push(AlarmMessage msg) {
if (msg != null) {
alarmPublisher.publish(msg);
return AjaxResult.success(msg);
}
return AjaxResult.error();
}
}

+ 17
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/domain/AlarmMessage.java View File

@ -0,0 +1,17 @@
package com.inspect.api.domain;
import com.inspect.base.core.web.domain.BaseEntity;
import lombok.*;
@ToString
@Data
@Builder
public class AlarmMessage extends BaseEntity {
private String messageId;
private String messageType;
// 告警类型: messageType = alarm_push时传入
private String alarmCategory;
private String timestamp;
private String systemCode;
private Object data;
}

+ 12
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/domain/ApiResult.java View File

@ -0,0 +1,12 @@
package com.inspect.api.domain;
import lombok.Data;
@Data
public class ApiResult<T> {
private boolean success;
private T data;
private String hintMessage;
private String type;
private int code;
}

+ 12
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/domain/AuthTokenData.java View File

@ -0,0 +1,12 @@
package com.inspect.api.domain;
import lombok.Data;
@Data
public class AuthTokenData {
private String access_token;
private String token_type;
private String scope;
private String userId;
private String jti;
}

+ 17
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/enums/AlarmCategory.java View File

@ -0,0 +1,17 @@
package com.inspect.api.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum AlarmCategory {
FIRE_SMOKE("fire_smoke", "烟火报警"),
NO_HELMET("no_helmet", "未佩戴安全帽报警"),
NO_UNIFORM("no_uniform", "未穿工装报警"),
METER_OVERRUN("meter_overrun", "红外温度超限报警"),
APPEARANCE_DEFECT("appearance_defect", "外观缺陷告警");
final private String code;
final private String value;
}

+ 14
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/enums/MessageType.java View File

@ -0,0 +1,14 @@
package com.inspect.api.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum MessageType {
ALARM("alarm_push", "告警推送"),
REPORT("report_push", "报告推送");
final private String code;
final private String value;
}

+ 15
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/enums/SystemCode.java View File

@ -0,0 +1,15 @@
package com.inspect.api.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum SystemCode {
PE("power&environment", "动环"),
FIREFIGHTING("firefighting", "消防"),
PATROL("patrol", "巡检");
final private String code;
final private String value;
}

+ 15
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/props/AppProperties.java View File

@ -0,0 +1,15 @@
package com.inspect.api.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "yanyuan.auth")
public class AppProperties {
private String baseUrl;
private String wsUrl;
private String clientId;
private String clientSecret;
}

+ 37
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/service/AlarmConsumer.java View File

@ -0,0 +1,37 @@
package com.inspect.api.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspect.api.domain.AlarmMessage;
import com.inspect.api.websocket.AlarmWsConnection;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AlarmConsumer {
private final AlarmWsConnection wsConnection;
private final ObjectMapper objectMapper;
public AlarmConsumer(AlarmWsConnection wsConnection, ObjectMapper objectMapper) {
this.wsConnection = wsConnection;
this.objectMapper = objectMapper;
}
@RabbitListener(queues = "#{alarmQueue.name}")
public void onAlarm(AlarmMessage msg) {
try {
String json = objectMapper.writeValueAsString(msg);
boolean sent = wsConnection.send(json);
if (sent) {
log.info("Alarm sent to WS: msg={}", msg);
} else {
log.warn("Alarm not sent, WS not connected: msg={}", msg);
throw new RuntimeException("WS not connected, message will be requeued");
}
} catch (Exception e) {
log.error("Alarm consumer error: {}", e.getMessage());
throw new RuntimeException("Alarm processing failed", e);
}
}
}

+ 26
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/service/AlarmPublisher.java View File

@ -0,0 +1,26 @@
package com.inspect.api.service;
import com.inspect.api.constant.YanyuanConstants;
import com.inspect.api.domain.AlarmMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AlarmPublisher {
private final RabbitTemplate rabbitTemplate;
public AlarmPublisher(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void publish(AlarmMessage msg) {
try {
rabbitTemplate.convertAndSend(YanyuanConstants.EXCHANGE, YanyuanConstants.ROUTING_KEY, msg);
log.info("Alert published: msg={}", msg);
} catch (Exception e) {
log.error("Failed to publish alert: {}", e.getMessage());
}
}
}

+ 41
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/service/ExtAuthService.java View File

@ -0,0 +1,41 @@
package com.inspect.api.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspect.api.domain.ApiResult;
import com.inspect.api.domain.AuthTokenData;
import com.inspect.api.props.AppProperties;
import com.inspect.base.core.utils.HttpClientUtils;
import org.springframework.stereotype.Service;
@Service
public class ExtAuthService {
private static final String TOKEN_HEADER = "joinbright-token";
private final ObjectMapper objectMapper;
private final AppProperties appProperties;
public ExtAuthService(ObjectMapper objectMapper, AppProperties appProperties) {
this.objectMapper = objectMapper;
this.appProperties = appProperties;
}
public ApiResult<AuthTokenData> getAuthToken() {
return getAuthToken(appProperties.getClientId(), appProperties.getClientSecret());
}
public ApiResult<AuthTokenData> getAuthToken(String clientId, String clientSecret) {
String url = appProperties.getBaseUrl() + "/ext_auth/getAuthToken";
String param = "clientId=" + clientId + "&clientSecret=" + clientSecret;
return executeGet(url, param, new TypeReference<ApiResult<AuthTokenData>>() {});
}
private <T> ApiResult<T> executeGet(String url, String param, TypeReference<ApiResult<T>> typeRef) {
try {
String json = HttpClientUtils.get(url, param);
return objectMapper.readValue(json, typeRef);
} catch (Exception e) {
throw new RuntimeException("HTTP GET failed: " + url, e);
}
}
}

+ 139
- 0
inspect-main/inspect-main-api/src/main/java/com/inspect/api/websocket/AlarmWsConnection.java View File

@ -0,0 +1,139 @@
package com.inspect.api.websocket;
import com.inspect.api.domain.ApiResult;
import com.inspect.api.domain.AuthTokenData;
import com.inspect.api.props.AppProperties;
import com.inspect.api.service.ExtAuthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import javax.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
@Component
public class AlarmWsConnection {
private final ExtAuthService extAuthService;
private final AppProperties appProperties;
private final StandardWebSocketClient wsClient;
private final AtomicReference<WebSocketSession> sessionRef = new AtomicReference<>();
private final AtomicInteger reconnectBackoff = new AtomicInteger(5);
private volatile boolean connecting = false;
public AlarmWsConnection(ExtAuthService extAuthService, AppProperties appProperties) {
this.extAuthService = extAuthService;
this.appProperties = appProperties;
this.wsClient = new StandardWebSocketClient();
}
@PostConstruct
public void init() {
connect();
}
public void connect() {
if (connecting) {
return;
}
connecting = true;
try {
ApiResult<AuthTokenData> result = extAuthService.getAuthToken();
if (!result.isSuccess() || result.getData() == null) {
log.error("Alarm WS: failed to get auth token, retry in {}s", reconnectBackoff.get());
connecting = false;
return;
}
String token = result.getData().getAccess_token();
String wsUrl = appProperties.getWsUrl() + "?Joinbright-Token=" + token;
wsClient.doHandshake(new AlarmWsHandler(), wsUrl)
.addCallback(
session -> {
sessionRef.set(session);
reconnectBackoff.set(5);
connecting = false;
log.info("Alarm WS connected: {}", session.getId());
},
ex -> {
connecting = false;
log.error("Alarm WS handshake failed: {}", ex.getMessage());
}
);
} catch (Exception e) {
connecting = false;
log.error("Alarm WS connect error: {}", e.getMessage());
}
}
@Scheduled(fixedDelay = 1000)
public void reconnect() {
WebSocketSession session = sessionRef.get();
if (session != null && session.isOpen()) {
return;
}
if (connecting) {
return;
}
int delay = reconnectBackoff.get();
log.info("Alarm WS reconnecting in {}s", delay);
try {
Thread.sleep(delay * 1000L);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
return;
}
int nextDelay = Math.min(delay * 2, 60);
reconnectBackoff.set(nextDelay);
connect();
}
public boolean send(String message) {
WebSocketSession session = sessionRef.get();
if (session == null || !session.isOpen()) {
log.warn("Alarm WS not connected, message dropped: {}", message);
return false;
}
try {
synchronized (session) {
session.sendMessage(new TextMessage(message));
}
return true;
} catch (Exception e) {
log.error("Alarm WS send failed: {}", e.getMessage());
return false;
}
}
public boolean isConnected() {
WebSocketSession session = sessionRef.get();
return session != null && session.isOpen();
}
private class AlarmWsHandler extends TextWebSocketHandler {
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
log.warn("Alarm WS closed: {}", status);
sessionRef.compareAndSet(session, null);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
log.info("Alarm WS received: {}", message.getPayload());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable ex) {
log.error("Alarm WS transport error: {}", ex.getMessage());
sessionRef.compareAndSet(session, null);
}
}
}

+ 5
- 5
inspect-main/inspect-main-start/src/main/resources/bootstrap.yaml View File

@ -6,15 +6,15 @@ server:
spring:
application:
# 应用名称
name: dliip-patrol
name: inspect-main
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
server-addr: 192.168.0.115:8848
namespace: 69445dc4-9c24-4814-ac93-ff14f1438c36
server-addr: http://192.168.1.116:8848
namespace: cf5b4192-f657-4012-b158-566325bae171
#server-addr: 192.168.0.114:8848
#namespace: 744b9c6a-5855-44cf-b537-808c0166d8f5
config:
@ -26,10 +26,10 @@ spring:
group: DEFAULT_GROUP
# 共享配置
shared-configs:
- dliip-patrol-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
- inspect-main-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
#dev-llc
# namespace: 6b358531-5084-4f9c-84f2-f732d0b2af39
main:
allow-bean-definition-overriding: true
allow-circular-references: true
allow-circular-references: true

Loading…
Cancel
Save