update 接口测试完成,新增ip限制链接 + 最大连接数配置.文件上传模块,路径修改
This commit is contained in:
parent
476cb6711e
commit
2d8088c6cb
|
@ -0,0 +1,16 @@
|
||||||
|
package com.m2pool.chat.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "websocket.transport")
|
||||||
|
public class CustomWebSocketConfig {
|
||||||
|
private int messageSizeLimit;
|
||||||
|
private int sendTimeLimit;
|
||||||
|
private int sendBufferSizeLimit;
|
||||||
|
private int timeToFirstMessage;
|
||||||
|
private int maxConnections;
|
||||||
|
}
|
|
@ -12,7 +12,9 @@ import org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler;
|
||||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +26,11 @@ import java.util.List;
|
||||||
@EnableWebSocketMessageBroker
|
@EnableWebSocketMessageBroker
|
||||||
public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CustomWebSocketConfig customWebSocketConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册 Stomp的端点 可以注册多个端点
|
* 注册 Stomp的端点 可以注册多个端点
|
||||||
* addEndpoint:添加STOMP协议的端点。客户端访问地址
|
* addEndpoint:添加STOMP协议的端点。客户端访问地址
|
||||||
|
@ -62,6 +69,20 @@ public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大消息字节数,发送超时时间,发送缓冲区大小,首次连接超时时间
|
||||||
|
* @param registration
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
|
||||||
|
registration
|
||||||
|
.setMessageSizeLimit(customWebSocketConfig.getMessageSizeLimit())
|
||||||
|
.setSendTimeLimit(customWebSocketConfig.getSendTimeLimit())
|
||||||
|
.setSendBufferSizeLimit(customWebSocketConfig.getSendBufferSizeLimit())
|
||||||
|
// 首次连接超时时间.正常情况下,前端订阅 和 心跳包的影响 不会超时断连
|
||||||
|
.setTimeToFirstMessage(customWebSocketConfig.getTimeToFirstMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +96,7 @@ public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||||
.maxPoolSize(20)
|
.maxPoolSize(20)
|
||||||
.keepAliveSeconds(60);
|
.keepAliveSeconds(60);
|
||||||
// 拦截器配置
|
// 拦截器配置
|
||||||
registration.interceptors(new WebsocketChannelInterceptor());
|
registration.interceptors(new WebsocketChannelInterceptor(customWebSocketConfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.m2pool.chat.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName CustomHeader
|
||||||
|
* @Description 自定义请求头
|
||||||
|
* @Author yyb
|
||||||
|
* @Date 2025/4/16 13:34
|
||||||
|
*/
|
||||||
|
public class CustomHeader {
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
public static final String TYPE = "type";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户邮箱
|
||||||
|
*/
|
||||||
|
public static final String EMAIL = "email";
|
||||||
|
/**
|
||||||
|
* 客服端ip地址请求头
|
||||||
|
*/
|
||||||
|
public static final String IPADDR = "ipAddr";
|
||||||
|
}
|
|
@ -25,10 +25,5 @@ public class Destination {
|
||||||
/**
|
/**
|
||||||
* stomp 默认发送消息前缀。
|
* stomp 默认发送消息前缀。
|
||||||
*/
|
*/
|
||||||
public static final String SEND_PREFIX = "/message";
|
public static final String SEND_PREFIX = "/point";
|
||||||
|
|
||||||
/**
|
|
||||||
* 游客标识
|
|
||||||
*/
|
|
||||||
public static final String VISITOR_PREFIX = "visitor";
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package com.m2pool.chat.dto;
|
package com.m2pool.chat.dto;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ClassName ChatMessageDto
|
* @ClassName ChatMessageDto
|
||||||
* @Description 聊天消息返回对象
|
* @Description 聊天消息返回对象
|
||||||
|
@ -29,5 +30,5 @@ public class ChatMessageDto {
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
@ApiModelProperty(value = "发送时间", example = "")
|
@ApiModelProperty(value = "发送时间", example = "")
|
||||||
private DateTime createTime;
|
private LocalDateTime createTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.m2pool.chat.dto;
|
package com.m2pool.chat.dto;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ClassName ChatRoomDto
|
* @ClassName ChatRoomDto
|
||||||
* @Description 客服 聊天室列表返回对象
|
* @Description 客服 聊天室列表返回对象
|
||||||
|
@ -34,10 +35,10 @@ public class ChatRoomDto {
|
||||||
/**
|
/**
|
||||||
* 用户回复时间
|
* 用户回复时间
|
||||||
*/
|
*/
|
||||||
private DateTime lastUserSendTime;
|
private LocalDateTime lastUserSendTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客服回复时间
|
* 客服回复时间
|
||||||
*/
|
*/
|
||||||
private DateTime lastCustomerSendTime;
|
private LocalDateTime lastCustomerSendTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package com.m2pool.chat.entity;
|
package com.m2pool.chat.entity;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
@Data
|
@Data
|
||||||
public class ChatMessage {
|
public class ChatMessage {
|
||||||
|
@ -13,6 +14,6 @@ public class ChatMessage {
|
||||||
private String sendEmail;
|
private String sendEmail;
|
||||||
private String content;
|
private String content;
|
||||||
private Long roomId;
|
private Long roomId;
|
||||||
private DateTime createTime;
|
private LocalDateTime createTime;
|
||||||
private DateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.m2pool.chat.entity;
|
package com.m2pool.chat.entity;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class ChatMessageHistory {
|
public class ChatMessageHistory {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
@ -10,6 +11,6 @@ public class ChatMessageHistory {
|
||||||
private String sendEmail;
|
private String sendEmail;
|
||||||
private String content;
|
private String content;
|
||||||
private Long roomId;
|
private Long roomId;
|
||||||
private DateTime createTime;
|
private LocalDateTime createTime;
|
||||||
private DateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
package com.m2pool.chat.entity;
|
package com.m2pool.chat.entity;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
@Data
|
@Data
|
||||||
public class ChatRoom {
|
public class ChatRoom {
|
||||||
private Long id;
|
private Long id;
|
||||||
private String userOneEmail;
|
private String userOneEmail;
|
||||||
private String userTwoEmail;
|
private String userTwoEmail;
|
||||||
private DateTime lastUserSendTime;
|
private LocalDateTime lastUserSendTime;
|
||||||
private DateTime lastCustomerSendTime;
|
private LocalDateTime lastCustomerSendTime;
|
||||||
private Boolean flag;
|
private Boolean flag;
|
||||||
private DateTime createTime;
|
private LocalDateTime createTime;
|
||||||
private DateTime updateTime;
|
private LocalDateTime updateTime;
|
||||||
private Boolean del;
|
private Boolean del;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
package com.m2pool.chat.entity;
|
package com.m2pool.chat.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stomp用户身份信息
|
* stomp用户身份信息
|
||||||
*/
|
*/
|
||||||
|
@Data
|
||||||
public class StompPrincipal implements Principal {
|
public class StompPrincipal implements Principal {
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
public StompPrincipal(String name) {
|
Integer type;
|
||||||
|
|
||||||
|
public StompPrincipal(String name,Integer type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package com.m2pool.chat.interceptor;
|
package com.m2pool.chat.interceptor;
|
||||||
|
|
||||||
|
|
||||||
|
import com.m2pool.chat.config.CustomWebSocketConfig;
|
||||||
import com.m2pool.chat.entity.StompPrincipal;
|
import com.m2pool.chat.entity.StompPrincipal;
|
||||||
|
import lombok.Data;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageChannel;
|
import org.springframework.messaging.MessageChannel;
|
||||||
|
import org.springframework.messaging.MessageDeliveryException;
|
||||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||||
import org.springframework.messaging.simp.stomp.StompCommand;
|
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||||
|
@ -15,6 +18,12 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static com.m2pool.chat.constant.CustomHeader.*;
|
||||||
|
import static com.m2pool.chat.constant.UserType.CUSTOMER;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ClassName WebsocketChannelInterceptor
|
* @ClassName WebsocketChannelInterceptor
|
||||||
|
@ -22,9 +31,30 @@ import java.util.Map;
|
||||||
* @Author yyb
|
* @Author yyb
|
||||||
* @Date 2025/4/10 15:44
|
* @Date 2025/4/10 15:44
|
||||||
*/
|
*/
|
||||||
|
@Data
|
||||||
public class WebsocketChannelInterceptor implements ChannelInterceptor {
|
public class WebsocketChannelInterceptor implements ChannelInterceptor {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketChannelInterceptor.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketChannelInterceptor.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前加入链接的ip
|
||||||
|
*/
|
||||||
|
private static final ConcurrentHashMap<String, Boolean> ipConnectionCountMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前链接数
|
||||||
|
*/
|
||||||
|
private static final AtomicInteger connectionCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* websocket 一些配置
|
||||||
|
*/
|
||||||
|
private CustomWebSocketConfig customWebSocketConfig;
|
||||||
|
|
||||||
|
public WebsocketChannelInterceptor(CustomWebSocketConfig customWebSocketConfig) {
|
||||||
|
this.customWebSocketConfig = customWebSocketConfig;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* websocket channel 通道拦截器
|
* websocket channel 通道拦截器
|
||||||
* @param message
|
* @param message
|
||||||
|
@ -35,18 +65,22 @@ public class WebsocketChannelInterceptor implements ChannelInterceptor {
|
||||||
public Message<?> preSend(Message<?> message, MessageChannel channel) {
|
public Message<?> preSend(Message<?> message, MessageChannel channel) {
|
||||||
//获取链接建立时的请求头信息
|
//获取链接建立时的请求头信息
|
||||||
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
|
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
|
||||||
if (accessor.getCommand() == StompCommand.CONNECT) {
|
if (accessor.getCommand() == StompCommand.CONNECT ) {
|
||||||
LOGGER.info("------------收到websocket的连接消息");
|
|
||||||
//获取channel 中的请求头信息
|
|
||||||
StompHeaderAccessor mha = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
|
StompHeaderAccessor mha = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
|
||||||
Object raw = message.getHeaders().get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
|
Object raw = message.getHeaders().get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
|
||||||
System.out.println("raw:"+raw);
|
int type = Integer.parseInt(getConnectCustomHeaders(raw, TYPE));
|
||||||
if (raw instanceof Map) {
|
String email = getConnectCustomHeaders(raw, EMAIL);
|
||||||
Object userInfo = ((Map) raw).get("email");
|
|
||||||
if(userInfo instanceof ArrayList){
|
//最大链接数限制
|
||||||
mha.setUser(new StompPrincipal((String) ((ArrayList) userInfo).get(0)));
|
maxConnectionsLimit();
|
||||||
}
|
//根据客服端ip + 用户类型限制连接数
|
||||||
|
ipLimit(accessor,type);
|
||||||
|
|
||||||
|
if(mha == null){
|
||||||
|
throw new MessageDeliveryException("get MessageHeaderAccessor failed,can not set Principal,connect failed");
|
||||||
}
|
}
|
||||||
|
//链接请求头中用户信息存入stomp中
|
||||||
|
mha.setUser(new StompPrincipal(email,type));
|
||||||
}
|
}
|
||||||
if (accessor.getCommand() == StompCommand.SEND) {
|
if (accessor.getCommand() == StompCommand.SEND) {
|
||||||
LOGGER.info("------------websocket send message");
|
LOGGER.info("------------websocket send message");
|
||||||
|
@ -61,11 +95,74 @@ public class WebsocketChannelInterceptor implements ChannelInterceptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessor.getCommand() == StompCommand.DISCONNECT){
|
if (accessor.getCommand() == StompCommand.DISCONNECT){
|
||||||
|
disconnectHandler(accessor);
|
||||||
LOGGER.info("------------websocket disconnect");
|
LOGGER.info("------------websocket disconnect");
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大连接数限制
|
||||||
|
*/
|
||||||
|
private void maxConnectionsLimit(){
|
||||||
|
if(connectionCount.incrementAndGet() >= customWebSocketConfig.getMaxConnections()){
|
||||||
|
LOGGER.info("reach max connections,refuse connect");
|
||||||
|
throw new MessageDeliveryException("reach max connections,refuse connect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ip 链接个数限制
|
||||||
|
* @param accessor
|
||||||
|
*/
|
||||||
|
private void ipLimit(StompHeaderAccessor accessor,int type){
|
||||||
|
Map<String, Object> sessionAttributes = accessor.getSessionAttributes();
|
||||||
|
if (sessionAttributes != null) {
|
||||||
|
String ipAddr = (String) sessionAttributes.get(IPADDR);
|
||||||
|
if(type != CUSTOMER && ipConnectionCountMap.get(ipAddr) != null){
|
||||||
|
throw new MessageDeliveryException("this ip maximum number of connections is reached");
|
||||||
|
}
|
||||||
|
ipConnectionCountMap.put(ipAddr,true);
|
||||||
|
}else{
|
||||||
|
throw new MessageDeliveryException("not find email and type headers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取stomp自定义请求头
|
||||||
|
* @param raw
|
||||||
|
* @param headerKey
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getConnectCustomHeaders(Object raw,String headerKey){
|
||||||
|
String headerValue = "";
|
||||||
|
if (raw instanceof Map) {
|
||||||
|
Object value = ((Map<?, ?>) raw).get(headerKey);
|
||||||
|
if(value instanceof ArrayList){
|
||||||
|
headerValue = ((ArrayList<?>) value).get(0).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开链接处理
|
||||||
|
*/
|
||||||
|
private void disconnectHandler(StompHeaderAccessor accessor){
|
||||||
|
//连接数减一
|
||||||
|
connectionCount.decrementAndGet();
|
||||||
|
//断开链接的ip
|
||||||
|
Map<String, Object> sessionAttributes = accessor.getSessionAttributes();
|
||||||
|
if (sessionAttributes != null) {
|
||||||
|
String ipAddr = (String) sessionAttributes.get(IPADDR);
|
||||||
|
if(ipConnectionCountMap.get(ipAddr) != null){
|
||||||
|
ipConnectionCountMap.remove(ipAddr);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new MessageDeliveryException("not find email and type headers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
|
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
package com.m2pool.chat.interceptor;
|
package com.m2pool.chat.interceptor;
|
||||||
|
|
||||||
|
import com.m2pool.common.core.utils.ip.IpUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.server.ServerHttpRequest;
|
import org.springframework.http.server.ServerHttpRequest;
|
||||||
import org.springframework.http.server.ServerHttpResponse;
|
import org.springframework.http.server.ServerHttpResponse;
|
||||||
|
import org.springframework.http.server.ServletServerHttpRequest;
|
||||||
import org.springframework.web.socket.WebSocketHandler;
|
import org.springframework.web.socket.WebSocketHandler;
|
||||||
import org.springframework.web.socket.server.HandshakeInterceptor;
|
import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static com.m2pool.chat.constant.Destination.VISITOR_PREFIX;
|
import static com.m2pool.chat.constant.CustomHeader.IPADDR;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,14 +27,18 @@ public class WebsocketHandshakeInterceptor implements HandshakeInterceptor {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
|
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
|
||||||
LOGGER.info("------------------WebsocketHandshakeInterceptor:beforeHandshake");
|
LOGGER.info("------------------WebsocketHandshakeInterceptor:beforeHandshake");
|
||||||
// 为游客生成一个唯一标识
|
if (request instanceof ServletServerHttpRequest) {
|
||||||
// String s = generateVisitorId(request);
|
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
|
||||||
// attributes.put(VISITOR_PREFIX, s);
|
HttpServletRequest httpRequest = servletRequest.getServletRequest();
|
||||||
// response.getHeaders().add(VISITOR_PREFIX, s);
|
// 获取 客服端 IP 地址 并放入attributes 中
|
||||||
|
String ipAddr = IpUtils.getIpAddr(httpRequest);
|
||||||
|
attributes.put(IPADDR, ipAddr);
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("Request is not an instance of ServletServerHttpRequest. Unable to extract HttpServletRequest.");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,14 +47,4 @@ public class WebsocketHandshakeInterceptor implements HandshakeInterceptor {
|
||||||
LOGGER.info("------------------WebsocketHandshakeInterceptor:afterHandshake");
|
LOGGER.info("------------------WebsocketHandshakeInterceptor:afterHandshake");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成一个唯一标识
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String generateVisitorId(ServerHttpRequest request) {
|
|
||||||
String first = request.getHeaders().getFirst("sec-websocket-key");
|
|
||||||
String prefix = VISITOR_PREFIX;
|
|
||||||
return prefix + first;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,17 @@ public class ChatMessageServiceImpl implements ChatMessageService {
|
||||||
ChatRoom chatRoom = chatRoomMapper.selectById(roomId);
|
ChatRoom chatRoom = chatRoomMapper.selectById(roomId);
|
||||||
String username = SecurityUtils.getUsername();
|
String username = SecurityUtils.getUsername();
|
||||||
|
|
||||||
String updateUserEmail = "";
|
if (chatRoom != null){
|
||||||
if(username.equals(chatRoom.getUserOneEmail())){
|
String updateUserEmail = "";
|
||||||
updateUserEmail = chatRoom.getUserTwoEmail();
|
if( username.equals(chatRoom.getUserOneEmail())){
|
||||||
}else if(username.equals(chatRoom.getUserTwoEmail())){
|
updateUserEmail = chatRoom.getUserTwoEmail();
|
||||||
updateUserEmail = chatRoom.getUserOneEmail();
|
}else if (username.equals(chatRoom.getUserTwoEmail())) {
|
||||||
|
updateUserEmail = chatRoom.getUserOneEmail();
|
||||||
|
}
|
||||||
|
int update = chatMessageMapper.update(ChatMessage.builder().read(1).build(),
|
||||||
|
new LambdaUpdateWrapper<ChatMessage>().eq(ChatMessage::getSendEmail, updateUserEmail).eq(ChatMessage::getRoomId, roomId));
|
||||||
|
return update > 0 ? AjaxResult.success("已读") : AjaxResult.error("消息读取失败");
|
||||||
}
|
}
|
||||||
int update = chatMessageMapper.update(ChatMessage.builder().read(1).build(),
|
return AjaxResult.error("聊天室不存在");
|
||||||
new LambdaUpdateWrapper<ChatMessage>().eq(ChatMessage::getSendEmail, updateUserEmail).eq(ChatMessage::getRoomId, roomId));
|
|
||||||
return update > 0 ? AjaxResult.success("已读") : AjaxResult.error("消息读取失败");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -38,11 +38,13 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
|
||||||
List<ChatRoomDto> roomList = chatRoomMapper.findRoomList(SecurityUtils.getUsername());
|
List<ChatRoomDto> roomList = chatRoomMapper.findRoomList(SecurityUtils.getUsername());
|
||||||
List<String> userEmails = roomList.stream().map(ChatRoomDto::getUserEmail).collect(Collectors.toList());
|
List<String> userEmails = roomList.stream().map(ChatRoomDto::getUserEmail).collect(Collectors.toList());
|
||||||
//2.查询未读数量
|
//2.查询未读数量
|
||||||
Map<String, Integer> unReadNums = chatMessageMapper.findUnReadNums(userEmails);
|
if (!userEmails.isEmpty()){
|
||||||
|
Map<String, Integer> unReadNums = chatMessageMapper.findUnReadNums(userEmails);
|
||||||
|
for (ChatRoomDto room : roomList) {
|
||||||
|
Integer i = unReadNums.get(room.getUserEmail());
|
||||||
|
room.setUnReadNumber(i == null ? 0 : i);
|
||||||
|
}
|
||||||
|
|
||||||
for (ChatRoomDto room : roomList) {
|
|
||||||
Integer i = unReadNums.get(room.getUserEmail());
|
|
||||||
room.setUnReadNumber(i == null ? 0 : i);
|
|
||||||
}
|
}
|
||||||
return getDataTable(roomList);
|
return getDataTable(roomList);
|
||||||
}
|
}
|
||||||
|
@ -85,6 +87,6 @@ public class ChatRoomServiceImpl extends ServiceImpl<ChatRoomMapper, ChatRoom> i
|
||||||
if(i > 0){
|
if(i > 0){
|
||||||
return AjaxResult.success("修改成功");
|
return AjaxResult.success("修改成功");
|
||||||
}
|
}
|
||||||
return AjaxResult.error("修改失败");
|
return AjaxResult.error("修改失败,不存在该聊天室");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package com.m2pool.chat.service.impl;
|
package com.m2pool.chat.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateTime;
|
|
||||||
import com.m2pool.chat.constant.Destination;
|
import com.m2pool.chat.constant.Destination;
|
||||||
import com.m2pool.chat.dto.WebsocketMessageDto;
|
import com.m2pool.chat.dto.WebsocketMessageDto;
|
||||||
import com.m2pool.chat.entity.ChatMessage;
|
import com.m2pool.chat.entity.ChatMessage;
|
||||||
|
@ -17,6 +16,7 @@ import org.springframework.messaging.simp.user.SimpUserRegistry;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import static com.m2pool.chat.constant.UserType.CUSTOMER;
|
import static com.m2pool.chat.constant.UserType.CUSTOMER;
|
||||||
import static com.m2pool.chat.constant.UserType.TOURIST;
|
import static com.m2pool.chat.constant.UserType.TOURIST;
|
||||||
|
@ -88,9 +88,9 @@ public class StompServiceImpl implements StompService {
|
||||||
private void updateRoom(UserMessageVo userMessageVo){
|
private void updateRoom(UserMessageVo userMessageVo){
|
||||||
ChatRoom room = ChatRoom.builder().id(userMessageVo.getRoomId()).build();
|
ChatRoom room = ChatRoom.builder().id(userMessageVo.getRoomId()).build();
|
||||||
if (CUSTOMER.equals(userMessageVo.getSendUserType())) {
|
if (CUSTOMER.equals(userMessageVo.getSendUserType())) {
|
||||||
room.setLastCustomerSendTime(DateTime.now());
|
room.setLastCustomerSendTime(LocalDateTime.now());
|
||||||
} else {
|
} else {
|
||||||
room.setLastUserSendTime(DateTime.now());
|
room.setLastUserSendTime(LocalDateTime.now());
|
||||||
}
|
}
|
||||||
chatRoomMapper.insert(room);
|
chatRoomMapper.insert(room);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,10 @@ spring:
|
||||||
max-file-size: 2MB
|
max-file-size: 2MB
|
||||||
max-request-size: 8MB
|
max-request-size: 8MB
|
||||||
|
|
||||||
myenv:
|
websocket:
|
||||||
domain: https://www.m2pool.com
|
transport:
|
||||||
path: /var/www/html/web
|
message-size-limit: 1500 # 消息大小限制 1.5k 约500汉字
|
||||||
img: /img
|
send-time-limit: 5000 # 发送超时时间 5秒
|
||||||
|
send-buffer-size-limit: 65536 # 发送缓冲区大小 64K
|
||||||
|
time-to-first-message: 5000 # 首次消息超时时间 5秒
|
||||||
|
max-connections: 100 # 最大连接数
|
|
@ -36,8 +36,10 @@ spring:
|
||||||
max-file-size: 2MB
|
max-file-size: 2MB
|
||||||
max-request-size: 8MB
|
max-request-size: 8MB
|
||||||
|
|
||||||
myenv:
|
websocket:
|
||||||
domain: https://test.m2pool.com
|
transport:
|
||||||
path: /var/www/html/web_test
|
message-size-limit: 1500 # 消息大小限制 1.5k 约500汉字
|
||||||
img: /imgpp
|
send-time-limit: 5000 # 发送超时时间 5秒
|
||||||
|
send-buffer-size-limit: 65536 # 发送缓冲区大小 64K
|
||||||
|
time-to-first-message: 5000 # 首次消息超时时间 5秒
|
||||||
|
max-connections: 100 # 最大连接数
|
|
@ -15,15 +15,15 @@
|
||||||
LIMIT #{pageNum}
|
LIMIT #{pageNum}
|
||||||
</select>
|
</select>
|
||||||
<select id="findUnReadNums" resultType="java.util.Map">
|
<select id="findUnReadNums" resultType="java.util.Map">
|
||||||
SELECT user_email as userEmail,
|
SELECT send_email as userEmail,
|
||||||
count(*) as unReadNums
|
count(*) as unReadNums
|
||||||
FROM chat_message
|
FROM chat_message
|
||||||
WHERE send_email IN
|
WHERE send_email IN
|
||||||
<foreach collection="userEmails" item="userEmail" open="(" separator="," close=")">
|
<foreach collection="userEmails" item="userEmail" open="(" separator="," close=")">
|
||||||
#{userEmail}
|
#{userEmail}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND read_flag = false
|
AND `read` = false
|
||||||
GROUP BY user_email
|
GROUP BY send_email
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
|
@ -1,12 +1,13 @@
|
||||||
package com.m2pool.file.config;
|
package com.m2pool.file.config;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用映射配置
|
* 通用映射配置
|
||||||
*
|
*
|
||||||
|
@ -18,7 +19,7 @@ public class ResourcesConfig implements WebMvcConfigurer
|
||||||
/**
|
/**
|
||||||
* 上传文件存储在本地的根路径
|
* 上传文件存储在本地的根路径
|
||||||
*/
|
*/
|
||||||
@Value("${file.path}")
|
@Value("${file.filepath}")
|
||||||
private String localFilePath;
|
private String localFilePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class SysFileController
|
||||||
/**
|
/**
|
||||||
* 上传文件存储在本地的根路径
|
* 上传文件存储在本地的根路径
|
||||||
*/
|
*/
|
||||||
@Value("${file.path}")
|
@Value("${file.filepath}")
|
||||||
private String localFilePath;
|
private String localFilePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,7 @@ public class LocalSysFileServiceImpl implements ISysFileService
|
||||||
/**
|
/**
|
||||||
* 资源映射路径 前缀
|
* 资源映射路径 前缀
|
||||||
*/
|
*/
|
||||||
@Value("${file.prefix}")
|
@Value("${file.prefix")
|
||||||
public String localFilePrefix;
|
public String localFilePrefix;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +32,7 @@ public class LocalSysFileServiceImpl implements ISysFileService
|
||||||
/**
|
/**
|
||||||
* 上传文件存储在本地的根路径
|
* 上传文件存储在本地的根路径
|
||||||
*/
|
*/
|
||||||
@Value("${file.path}")
|
@Value("${file.filepath}")
|
||||||
private String localFilePath;
|
private String localFilePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Tomcat
|
||||||
|
server:
|
||||||
|
port: 9300
|
||||||
|
|
||||||
|
# Spring
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
# 应用名称
|
||||||
|
name: m2pool-file
|
||||||
|
profiles:
|
||||||
|
# 环境配置
|
||||||
|
active: test
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
# 服务注册地址
|
||||||
|
server-addr: 127.0.0.1:8808
|
||||||
|
config:
|
||||||
|
# 配置中心地址
|
||||||
|
server-addr: 127.0.0.1:8808
|
||||||
|
# 配置文件格式
|
||||||
|
file-extension: yml
|
||||||
|
# 共享配置
|
||||||
|
shared-configs:
|
||||||
|
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||||
|
file:
|
||||||
|
domain: https://www.m2pool.com
|
||||||
|
path: /var/www/html/web
|
||||||
|
img: /img
|
||||||
|
filepath: /home/ubuntu/prod
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Tomcat
|
||||||
|
server:
|
||||||
|
port: 9300
|
||||||
|
|
||||||
|
# Spring
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
# 应用名称
|
||||||
|
name: m2pool-file
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
nacos:
|
||||||
|
discovery:
|
||||||
|
# 服务注册地址
|
||||||
|
server-addr: 127.0.0.1:8848
|
||||||
|
config:
|
||||||
|
# 配置中心地址
|
||||||
|
server-addr: 127.0.0.1:8848
|
||||||
|
# 配置文件格式
|
||||||
|
file-extension: yml
|
||||||
|
# 共享配置
|
||||||
|
shared-configs:
|
||||||
|
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||||
|
file:
|
||||||
|
domain: https://www.m2pool.com
|
||||||
|
path: /var/www/html/web-test
|
||||||
|
# img: /img
|
||||||
|
filepath: /home/ubuntu/web
|
|
@ -1,25 +1,3 @@
|
||||||
# Tomcat
|
|
||||||
server:
|
|
||||||
port: 9300
|
|
||||||
|
|
||||||
# Spring
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
|
||||||
# 应用名称
|
|
||||||
name: m2pool-file
|
|
||||||
profiles:
|
profiles:
|
||||||
# 环境配置
|
active: test
|
||||||
active: dev
|
|
||||||
cloud:
|
|
||||||
nacos:
|
|
||||||
discovery:
|
|
||||||
# 服务注册地址
|
|
||||||
server-addr: 127.0.0.1:8808
|
|
||||||
config:
|
|
||||||
# 配置中心地址
|
|
||||||
server-addr: 127.0.0.1:8808
|
|
||||||
# 配置文件格式
|
|
||||||
file-extension: yml
|
|
||||||
# 共享配置
|
|
||||||
shared-configs:
|
|
||||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
|
||||||
|
|
Loading…
Reference in New Issue