diff --git a/nflg-mobilebroken-admin/pom.xml b/nflg-mobilebroken-admin/pom.xml
index 2a39765d..58685ac6 100644
--- a/nflg-mobilebroken-admin/pom.xml
+++ b/nflg-mobilebroken-admin/pom.xml
@@ -119,8 +119,8 @@
org.apache.maven.plugins
maven-compiler-plugin
- 10
- 10
+ 11
+ 11
diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/AdminApplication.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/AdminApplication.java
index cd15c5c0..7b45e487 100644
--- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/AdminApplication.java
+++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/AdminApplication.java
@@ -8,12 +8,14 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@MapperScan("com.nflg.mobilebroken.repository.mapper")
@ComponentScan(basePackages = {"com.nflg.mobilebroken.repository.service", "com.nflg.mobilebroken.admin"
, "com.nflg.mobilebroken.starter"})
@EnableDiscoveryClient
+@EnableScheduling
@Slf4j
@EnableAsync
public class AdminApplication {
diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
index d34ad7df..b1d1f529 100644
--- a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
+++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
@@ -1,28 +1,25 @@
package com.nflg.mobilebroken.admin.controller;
import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.layout.font.FontProvider;
import com.nflg.mobilebroken.admin.annotation.ApiMark;
import com.nflg.mobilebroken.admin.publisher.TicketEventPublisher;
+import com.nflg.mobilebroken.admin.service.SsePushService;
import com.nflg.mobilebroken.common.constant.STATE;
import com.nflg.mobilebroken.common.constant.TicketState;
import com.nflg.mobilebroken.common.exception.NflgException;
import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
-import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
-import com.nflg.mobilebroken.common.pojo.dto.TicketChatDTO;
import com.nflg.mobilebroken.common.pojo.request.*;
import com.nflg.mobilebroken.common.pojo.vo.*;
import com.nflg.mobilebroken.common.util.*;
import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
import com.nflg.mobilebroken.starter.annotation.MethodInfoMark;
-import com.nflg.mobilebroken.starter.service.impl.APPSSEManagerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
@@ -42,8 +39,6 @@ import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -77,7 +72,7 @@ public class TicketController extends ControllerBase {
private TicketChatService ticketChatService;
@Resource
- private APPSSEManagerService sseManagerService;
+ private SsePushService ssePushService;
@Resource
private IAppAreaService appAreaService;
@@ -204,25 +199,18 @@ public class TicketController extends ControllerBase {
@ApiMark(moduleName = "工单管理", apiName = "分派工单")
public ApiResult assignmentTicket(@Valid @RequestBody AssignmentTicketRequest request) {
Ticket ticket=ticketService.assignmentTicket(request);
- TicketChatDTO message=new TicketChatDTO()
- .setTicketId(ticket.getId())
- .setMessages(Collections.singletonList(new ChatMessageDTO()
- .setFrom("system")
- .setTicketState(ticket.getState())
- .setSenderId(0)
- .setSenderName("服务助手")
- .setCreateTime(Instant.now())
- .setContent("已为您分派工程师
如需补充信息,请继续留言。")));
- ticketChatService.add(message);
- try {
- SSEMessageDTO messageDTO = new SSEMessageDTO()
- .setType(1)
- .setData(message);
- sseManagerService.send(ticket.getUserId(), messageDTO);
- } catch (IOException e) {
- log.error("发送SSE消息出错", e);
- }
ticketEventPublisher.publishTicketAssignedEvent(ticket,request.getUserIds());
+ ChatMessageDTO message = new ChatMessageDTO()
+ .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
+ .setFrom("system")
+ .setTicketState(ticket.getState())
+ .setSenderId(0)
+ .setSenderName("服务助手")
+ .setContent("已为您分派工程师
如需补充信息,请继续留言。")
+ .setCreateTime(Instant.now());
+ ticketChatService.addMessage(ticket.getId(), message);
+ //推送消息
+ ssePushService.sendTicketMessageToApp(ticket.getUserId(),message);
return ApiResult.success();
}
@@ -261,23 +249,22 @@ public class TicketController extends ControllerBase {
for (Integer id : ids){
Ticket ticket=ticketService.completeTicket(id);
ticketEventPublisher.publishTicketCompleteEvent(ticket);
- TicketChatDTO message=new TicketChatDTO()
- .setTicketId(ticket.getId())
- .setMessages(Collections.singletonList(new ChatMessageDTO()
- .setFrom("system")
- .setTicketState(ticket.getState())
- .setSenderId(0)
- .setSenderName("服务助手")
- .setCreateTime(Instant.now())
- .setContent("工单已完成
工单已完成,如需补充信息,请重新打开工单,继续留言。")));
- ticketChatService.add(message);
- try {
- SSEMessageDTO messageDTO = new SSEMessageDTO()
- .setType(1)
- .setData(message);
- sseManagerService.send(ticket.getUserId(), messageDTO);
- } catch (IOException e) {
- log.error("发送SSE消息出错", e);
+ ChatMessageDTO message = new ChatMessageDTO()
+ .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
+ .setFrom("system")
+ .setTicketState(ticket.getState())
+ .setSenderId(0)
+ .setSenderName("服务助手")
+ .setContent("工单已完成
工单已完成,如需补充信息,请重新打开工单,继续留言。")
+ .setCreateTime(Instant.now());
+ ticketChatService.addMessage(id, message);
+ //推送消息
+ ssePushService.sendTicketMessageToApp(ticket.getUserId(),message);
+ List handles = Arrays.stream(ticket.getHandle().split(","))
+ .map(Integer::parseInt).collect(Collectors.toList());
+ handles.remove(AdminUserUtil.getUserId());
+ if (CollectionUtil.isNotEmpty(handles)){
+ handles.forEach(uid->ssePushService.sendTicketMessageToAdmin(uid,message));
}
}
return ApiResult.success();
@@ -293,23 +280,22 @@ public class TicketController extends ControllerBase {
public ApiResult closeTicket(@Valid @RequestBody TicketCloseRequest request) {
Ticket ticket=ticketService.closeTicket(request);
ticketEventPublisher.publishTicketCloseEvent(ticket);
- TicketChatDTO message=new TicketChatDTO()
- .setTicketId(ticket.getId())
- .setMessages(Collections.singletonList(new ChatMessageDTO()
- .setFrom("system")
- .setTicketState(ticket.getState())
- .setSenderId(0)
- .setSenderName("服务助手")
- .setCreateTime(Instant.now())
- .setContent("工单已关闭
感谢你的使用,如有问题,请重新提交新的工单。")));
- ticketChatService.add(message);
- try {
- SSEMessageDTO messageDTO = new SSEMessageDTO()
- .setType(1)
- .setData(message);
- sseManagerService.send(ticket.getUserId(), messageDTO);
- } catch (IOException e) {
- log.error("发送SSE消息出错", e);
+ ChatMessageDTO message = new ChatMessageDTO()
+ .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
+ .setFrom("system")
+ .setTicketState(ticket.getState())
+ .setSenderId(0)
+ .setSenderName("服务助手")
+ .setContent("工单已关闭
感谢你的使用,如有问题,请重新提交新的工单。")
+ .setCreateTime(Instant.now());
+ ticketChatService.addMessage(request.getTicketId(), message);
+ //推送消息
+ ssePushService.sendTicketMessageToApp(ticket.getUserId(),message);
+ List handles = Arrays.stream(ticket.getHandle().split(","))
+ .map(Integer::parseInt).collect(Collectors.toList());
+ handles.remove(AdminUserUtil.getUserId());
+ if (CollectionUtil.isNotEmpty(handles)){
+ handles.forEach(uid->ssePushService.sendTicketMessageToAdmin(uid,message));
}
return ApiResult.success();
}
@@ -545,8 +531,10 @@ public class TicketController extends ControllerBase {
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.Processing.getState()))
.throwMessage("当前工单状态不允许发送消息");
- VUtils.trueThrowBusinessError(Arrays.stream(ticket.getHandle().split(","))
- .noneMatch(uid -> StrUtil.equals(uid, AdminUserUtil.getUserId().toString())))
+ List handles=Arrays.stream(ticket.getHandle().split(","))
+ .map(Integer::parseInt).collect(Collectors.toList());
+ VUtils.trueThrowBusinessError(handles.stream()
+ .noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId())))
.throwMessage("只有工单处理人能发送消息");
ticket.setCurrentHandle(AdminUserUtil.getUserId());
ticketService.updateById(ticket);
@@ -568,38 +556,10 @@ public class TicketController extends ControllerBase {
}
ticketChatService.addMessage(request.getTicketId(), message);
//推送消息
- try {
- String zone = MultilingualUtil.getZone();
- ZoneId zoneId = ZoneId.of(zone);
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).withZone(zoneId);
- ChatMessageVO messageVO = new ChatMessageVO()
- .setId(message.getId())
- .setFrom(message.getFrom())
- .setSenderId(message.getSenderId())
- .setSenderName(message.getSenderName())
- .setSenderAvatar(message.getSenderAvatar())
- .setContent(message.getContent())
- .setTicketState(message.getTicketState())
- .setCreateTime(formatter.format(message.getCreateTime()))
- .setImages(message.getImages())
- .setAttachments(message.getAttachments())
- .setQuote(Objects.isNull(message.getQuote()) ? null : new ChatMessageVO()
- .setId(message.getQuote().getId())
- .setFrom(message.getQuote().getFrom())
- .setSenderId(message.getQuote().getSenderId())
- .setSenderName(message.getQuote().getSenderName())
- .setSenderAvatar(message.getQuote().getSenderAvatar())
- .setTicketState(message.getQuote().getTicketState())
- .setContent(message.getQuote().getContent())
- .setAttachments(message.getQuote().getAttachments())
- .setImages(message.getQuote().getImages())
- .setCreateTime(formatter.format(message.getQuote().getCreateTime())));
- SSEMessageDTO messageDTO = new SSEMessageDTO()
- .setType(1)
- .setData(messageVO);
- sseManagerService.send(ticket.getUserId(), messageDTO);
- } catch (IOException e) {
- log.error("发送SSE消息出错", e);
+ ssePushService.sendTicketMessageToApp(ticket.getUserId(),message);
+ handles.remove(AdminUserUtil.getUserId());
+ if (CollectionUtil.isNotEmpty(handles)){
+ handles.forEach(uid->ssePushService.sendTicketMessageToAdmin(uid,message));
}
ticketEventPublisher.publishTicketReplyEvent(ticket);
return ApiResult.success();
diff --git a/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/SsePushService.java b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/SsePushService.java
new file mode 100644
index 00000000..d47667db
--- /dev/null
+++ b/nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/service/SsePushService.java
@@ -0,0 +1,82 @@
+package com.nflg.mobilebroken.admin.service;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.json.JSONUtil;
+import com.nflg.mobilebroken.common.pojo.ApiResult;
+import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
+import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
+import com.nflg.mobilebroken.common.pojo.request.PushRequest;
+import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO;
+import com.nflg.mobilebroken.common.util.MultilingualUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+
+@Slf4j
+@Component
+@RefreshScope
+public class SsePushService {
+
+ @Value("${sse.url}")
+ private String sseUrl;
+
+ public void sendTicketMessageToAdmin(Integer userId, ChatMessageDTO message){
+ try {
+ PushRequest request=new PushRequest().setUserId(userId).setMessage(buildMessage(message));
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity response = restTemplate.postForEntity(sseUrl+"/sse/admin/push",request, ApiResult.class);
+ log.debug("发送消息结果:{}", JSONUtil.toJsonStr(response.getBody()));
+ } catch (Exception e) {
+ log.error("发送消息出错", e);
+ }
+ }
+
+ public void sendTicketMessageToApp(Integer userId, ChatMessageDTO message){
+ try {
+ PushRequest request=new PushRequest().setUserId(userId).setMessage(buildMessage(message));
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity response = restTemplate.postForEntity(sseUrl+"/sse/app/push",request, ApiResult.class);
+ log.debug("发送消息结果:{}", JSONUtil.toJsonStr(response.getBody()));
+ } catch (Exception e) {
+ log.error("发送消息出错", e);
+ }
+ }
+
+ private SSEMessageDTO buildMessage(ChatMessageDTO message){
+ String zone = MultilingualUtil.getZone();
+ ZoneId zoneId = ZoneId.of(zone);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).withZone(zoneId);
+ ChatMessageVO messageVO = new ChatMessageVO()
+ .setId(message.getId())
+ .setFrom(message.getFrom())
+ .setSenderId(message.getSenderId())
+ .setSenderName(message.getSenderName())
+ .setSenderAvatar(message.getSenderAvatar())
+ .setContent(message.getContent())
+ .setTicketState(message.getTicketState())
+ .setCreateTime(formatter.format(message.getCreateTime()))
+ .setImages(message.getImages())
+ .setAttachments(message.getAttachments())
+ .setQuote(Objects.isNull(message.getQuote()) ? null : new ChatMessageVO()
+ .setId(message.getQuote().getId())
+ .setFrom(message.getQuote().getFrom())
+ .setSenderId(message.getQuote().getSenderId())
+ .setSenderName(message.getQuote().getSenderName())
+ .setSenderAvatar(message.getQuote().getSenderAvatar())
+ .setTicketState(message.getQuote().getTicketState())
+ .setContent(message.getQuote().getContent())
+ .setAttachments(message.getQuote().getAttachments())
+ .setImages(message.getQuote().getImages())
+ .setCreateTime(formatter.format(message.getQuote().getCreateTime())));
+ return new SSEMessageDTO()
+ .setType(1)
+ .setData(messageVO);
+ }
+}
diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/CfsApplication.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/CfsApplication.java
index 5b70c53a..3a3acf91 100644
--- a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/CfsApplication.java
+++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/CfsApplication.java
@@ -6,12 +6,14 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@MapperScan("com.nflg.mobilebroken.repository.mapper")
@ComponentScan(basePackages = {"com.nflg.mobilebroken.repository.service", "com.nflg.mobilebroken.cfs"
,"com.nflg.mobilebroken.starter"})
@EnableDiscoveryClient
+@EnableScheduling
@EnableAsync
public class CfsApplication {
diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TiketController.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TiketController.java
index c3fd8e14..e4290aac 100644
--- a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TiketController.java
+++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/controller/TiketController.java
@@ -1,17 +1,16 @@
package com.nflg.mobilebroken.cfs.controller;
import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.mobilebroken.cfs.publisher.TicketEventPublisher;
+import com.nflg.mobilebroken.cfs.service.SsePushService;
import com.nflg.mobilebroken.common.constant.Constant;
import com.nflg.mobilebroken.common.constant.TicketState;
import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
-import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import com.nflg.mobilebroken.common.pojo.dto.TicketChatDTO;
import com.nflg.mobilebroken.common.pojo.request.*;
import com.nflg.mobilebroken.common.pojo.vo.*;
@@ -21,7 +20,6 @@ import com.nflg.mobilebroken.common.util.PageUtil;
import com.nflg.mobilebroken.common.util.VUtils;
import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
-import com.nflg.mobilebroken.starter.service.impl.AdminSSEManagerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
@@ -30,10 +28,7 @@ import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
-import java.io.IOException;
import java.time.Instant;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@@ -65,9 +60,6 @@ public class TiketController extends ControllerBase {
@Resource
private ITicketEvaluateService ticketEvaluateService;
- @Resource
- private IAdminMessageService adminMessageService;
-
@Resource
private IDictionaryItemTranslateService dictionaryItemTranslateService;
@@ -84,7 +76,7 @@ public class TiketController extends ControllerBase {
private ITBaseCustomerService customerService;
@Resource
- private AdminSSEManagerService sseManagerService;
+ private SsePushService ssePushService;
@Resource
private TicketEventPublisher ticketEventPublisher;
@@ -339,43 +331,10 @@ public class TiketController extends ControllerBase {
}
ticketChatService.addMessage(request.getTicketId(), message);
//推送消息
- String handle = ticket.getHandle();
- if (StrUtil.isNotBlank(handle)) {
- String zone = MultilingualUtil.getZone();
- ZoneId zoneId = ZoneId.of(zone);
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).withZone(zoneId);
- ChatMessageVO messageVO = new ChatMessageVO()
- .setId(message.getId())
- .setFrom(message.getFrom())
- .setSenderId(message.getSenderId())
- .setSenderName(message.getSenderName())
- .setSenderAvatar(message.getSenderAvatar())
- .setContent(message.getContent())
- .setTicketState(message.getTicketState())
- .setCreateTime(formatter.format(message.getCreateTime()))
- .setImages(message.getImages())
- .setAttachments(message.getAttachments())
- .setQuote(Objects.isNull(message.getQuote()) ? null : new ChatMessageVO()
- .setId(message.getQuote().getId())
- .setFrom(message.getQuote().getFrom())
- .setSenderId(message.getQuote().getSenderId())
- .setSenderName(message.getQuote().getSenderName())
- .setSenderAvatar(message.getQuote().getSenderAvatar())
- .setTicketState(message.getQuote().getTicketState())
- .setContent(message.getQuote().getContent())
- .setAttachments(message.getQuote().getAttachments())
- .setImages(message.getQuote().getImages())
- .setCreateTime(formatter.format(message.getQuote().getCreateTime())));
- SSEMessageDTO messageDTO = new SSEMessageDTO()
- .setType(1)
- .setData(messageVO);
- StrUtil.split(handle, ",").forEach(userId -> {
- try {
- sseManagerService.send(Integer.valueOf(userId), messageDTO);
- } catch (IOException e) {
- log.error("发送SSE消息出错", e);
- }
- });
+ List handles=Arrays.stream(ticket.getHandle().split(","))
+ .map(Integer::parseInt).collect(Collectors.toList());
+ if (CollectionUtil.isNotEmpty(handles)){
+ handles.forEach(uid->ssePushService.sendTicketMessageToAdmin(uid,message));
}
ticketEventPublisher.publishTicketReplyEvent(ticket, MultilingualUtil.getLanguage(), MultilingualUtil.getZone());
return ApiResult.success();
diff --git a/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/SsePushService.java b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/SsePushService.java
new file mode 100644
index 00000000..4a87af94
--- /dev/null
+++ b/nflg-mobilebroken-cfs-app/src/main/java/com/nflg/mobilebroken/cfs/service/SsePushService.java
@@ -0,0 +1,71 @@
+package com.nflg.mobilebroken.cfs.service;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.json.JSONUtil;
+import com.nflg.mobilebroken.common.pojo.ApiResult;
+import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
+import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
+import com.nflg.mobilebroken.common.pojo.request.PushRequest;
+import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO;
+import com.nflg.mobilebroken.common.util.MultilingualUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+
+@Slf4j
+@Component
+@RefreshScope
+public class SsePushService {
+
+ @Value("${sse.url}")
+ private String sseUrl;
+
+ public void sendTicketMessageToAdmin(Integer userId, ChatMessageDTO message){
+ try {
+ PushRequest request=new PushRequest().setUserId(userId).setMessage(buildMessage(message));
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity response = restTemplate.postForEntity(sseUrl+"/sse/admin/push",request, ApiResult.class);
+ log.debug("发送消息结果:{}", JSONUtil.toJsonStr(response.getBody()));
+ } catch (Exception e) {
+ log.error("发送消息出错", e);
+ }
+ }
+
+ private SSEMessageDTO buildMessage(ChatMessageDTO message){
+ String zone = MultilingualUtil.getZone();
+ ZoneId zoneId = ZoneId.of(zone);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN).withZone(zoneId);
+ ChatMessageVO messageVO = new ChatMessageVO()
+ .setId(message.getId())
+ .setFrom(message.getFrom())
+ .setSenderId(message.getSenderId())
+ .setSenderName(message.getSenderName())
+ .setSenderAvatar(message.getSenderAvatar())
+ .setContent(message.getContent())
+ .setTicketState(message.getTicketState())
+ .setCreateTime(formatter.format(message.getCreateTime()))
+ .setImages(message.getImages())
+ .setAttachments(message.getAttachments())
+ .setQuote(Objects.isNull(message.getQuote()) ? null : new ChatMessageVO()
+ .setId(message.getQuote().getId())
+ .setFrom(message.getQuote().getFrom())
+ .setSenderId(message.getQuote().getSenderId())
+ .setSenderName(message.getQuote().getSenderName())
+ .setSenderAvatar(message.getQuote().getSenderAvatar())
+ .setTicketState(message.getQuote().getTicketState())
+ .setContent(message.getQuote().getContent())
+ .setAttachments(message.getQuote().getAttachments())
+ .setImages(message.getQuote().getImages())
+ .setCreateTime(formatter.format(message.getQuote().getCreateTime())));
+ return new SSEMessageDTO()
+ .setType(1)
+ .setData(messageVO);
+ }
+}
\ No newline at end of file
diff --git a/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/SSEMessageDTO.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/SSEMessageDTO.java
index 12931b3e..b405ffc6 100644
--- a/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/SSEMessageDTO.java
+++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/dto/SSEMessageDTO.java
@@ -3,13 +3,17 @@ package com.nflg.mobilebroken.common.pojo.dto;
import lombok.Data;
import lombok.experimental.Accessors;
+import javax.validation.constraints.NotNull;
+
@Data
@Accessors(chain = true)
public class SSEMessageDTO {
//类型,1:工单会话消息,2:消息提醒
+ @NotNull
private int type;
//消息内容
+ @NotNull
private Object data;
}
diff --git a/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/request/PushRequest.java b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/request/PushRequest.java
new file mode 100644
index 00000000..e27f3a19
--- /dev/null
+++ b/nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/pojo/request/PushRequest.java
@@ -0,0 +1,22 @@
+package com.nflg.mobilebroken.common.pojo.request;
+
+import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+@Data
+@Accessors(chain = true)
+public class PushRequest {
+
+ //用户id
+ @NotNull
+ private Integer userId;
+
+ //消息
+ @NotNull
+ @Valid
+ private SSEMessageDTO message;
+}
diff --git a/nflg-mobilebroken-push/pom.xml b/nflg-mobilebroken-push/pom.xml
new file mode 100644
index 00000000..785fe915
--- /dev/null
+++ b/nflg-mobilebroken-push/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+
+ com.nflg
+ nflg-mobilebroken
+ 1.0.0-SNAPSHOT
+
+ nflg-mobilebroken-push
+ 1.0.0-SNAPSHOT
+ 服务-SSE服务
+ SSE消息推送功能接口
+ jar
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ com.nflg
+ nflg-mobilebroken-common
+
+
+ org.springframework
+ spring-webmvc
+
+
+ cn.dev33
+ sa-token-spring-boot-starter
+
+
+ cn.dev33
+ sa-token-jwt
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+
\ No newline at end of file
diff --git a/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/PushApplication.java b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/PushApplication.java
new file mode 100644
index 00000000..80021eea
--- /dev/null
+++ b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/PushApplication.java
@@ -0,0 +1,20 @@
+package com.nflg.mobilebroken.push;
+
+import cn.dev33.satoken.SaManager;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@Slf4j
+@EnableScheduling
+@EnableAsync
+public class PushApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(PushApplication.class, args);
+ log.info("启动成功,Sa-Token 配置如下:" + SaManager.getConfig());
+ }
+}
diff --git a/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/advice/GlobalRestControllerAdvice.java b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/advice/GlobalRestControllerAdvice.java
new file mode 100644
index 00000000..9542d632
--- /dev/null
+++ b/nflg-mobilebroken-push/src/main/java/com/nflg/mobilebroken/push/advice/GlobalRestControllerAdvice.java
@@ -0,0 +1,67 @@
+package com.nflg.mobilebroken.push.advice;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.hutool.core.util.StrUtil;
+import com.nflg.mobilebroken.common.constant.STATE;
+import com.nflg.mobilebroken.common.exception.NflgException;
+import com.nflg.mobilebroken.common.pojo.ApiResult;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalRestControllerAdvice {
+
+ @ExceptionHandler(Exception.class)
+ public ApiResult handleAllExceptions(Exception ex) {
+ log.error("服务器内部错误: ", ex);
+ return ApiResult.error(STATE.BusinessError,"服务器内部错误: " + ex.getMessage());
+ }
+
+ @ExceptionHandler(NflgException.class)
+ public ResponseEntity