From 2c62939aeb8c55e351511853a37335f9d24d28a2 Mon Sep 17 00:00:00 2001
From: caoyizhong <1270296080>
Date: Fri, 1 Dec 2023 18:59:05 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0web=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/constant/ModuleNameConstant.java | 4 +
.../entity/AftersalesExchangeEntity.java | 17 +++
blade-service/logpm-aftersales/pom.xml | 11 ++
.../aftersales/AftersalesApplication.java | 12 ++
.../aftersales/config/WebSocketConfig.java | 38 +++++++
.../launcher/OpcSessionHandler.java | 78 +++++++++++++
.../aftersales/resp/NoticeWebsocketResp.java | 20 ++++
.../aftersales/service/WebSocketServer.java | 105 ++++++++++++++++++
.../impl/AftersalesExchangeServiceImpl.java | 12 +-
9 files changed, 295 insertions(+), 2 deletions(-)
create mode 100644 blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/config/WebSocketConfig.java
create mode 100644 blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/launcher/OpcSessionHandler.java
create mode 100644 blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/resp/NoticeWebsocketResp.java
create mode 100644 blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/WebSocketServer.java
diff --git a/blade-biz-common/src/main/java/org/springblade/common/constant/ModuleNameConstant.java b/blade-biz-common/src/main/java/org/springblade/common/constant/ModuleNameConstant.java
index 95746ccec..153720380 100644
--- a/blade-biz-common/src/main/java/org/springblade/common/constant/ModuleNameConstant.java
+++ b/blade-biz-common/src/main/java/org/springblade/common/constant/ModuleNameConstant.java
@@ -46,6 +46,10 @@ public interface ModuleNameConstant {
* 仓库服务名称
*/
String APPLICATION_WAREHOUSE_NAME = "logpm-warehouse"+DEVAUTH;
+ /**
+ * 仓库服务名称
+ */
+ String APPLICATION_WEBSTOCKET_NAME = "logpm-webstocket"+DEVAUTH;
/**
* 配送签收服务名称
diff --git a/blade-service-api/logpm-aftersales-api/src/main/java/com/logpm/aftersales/entity/AftersalesExchangeEntity.java b/blade-service-api/logpm-aftersales-api/src/main/java/com/logpm/aftersales/entity/AftersalesExchangeEntity.java
index 1bc9169c1..2e9dd1da4 100644
--- a/blade-service-api/logpm-aftersales-api/src/main/java/com/logpm/aftersales/entity/AftersalesExchangeEntity.java
+++ b/blade-service-api/logpm-aftersales-api/src/main/java/com/logpm/aftersales/entity/AftersalesExchangeEntity.java
@@ -92,4 +92,21 @@ public class AftersalesExchangeEntity extends TenantEntity {
@ApiModelProperty(value = "仓库ID")
private String warehouseId;
+
+ @Override
+ public String toString() {
+ return "AftersalesExchangeEntity{" +
+ "reserve1='" + reserve1 + '\'' +
+ ", reserve2='" + reserve2 + '\'' +
+ ", reserve3='" + reserve3 + '\'' +
+ ", reserve4='" + reserve4 + '\'' +
+ ", reserve5='" + reserve5 + '\'' +
+ ", workOrderId='" + workOrderId + '\'' +
+ ", businessName='" + businessName + '\'' +
+ ", businessId='" + businessId + '\'' +
+ ", content='" + content + '\'' +
+ ", annex='" + annex + '\'' +
+ ", warehouseId='" + warehouseId + '\'' +
+ '}';
+ }
}
diff --git a/blade-service/logpm-aftersales/pom.xml b/blade-service/logpm-aftersales/pom.xml
index a934b97bb..b093409c6 100644
--- a/blade-service/logpm-aftersales/pom.xml
+++ b/blade-service/logpm-aftersales/pom.xml
@@ -16,6 +16,17 @@
jar
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+ spring-boot-starter-tomcat
+ org.springframework.boot
+
+
+
org.springblade
blade-core-boot
diff --git a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/AftersalesApplication.java b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/AftersalesApplication.java
index b0db4c432..dac63b988 100644
--- a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/AftersalesApplication.java
+++ b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/AftersalesApplication.java
@@ -19,6 +19,9 @@ package com.logpm.aftersales;
import org.springblade.common.constant.ModuleNameConstant;
import org.springblade.core.cloud.client.BladeCloudApplication;
import org.springblade.core.launch.BladeApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* Demo启动器
@@ -26,11 +29,20 @@ import org.springblade.core.launch.BladeApplication;
* @author Chill
*/
@BladeCloudApplication
+//@EnableWebSocket
public class AftersalesApplication {
public static void main(String[] args) {
BladeApplication.run(ModuleNameConstant.APPLICATION_AFTERSALES_NAME, AftersalesApplication.class, args);
}
+ /**
+ * 如果直接使用springboot的内置容器,而不是使用独立的servlet容器,就要注入ServerEndpointExporter,外部容器则不需要。
+ */
+/* @Bean
+ public ServerEndpointExporter serverEndpointExporter() {
+ return new ServerEndpointExporter();
+ }*/
+
}
diff --git a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/config/WebSocketConfig.java b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/config/WebSocketConfig.java
new file mode 100644
index 000000000..ce3c898b7
--- /dev/null
+++ b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/config/WebSocketConfig.java
@@ -0,0 +1,38 @@
+package com.logpm.aftersales.config;
+
+import com.logpm.aftersales.launcher.OpcSessionHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+import javax.annotation.Resource;
+
+/**
+ * 开启WebSocket支持
+ * @author 12702
+ */
+@Slf4j
+@Configuration
+@EnableWebSocket
+@ConditionalOnProperty(name = "system.websocket.isOpen",havingValue = "true")
+//@ConditionalOnProperty(name = "spring.profiles.active",havingValue = "dev")
+public class WebSocketConfig implements WebSocketConfigurer {
+
+ @Resource
+ private OpcSessionHandler opcSessionHandler;
+
+// @Bean
+// public ServerEndpointExporter serverEndpointExporter() {
+// return new ServerEndpointExporter();
+// }
+
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ registry.addHandler(opcSessionHandler, "/ws/automate").setAllowedOrigins("*");
+ }
+}
diff --git a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/launcher/OpcSessionHandler.java b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/launcher/OpcSessionHandler.java
new file mode 100644
index 000000000..122e63215
--- /dev/null
+++ b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/launcher/OpcSessionHandler.java
@@ -0,0 +1,78 @@
+package com.logpm.aftersales.launcher;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.*;
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * @author tarzan
+ */
+@Component
+@Slf4j
+public class OpcSessionHandler implements WebSocketHandler {
+
+
+
+ private static final CopyOnWriteArraySet SESSIONS=new CopyOnWriteArraySet<>();
+
+
+ private final static String ALERT="alert";
+ private final static String CONTROL="control";
+
+ @Override
+ public void afterConnectionEstablished(@NonNull WebSocketSession session) throws Exception {
+ SESSIONS.add(session);
+ log.info(session.getId()+" OpcSessionHandler当前在线人数:"+SESSIONS.size());
+ }
+
+ @Override
+ public void handleMessage(WebSocketSession session, WebSocketMessage> message) throws Exception {
+ String msg = message.getPayload().toString();
+ log.info("接收消息"+session.getId()+":"+msg);
+
+ }
+
+
+
+ @Override
+ public void handleTransportError(WebSocketSession session,@NonNull Throwable exception) throws Exception {
+ log.error("OpcSessionHandler连接出错"+session.getId());
+ SESSIONS.remove(session);
+ if (!session.isOpen()) {
+ session.close();
+ }
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, @NonNull CloseStatus closeStatus) throws Exception {
+ log.info("OpcSessionHandler关闭连接"+session.getId());
+ SESSIONS.remove(session);
+ }
+
+
+ @Override
+ public boolean supportsPartialMessages() {
+ return false;
+ }
+
+
+ public void sendMessageToUser(WebSocketSession session, String contents) {
+ if (session != null && session.isOpen()) {
+ TextMessage message = new TextMessage(contents);
+ try {
+ session.sendMessage(message);
+ } catch (IOException e) {
+ log.error(e.getMessage());
+ }
+ }
+ }
+
+ public void sendMessageToAllUsers(String contents) {
+ SESSIONS.forEach(session->sendMessageToUser(session, contents));
+ }
+
+}
diff --git a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/resp/NoticeWebsocketResp.java b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/resp/NoticeWebsocketResp.java
new file mode 100644
index 000000000..f947a4fe1
--- /dev/null
+++ b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/resp/NoticeWebsocketResp.java
@@ -0,0 +1,20 @@
+package com.logpm.aftersales.resp;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author 12702
+ */
+@Data
+@ApiModel("ws通知返回对象")
+public class NoticeWebsocketResp {
+
+ @ApiModelProperty(value = "通知类型")
+ private String noticeType;
+
+ @ApiModelProperty(value = "通知内容")
+ private T noticeInfo;
+
+}
diff --git a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/WebSocketServer.java b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/WebSocketServer.java
new file mode 100644
index 000000000..2a65474af
--- /dev/null
+++ b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/WebSocketServer.java
@@ -0,0 +1,105 @@
+package com.logpm.aftersales.service;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.logpm.aftersales.config.WebSocketConfig;
+import lombok.EqualsAndHashCode;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.tool.utils.CollectionUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * @author tarzan
+ */
+@ConditionalOnClass(value = WebSocketConfig.class)
+@ServerEndpoint("/ws/automate")
+@Slf4j
+@EqualsAndHashCode
+public class WebSocketServer {
+
+ /** 虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。 */
+ private static final CopyOnWriteArraySet WEBSOCKET_CLIENTS =new CopyOnWriteArraySet<>();
+ /** 当前session */
+ private Session session;
+ /** 当前session订阅的话题 */
+ private List topics;
+
+ public WebSocketServer() {
+ }
+
+ @OnOpen
+ public void onOpen(Session session) {
+ this.session = session;
+ WEBSOCKET_CLIENTS.add(this);
+ log.info("WebSocketServer有新客户端连接加入:{},当前在线人数为:{}", session.getId(),WEBSOCKET_CLIENTS.size());
+ }
+
+ @OnClose
+ public void onClose() {
+ WEBSOCKET_CLIENTS.remove(this);
+ log.info("有一连接关闭:{},当前在线人数为:{}", this.session.getId(), WEBSOCKET_CLIENTS.size());
+ }
+
+ @OnMessage
+ public void onMessage(String message, Session session) {
+ this.topics= Func.toStrList(message);
+ log.info("服务端收到客户端[{}]的消息:{}", session.getId(), message);
+ }
+
+ @OnError
+ public void onError(Session session, Throwable error) {
+ log.error("发生错误:"+error.getMessage());
+ WEBSOCKET_CLIENTS.remove(this);
+ log.info("有一连接异常:{},当前在线人数为:{}", session.getId(), WEBSOCKET_CLIENTS.size());
+ }
+
+ public void sendData(T data, String topicName) {
+ JSONObject result=new JSONObject();
+ result.put("topic",topicName);
+ result.put("data",data);
+ //显示值为null的字段
+ // String jsonString = JSON.toJSONString(result, SerializerFeature.WriteMapNullValue);
+ sendMessage(result.toString(),topicName);
+ }
+
+ /**
+ * 发送消息广播
+ *
+ * @param message 消息文本
+ * @author tarzan
+ * @date 2022年12月08日 09:24:34
+ */
+ public void sendMessage(String message,String topic){
+ try {
+ WEBSOCKET_CLIENTS.forEach(client ->{
+ if (client.session.isOpen()&&CollectionUtil.isNotEmpty(client.topics)&&client.topics.contains(topic)) {
+ client.session.getAsyncRemote().sendText(message);
+ }
+ });
+ } catch (Exception e) {
+ log.error(e.getMessage());
+ }
+ }
+
+ public static void sendMessageToAllUsers(String message){
+ try {
+ WEBSOCKET_CLIENTS.forEach(client -> {
+ if (client.session.isOpen()) {
+ client.session.getAsyncRemote().sendText(message);
+ }
+ });
+ } catch (Exception e) {
+ log.error(e.getMessage());
+ }
+ }
+
+
+}
diff --git a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/impl/AftersalesExchangeServiceImpl.java b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/impl/AftersalesExchangeServiceImpl.java
index 0c698aebc..8613b1323 100644
--- a/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/impl/AftersalesExchangeServiceImpl.java
+++ b/blade-service/logpm-aftersales/src/main/java/com/logpm/aftersales/service/impl/AftersalesExchangeServiceImpl.java
@@ -19,14 +19,16 @@ package com.logpm.aftersales.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.logpm.aftersales.entity.AftersalesExchangeEntity;
+import com.logpm.aftersales.service.WebSocketServer;
import com.logpm.aftersales.vo.AftersalesExchangeVO;
import com.logpm.aftersales.excel.AftersalesExchangeExcel;
import com.logpm.aftersales.mapper.AftersalesExchangeMapper;
import com.logpm.aftersales.service.IAftersalesExchangeService;
+import lombok.AllArgsConstructor;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
-import org.springblade.core.tool.utils.AesUtil;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -43,8 +45,11 @@ import java.util.Map;
* @since 2023-11-17
*/
@Service
+@AllArgsConstructor
public class AftersalesExchangeServiceImpl extends BaseServiceImpl implements IAftersalesExchangeService {
+ private static int count=0;
+
@Override
public IPage selectAftersalesExchangePage(IPage page, AftersalesExchangeVO aftersalesExchange) {
return page.setRecords(baseMapper.selectAftersalesExchangePage(page, aftersalesExchange));
@@ -69,6 +74,7 @@ public class AftersalesExchangeServiceImpl extends BaseServiceImpl