Compare commits
	
		
			2 Commits
		
	
	
		
			71f3810e51
			...
			6b4cd4ae0d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6b4cd4ae0d | |||
| 261dd0b643 | 
| @ -252,6 +252,11 @@ | ||||
|             <scope>compile</scope> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>io.netty</groupId> | ||||
|             <artifactId>netty-all</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|     </dependencies> | ||||
|  | ||||
| </project> | ||||
|  | ||||
| @ -127,6 +127,7 @@ public class BusLandTransferLedgerServiceImpl extends ServiceImpl<BusLandTransfe | ||||
|                     String transferStatus = son.getTransferStatus(); | ||||
|                     //0是未流转,1已流转,2是不流转 | ||||
|                     switch (transferStatus) { | ||||
|  | ||||
|                         case "1": | ||||
|                             if (son.getAreaValue() != null) { | ||||
|                                 transferArea = transferArea.add(son.getAreaValue()); | ||||
| @ -138,17 +139,21 @@ public class BusLandTransferLedgerServiceImpl extends ServiceImpl<BusLandTransfe | ||||
|                                 noTrans = noTrans.add(son.getAreaValue()); | ||||
|                             } | ||||
|                             break; | ||||
|  | ||||
|                         default: | ||||
|                             break; | ||||
|                     } | ||||
|  | ||||
|                     //土地租金(元) | ||||
|                     if (son.getLandRent() != null) { | ||||
|                         landRentAll = landRentAll.add(son.getLandRent()); | ||||
|                     } | ||||
|  | ||||
|                     //青苗赔偿(元) | ||||
|                     if (son.getSeedlingCompensation()!=null) { | ||||
|                         seedlingCompensationAll = seedlingCompensationAll.add(son.getSeedlingCompensation()); | ||||
|                     } | ||||
|  | ||||
|                     //总金额(元) | ||||
|                     if (son.getTotalAmount()!=null) { | ||||
|                         totalAmountAll = totalAmountAll.add(son.getTotalAmount()); | ||||
|  | ||||
| @ -0,0 +1,22 @@ | ||||
| package org.dromara.websocket; | ||||
|  | ||||
| import io.netty.channel.ChannelHandlerContext; | ||||
| import io.netty.channel.SimpleChannelInboundHandler; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
|  | ||||
| @Slf4j | ||||
| public class ChatClientHandler extends SimpleChannelInboundHandler<String> { | ||||
|  | ||||
|     @Override | ||||
|     protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { | ||||
|         // 打印服务器发送的消息 | ||||
|         log.info(msg); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | ||||
|         log.error("客户端发生异常:" + cause.getMessage()); | ||||
|         ctx.close(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,98 @@ | ||||
| package org.dromara.websocket; | ||||
|  | ||||
| import io.netty.bootstrap.ServerBootstrap; | ||||
| import io.netty.channel.ChannelFuture; | ||||
| import io.netty.channel.ChannelInitializer; | ||||
| import io.netty.channel.ChannelOption; | ||||
| import io.netty.channel.EventLoopGroup; | ||||
| import io.netty.channel.nio.NioEventLoopGroup; | ||||
| import io.netty.channel.socket.SocketChannel; | ||||
| import io.netty.channel.socket.nio.NioServerSocketChannel; | ||||
| import io.netty.handler.codec.http.HttpObjectAggregator; | ||||
| import io.netty.handler.codec.http.HttpServerCodec; | ||||
| import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; | ||||
| import io.netty.handler.stream.ChunkedWriteHandler; | ||||
| import jakarta.annotation.PostConstruct; | ||||
| import jakarta.annotation.PreDestroy; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.boot.CommandLineRunner; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| @Slf4j | ||||
| @Configuration | ||||
| public class ChatServer  { | ||||
|     private final int port = 9099; // 聊天服务器端口 | ||||
|  | ||||
|     private EventLoopGroup bossGroup; | ||||
|     private EventLoopGroup workerGroup; | ||||
|  | ||||
|  | ||||
| //    @Override | ||||
| //    public void run(String... args) throws Exception { | ||||
| //        // 使用新线程启动Netty服务器,避免阻塞Spring启动 | ||||
| //        new Thread(() -> { | ||||
| //            try { | ||||
| //                start(); | ||||
| //            } catch (Exception e) { | ||||
| //                log.error("Netty服务器启动失败", e); | ||||
| //            } | ||||
| //        }, "NettyServer").start(); | ||||
| //    } | ||||
|  | ||||
|     // 启动Netty服务器 | ||||
|     @PostConstruct | ||||
|     public void start() throws Exception { | ||||
|         bossGroup = new NioEventLoopGroup(); | ||||
|         workerGroup = new NioEventLoopGroup(); | ||||
|  | ||||
|         try { | ||||
|             ServerBootstrap bootstrap = new ServerBootstrap(); | ||||
|             bootstrap.group(bossGroup, workerGroup) | ||||
|                 .channel(NioServerSocketChannel.class) | ||||
|                 .option(ChannelOption.SO_BACKLOG, 128) | ||||
|                 .childOption(ChannelOption.SO_KEEPALIVE, true) | ||||
|                 .childHandler(new ChannelInitializer<SocketChannel>() { | ||||
|                     @Override | ||||
|                     protected void initChannel(SocketChannel ch) throws Exception { | ||||
|                         // websocket协议本身是基于http协议的,所以这边也要使用http解编码器 | ||||
|                         ch.pipeline().addLast(new HttpServerCodec()); | ||||
|                         // 以块的方式来写的处理器 | ||||
|                         ch.pipeline().addLast(new ChunkedWriteHandler()); | ||||
|                         ch.pipeline().addLast(new HttpObjectAggregator(8192)); | ||||
|                         // 注意:WebSocketServerProtocolHandler 必须在 ChatServerHandler 之前添加 | ||||
|                         ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10,false,true)); | ||||
|                         ch.pipeline().addLast(new ChatServerHandler()); // 添加聊天消息处理类 | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|             log.info("Netty聊天服务器启动,端口:" + port); | ||||
|             ChannelFuture future = bootstrap.bind(port).sync(); | ||||
| //            future.channel().closeFuture().sync(); | ||||
|         } finally { | ||||
| //            workerGroup.shutdownGracefully().sync(); | ||||
| //            bossGroup.shutdownGracefully().sync(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 关闭服务器时释放资源 | ||||
|     @PreDestroy | ||||
|     public void destroy() { | ||||
|         if (bossGroup != null) { | ||||
|             bossGroup.shutdownGracefully(); | ||||
|         } | ||||
|         if (workerGroup != null) { | ||||
|             workerGroup.shutdownGracefully(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| //    @Bean | ||||
| //    public ServerBootstrap serverBootstrap() { | ||||
| //        // 确保在 pipeline 中添加了 WebSocketServerProtocolHandler | ||||
| //        // 例如: | ||||
| //        // pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true)); | ||||
| //        return new ServerBootstrap(); | ||||
| //    } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,338 @@ | ||||
| package org.dromara.websocket; | ||||
|  | ||||
| import com.alibaba.fastjson.JSONObject; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import io.netty.channel.Channel; | ||||
| import io.netty.channel.ChannelHandler; | ||||
| import io.netty.channel.ChannelHandlerContext; | ||||
| import io.netty.channel.SimpleChannelInboundHandler; | ||||
| import io.netty.channel.group.ChannelGroup; | ||||
| import io.netty.channel.group.DefaultChannelGroup; | ||||
| import io.netty.handler.codec.http.HttpHeaders; | ||||
| import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; | ||||
| import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; | ||||
| import io.netty.util.concurrent.GlobalEventExecutor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.dromara.common.core.domain.dto.UserDTO; | ||||
| import org.dromara.common.core.domain.model.LoginUser; | ||||
| import org.dromara.common.json.utils.JsonUtils; | ||||
| import org.dromara.common.redis.utils.RedisUtils; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.system.domain.bo.SysUserBo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.service.impl.SysUserServiceImpl; | ||||
| import org.dromara.websocket.domain.ChatGroup; | ||||
| import org.dromara.websocket.domain.ChatHistory; | ||||
| import org.dromara.websocket.service.Impl.ChatGroupServiceImpl; | ||||
| import org.dromara.websocket.service.Impl.ChatHistoryServiceImpl; | ||||
| import org.springframework.beans.BeanUtils; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.context.ApplicationContext; | ||||
| import org.springframework.stereotype.Component; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| @Slf4j | ||||
| @Component | ||||
| @ChannelHandler.Sharable | ||||
| public class ChatServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { | ||||
|  | ||||
|     // 移除 @Autowired 注解 | ||||
|     private static ChatHistoryServiceImpl chatHistoryService; | ||||
|     private static ChatGroupServiceImpl chatGroupService; | ||||
|     private static SysUserServiceImpl sysUserService; | ||||
|     @Autowired | ||||
|     public void setChatHistoryService(ChatHistoryServiceImpl service) { | ||||
|         chatHistoryService = service; | ||||
|     } | ||||
|     @Autowired | ||||
|     public void setChatGroupService(ChatGroupServiceImpl service){ | ||||
|         chatGroupService = service; | ||||
|     } | ||||
|     @Autowired | ||||
|     public void setSysUserService(SysUserServiceImpl service){ | ||||
|         sysUserService = service; | ||||
|     } | ||||
|  | ||||
|     // 存储所有连接的客户端Channel | ||||
|     private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); | ||||
|     //日期格式 | ||||
|     private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | ||||
|     // 使用内存映射替代Redis存储 | ||||
|     private static final ConcurrentHashMap<String, List<ChannelHandlerContext>> userChannelMap = new ConcurrentHashMap<>(); | ||||
|     private static final ConcurrentHashMap<ChannelHandlerContext, String> channelUserMap = new ConcurrentHashMap<>(); | ||||
|     //维护用户房间未读数量的映射表    用户->RoomId  RoomId->Count   用户+房间->Count | ||||
|     private static final ConcurrentHashMap<String, Integer> userRoomCountMap = new ConcurrentHashMap<>(); | ||||
|     //维护一个在线用户列表 | ||||
|     private static final List<String> onlineUserList = new ArrayList<>(); | ||||
|     public static List<String> getOnlineUserList(){ | ||||
|         return onlineUserList; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // 当有客户端连接时调用 | ||||
|     @Override | ||||
|     public void handlerAdded(ChannelHandlerContext ctx) throws Exception { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     // 处理用户认证事件 | ||||
|     @Override | ||||
|     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { | ||||
|         if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) { | ||||
|             WebSocketServerProtocolHandler.HandshakeComplete handshake = (WebSocketServerProtocolHandler.HandshakeComplete) evt; | ||||
|  | ||||
|             // 从HTTP请求URI中提取token | ||||
|             String uri = handshake.requestUri(); | ||||
|             String token = null; | ||||
|             if (uri.contains("Authorization=")) { | ||||
|                 token = uri.split("Authorization=")[1].split("&")[0]; | ||||
|             } | ||||
|  | ||||
|             //建立双向映射关系 | ||||
|             LoginUser loginUser = LoginHelper.getLoginUser(token.replace("Bearer%20", "")); | ||||
|             if (loginUser == null){ | ||||
|                 throw new RuntimeException("token获取信息失败"); | ||||
|             } | ||||
|             //判断是否存在该账号的通道实例列表 | ||||
|             userChannelMap.computeIfAbsent(loginUser.getUserId().toString(), k -> new ArrayList<>()); | ||||
|             List<ChannelHandlerContext> channelHandlerContexts = userChannelMap.get(loginUser.getUserId().toString()); | ||||
|             if (!channelHandlerContexts.contains( ctx)){ | ||||
|                 channelHandlerContexts.add(ctx); | ||||
|             } | ||||
|             //把该账号的通道实例列表跟账号id关联 一个账号有多个通道实例 | ||||
|             userChannelMap.put(loginUser.getUserId().toString(), channelHandlerContexts); | ||||
|             //把通道实例跟账号id关联 | ||||
|             channelUserMap.put(ctx, loginUser.getUserId().toString()); | ||||
|  | ||||
|             if (!onlineUserList.contains(loginUser.getUserId().toString())) { | ||||
|                 onlineUserList.add(loginUser.getUserId().toString()); | ||||
|             } | ||||
|  | ||||
|             Channel channel = ctx.channel(); | ||||
|             channelGroup.writeAndFlush(new TextWebSocketFrame("[系统消息] " + sdf.format(new Date()) + ":" + channel.remoteAddress() + " 上线\n")); | ||||
|             channelGroup.add(channel); | ||||
|  | ||||
|             //构建推送消息 | ||||
|             List<Long> userIds = new ArrayList<>(); | ||||
|             //类型转换 | ||||
|             for (String s : onlineUserList) { | ||||
|                 userIds.add(Long.parseLong(s)); | ||||
|             } | ||||
| //            List<UserDTO> userDTOS = sysUserService.selectListByIds(userIds); | ||||
|  | ||||
|             //构建各个聊天房间未读 数量 | ||||
|             LambdaQueryWrapper<ChatGroup> queryWrapper = new LambdaQueryWrapper<>(); | ||||
|             queryWrapper.like(ChatGroup::getMembers, loginUser.getUserId()+",").or().like(ChatGroup::getMembers,loginUser.getUserId()+"]"); | ||||
|             //拿到该用户的房间列表 | ||||
|             List<ChatGroup> chatGroups = chatGroupService.list(queryWrapper); | ||||
|             if (chatGroups != null && !chatGroups.isEmpty()) { | ||||
| //                List<HashMap<String, Object>> roomCounts = new ArrayList<>(); | ||||
|                 HashMap<String, Object> roomCounts = new HashMap<>(); | ||||
|                 for (ChatGroup chatGroup : chatGroups) { | ||||
|                     LambdaQueryWrapper<ChatHistory> queryWrapper1 = new LambdaQueryWrapper<>(); | ||||
|                     queryWrapper1.eq(ChatHistory::getGeterId, chatGroup.getId()); | ||||
|                     queryWrapper1.ne(ChatHistory::getSenderId, loginUser.getUserId()); | ||||
|                     queryWrapper1.eq(ChatHistory::getIsRead, "1"); | ||||
|                     List<ChatHistory> list = chatHistoryService.list(queryWrapper1); | ||||
|                     if (list != null && !list.isEmpty()) { | ||||
| //                        HashMap<String, Object> map = new HashMap<>(); | ||||
|                         roomCounts.put(chatGroup.getId().toString(), list.size()); | ||||
| //                        roomCounts.add(map); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 JSONObject message = new JSONObject(); | ||||
| //              message.put("type", "2"); | ||||
| //              message.put("onLineUser", userDTOS); | ||||
|                 message.put("type", "3"); | ||||
|                 message.put("unReadCount", roomCounts); | ||||
|                 log.info("发送所有未读消息:{}",message); | ||||
| //              channelGroup.writeAndFlush(new TextWebSocketFrame(message.toJSONString())); | ||||
|  | ||||
|                 sendMessage(ctx, message.toJSONString()); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         super.userEventTriggered(ctx, evt); | ||||
|     } | ||||
|  | ||||
|     // 当有客户端断开连接时调用 | ||||
|     @Override | ||||
|     public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { | ||||
|         Channel channel = ctx.channel(); | ||||
|         // 实际上ChannelGroup会自动移除断开连接的channel,这里只是演示 | ||||
|         // 向所有已连接的客户端广播客户端离开的消息 | ||||
|         channelGroup.writeAndFlush(new TextWebSocketFrame("[系统消息] " + sdf.format(new Date()) + ":" + channel.remoteAddress() + " 离开聊天\n")); | ||||
|         channelGroup.remove(channel); | ||||
|         log.info("{} 离开聊天,剩余在线人数:{}", channel.remoteAddress(), channelGroup.size()); | ||||
|  | ||||
|         //先找到该通道绑定的哪个账号 | ||||
|         String userId = channelUserMap.get(ctx); | ||||
|         if (userId != null) { | ||||
|             //获取该账号下的通道列表 剔除元素 | ||||
|             List<ChannelHandlerContext> channelHandlerContexts = userChannelMap.get(userId); | ||||
|             channelHandlerContexts.remove(ctx); | ||||
|             //如果该账号下没有通道实例了 | ||||
|             if (channelHandlerContexts.isEmpty()) { | ||||
|                 //在缓存的列表里去掉在线ID 然后更新缓存 | ||||
|                 onlineUserList.remove(userId); | ||||
|                 //删除该账号的通道实例列表 | ||||
|                 userChannelMap.remove(userId); | ||||
|  | ||||
|                 //构建推送消息 | ||||
|                 List<Long> userIds = new ArrayList<>(); | ||||
|                 //类型转换 | ||||
|                 for (String s : onlineUserList) { | ||||
|                     userIds.add(Long.parseLong(s)); | ||||
|                 } | ||||
|                 List<UserDTO> userDTOS = sysUserService.selectListByIds(userIds); | ||||
|  | ||||
|                 JSONObject message = new JSONObject(); | ||||
|                 message.put("type", "2"); | ||||
|                 message.put("users", userDTOS); | ||||
|                 channelGroup.writeAndFlush(new TextWebSocketFrame(message.toJSONString())); | ||||
|             } else { | ||||
|                 userChannelMap.put(userId, channelHandlerContexts); | ||||
|             } | ||||
|             //删除 通道-ID | ||||
|             channelUserMap.remove(ctx); | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     // 当通道就绪时调用 | ||||
|     @Override | ||||
|     public void channelActive(ChannelHandlerContext ctx) throws Exception { | ||||
|         log.info("{} 上线了", ctx.channel().remoteAddress()); | ||||
|     } | ||||
|  | ||||
|     // 当通道不可用时调用 | ||||
|     @Override | ||||
|     public void channelInactive(ChannelHandlerContext ctx) throws Exception { | ||||
|         log.info(ctx.channel().remoteAddress() + " 下线了"); | ||||
|     } | ||||
|  | ||||
|     // 读取客户端发送的消息 | ||||
|     @Transactional | ||||
|     @Override | ||||
|     protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { | ||||
|  | ||||
| //        { | ||||
| //            "type":"0", | ||||
| //            "from":"66666666", | ||||
| //            "roomId": "1", | ||||
| //            "message": "testing" | ||||
| //        } | ||||
|         //0聊天推送的正常消息  1前端主动发送消息以确认消息收到 3发送离线后未读消息列表 | ||||
|         //前端判断当前聊天框跟消息接收ID一致后,收到消息后,主动发送消息给服务端,确认该消息收到 | ||||
|         //当发送消息后,给接收方推送未读消息 | ||||
|  | ||||
|         JSONObject jsonObject = JSONObject.parseObject(msg.text()); | ||||
|         String type = jsonObject.get("type").toString(); | ||||
|  | ||||
|         if ("0".equals(type)) { | ||||
|             //来自哪个用户 | ||||
|             jsonObject.put("from", channelUserMap.get(ctx)); | ||||
|             log.info("收到客户端消息:{}", jsonObject); | ||||
|             String RoomId = jsonObject.get("roomId").toString(); | ||||
|             //根据ID拿到房间实例 | ||||
|             ChatGroup byId = chatGroupService.getById(RoomId); | ||||
|             //通过RoomId拿到该房间的所有成员 | ||||
|             List<Long> ids = JSONObject.parseArray(byId.getMembers(), Long.class); | ||||
|             if (ids != null && !ids.isEmpty()) { | ||||
|                 //要从IDS中去掉自己ID防止发送自己消息 | ||||
|                 ids.remove(Long.valueOf(channelUserMap.get(ctx))); | ||||
|                 for (Long id : ids) { | ||||
|                     //通过每个用户ID拿到该用户所有通道实例 | ||||
|                     List<ChannelHandlerContext> channelHandlerContexts = userChannelMap.get(id.toString()); | ||||
|                     //如果满足则说明用户在线 | ||||
|                     if (channelHandlerContexts != null && !channelHandlerContexts.isEmpty()) { | ||||
|                         //只要发送一条数据,就要给接收方推送所有未读消息 | ||||
|                         if (!userRoomCountMap.containsKey(id + "+" + RoomId)) { | ||||
|                             userRoomCountMap.put(id + "+" + RoomId, 1); | ||||
|                         }else { | ||||
|                             userRoomCountMap.put(id + "+" + RoomId, userRoomCountMap.get(id + "+" + RoomId) + 1); | ||||
|                         } | ||||
|                         //所有房间的未读消息数 | ||||
|                         jsonObject.put("countValue", JsonUtils.toJsonString(userRoomCountMap)); | ||||
|                         //给每个通道发送对应消息 | ||||
|                         for (ChannelHandlerContext handlerContext : channelHandlerContexts) { | ||||
|                             sendMessage(handlerContext, jsonObject.toString()); | ||||
|                             log.info("发送消息{}", jsonObject); | ||||
|                         } | ||||
|                     } | ||||
|                     //发送消息完成后添加聊天记录 | ||||
|                     ChatHistory chatHistory = new ChatHistory(); | ||||
|                     chatHistory.setMessageDate(new Date()); | ||||
|                     chatHistory.setGeterId(Long.valueOf(RoomId)); | ||||
|                     chatHistory.setSenderId(Long.valueOf(channelUserMap.get(ctx))); | ||||
|                     chatHistory.setIsRead("1"); | ||||
|                     chatHistory.setMessage(String.valueOf(jsonObject)); | ||||
|                     chatHistoryService.save(chatHistory); | ||||
|  | ||||
|                     //将房间最后消息及时间存储 | ||||
|                     byId.setLastMessage(jsonObject.get("message").toString()); | ||||
|                     byId.setLastMessageTime(new Date()); | ||||
|                     chatGroupService.updateById(byId); | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         }else if ("1".equals(type)){ | ||||
|             log.info("收到客户端确认消息:{}", jsonObject); | ||||
|             //将数据库中该消息的已读状态改为已读 | ||||
|             LambdaQueryWrapper<ChatHistory> lambdaQueryWrapper = new LambdaQueryWrapper<>(); | ||||
|             lambdaQueryWrapper | ||||
|                 .eq(ChatHistory::getSenderId,jsonObject.get("from")) | ||||
|                 .eq(ChatHistory::getGeterId,jsonObject.get("roomId")) | ||||
|                 .eq(ChatHistory::getMessage,jsonObject.get("message")) | ||||
|                 .eq(ChatHistory::getIsRead,"1"); | ||||
|             List<ChatHistory> list = chatHistoryService.list(lambdaQueryWrapper); | ||||
|             if (list != null && !list.isEmpty()){ | ||||
|                 for (ChatHistory chatHistory : list) { | ||||
|                     chatHistory.setIsRead("0"); | ||||
|                 } | ||||
|             } | ||||
|             chatHistoryService.updateBatchById( list); | ||||
|  | ||||
|             //将未读消息数减一 | ||||
|             if(userRoomCountMap.get(channelUserMap.get(ctx) + "+" + jsonObject.get("roomId")) > 0) { | ||||
|                 userRoomCountMap.put(channelUserMap.get(ctx) + "+" + jsonObject.get("roomId"), userRoomCountMap.get(channelUserMap.get(ctx) + "+" + jsonObject.get("roomId")) - 1); | ||||
|             }else { | ||||
|                 userRoomCountMap.put(channelUserMap.get(ctx) + "+" + jsonObject.get("roomId"), 0); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 处理异常 | ||||
|     @Override | ||||
|     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | ||||
|         log.error("发生异常:{}", cause.getMessage()); | ||||
| //        this.handlerRemoved( ctx); | ||||
|         ctx.close(); // 关闭通道 | ||||
|     } | ||||
|  | ||||
|     //给固定的人发消息 | ||||
|     private void sendMessage(ChannelHandlerContext ctx,String  message) { | ||||
|  | ||||
|         ctx.channel().writeAndFlush(new TextWebSocketFrame(message)); | ||||
|     } | ||||
|     //发送群消息,此时其他客户端也能收到群消息 | ||||
|     private void sendAllMessage(){ | ||||
|         String message = "我是服务器,这里发送的是群消息"; | ||||
|         channelGroup.writeAndFlush( new TextWebSocketFrame(message)); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     //通过userId进行发送消息 | ||||
|     private void sendMessageByUserId(Long userId,String message){ | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,145 @@ | ||||
| package org.dromara.websocket.controller; | ||||
|  | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaCheckPermission; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.service.impl.SysUserServiceImpl; | ||||
| import org.dromara.websocket.domain.ChatFriendship; | ||||
| import org.dromara.websocket.service.Impl.ChatFriendshipServiceImpl; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RequestParam; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| @RestController | ||||
| @RequestMapping("/chatFriendship") | ||||
| public class ChatFriendshipController { | ||||
|  | ||||
|     @Autowired | ||||
|     private ChatFriendshipServiceImpl chatFriendshipService; | ||||
|     @Autowired | ||||
|     private SysUserServiceImpl sysUserService; | ||||
|  | ||||
|     /** | ||||
|      * 同步部门下的所有用户 每次进入都可调用 判断出没有的好友关系进行同步 | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:chatFriendship:addFromDept") | ||||
|     @GetMapping("/addFromDept") | ||||
|     @Transactional | ||||
|     public R<Void> addFromDept(){ | ||||
|         Long userId = LoginHelper.getLoginUser().getUserId(); | ||||
|         Long deptId = LoginHelper.getLoginUser().getDeptId(); | ||||
|         LambdaQueryWrapper<ChatFriendship> lambdaQueryWrapper = new LambdaQueryWrapper<>(); | ||||
|  | ||||
|         //首先处理以前部门好友关系 | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getOurSide,userId); | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getType,"0"); | ||||
|         lambdaQueryWrapper.ne(ChatFriendship::getFromDept,deptId); | ||||
|         chatFriendshipService.remove(lambdaQueryWrapper); | ||||
|  | ||||
|         //需要新增的关系列表 | ||||
|         List<ChatFriendship> chatFriendshipList = new ArrayList<>(); | ||||
|         //查询出同部门下的用户 | ||||
|         List<SysUserVo> sysUserVos = sysUserService.selectUserListByDept(deptId); | ||||
|         for (SysUserVo sysUserVo : sysUserVos) { | ||||
|             if (sysUserVo.getUserId().equals(userId)){ | ||||
|                 sysUserVos.remove(sysUserVo); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         //查询出自己的所有好友关系 | ||||
|         lambdaQueryWrapper = new LambdaQueryWrapper<>(); | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getOurSide,userId); | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getType,"0"); | ||||
|         List<ChatFriendship> chatFriendships = chatFriendshipService.list(lambdaQueryWrapper); | ||||
|         for (SysUserVo sysUserVo : sysUserVos) { | ||||
|             boolean isFind = false; | ||||
|             for (ChatFriendship chatFriendship : chatFriendships) { | ||||
|                 if (chatFriendship.getOtherSide().equals(sysUserVo.getUserId()) && chatFriendship.getOurSide().equals(userId)){ | ||||
|                     chatFriendships.remove(chatFriendship); | ||||
|                     isFind = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (!isFind){ | ||||
|                 ChatFriendship chatFriendship = new ChatFriendship(); | ||||
|                 chatFriendship.setOtherSide(sysUserVo.getUserId()); | ||||
|                 chatFriendship.setOurSide(userId); | ||||
|                 chatFriendship.setType("0"); | ||||
|                 chatFriendship.setFromDept(deptId); | ||||
|                 chatFriendshipList.add(chatFriendship); | ||||
|             } | ||||
|         } | ||||
|         if (!chatFriendshipList.isEmpty()){ | ||||
|             boolean b = chatFriendshipService.saveBatch(chatFriendshipList); | ||||
|             if (b){ | ||||
|                 return R.ok(); | ||||
|             }else { | ||||
|                 return R.fail("同步失败"); | ||||
|             } | ||||
|         }else { | ||||
|             return R.ok("无新增关系"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 添加好友关系 | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:chatFriendship:add") | ||||
|     @Transactional | ||||
|     @GetMapping("/add") | ||||
|     public R<Void> add(@RequestParam Long otherSide){ | ||||
|         Long userId = LoginHelper.getLoginUser().getUserId(); | ||||
|  | ||||
|         if (userId.equals(otherSide)){ | ||||
|             return R.fail("不能添加自己为好友"); | ||||
|         } | ||||
|  | ||||
|         LambdaQueryWrapper<ChatFriendship> lambdaQueryWrapper = new LambdaQueryWrapper<>(); | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getOtherSide,otherSide); | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getOurSide,userId); | ||||
|         ChatFriendship one = chatFriendshipService.getOne(lambdaQueryWrapper); | ||||
|         if (one != null){ | ||||
|             return R.fail("已添加"); | ||||
|         } | ||||
|  | ||||
|         ChatFriendship chatFriendship = new ChatFriendship(); | ||||
|         chatFriendship.setOtherSide(otherSide); | ||||
|         chatFriendship.setOurSide(userId); | ||||
|         chatFriendship.setType("1"); | ||||
|         boolean b = chatFriendshipService.save(chatFriendship); | ||||
|         if (b){ | ||||
|             return R.ok("添加成功"); | ||||
|         }else { | ||||
|             return R.fail(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 获取好友列表 | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:chatFriendship:getList") | ||||
|     @GetMapping("/getList") | ||||
|     public R<List<SysUserVo>> getList(){ | ||||
|         Long userId = LoginHelper.getLoginUser().getUserId(); | ||||
|         LambdaQueryWrapper<ChatFriendship> lambdaQueryWrapper = new LambdaQueryWrapper<>(); | ||||
|         lambdaQueryWrapper.eq(ChatFriendship::getOurSide,userId); | ||||
|         List<ChatFriendship> list = chatFriendshipService.list(lambdaQueryWrapper); | ||||
|  | ||||
|         List<SysUserVo> sysUserVos = new ArrayList<>(); | ||||
|         for (ChatFriendship chatFriendship : list) { | ||||
|             sysUserVos.add(sysUserService.selectUserById(chatFriendship.getOtherSide())); | ||||
|         } | ||||
|         return R.ok(sysUserVos); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,162 @@ | ||||
| package org.dromara.websocket.controller; | ||||
|  | ||||
| import cn.dev33.satoken.annotation.SaCheckPermission; | ||||
| import com.alibaba.fastjson.JSONObject; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import org.dromara.common.core.domain.R; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.service.impl.SysUserServiceImpl; | ||||
| import org.dromara.websocket.domain.ChatGroup; | ||||
| import org.dromara.websocket.domain.ChatHistory; | ||||
| import org.dromara.websocket.service.Impl.ChatGroupServiceImpl; | ||||
| import org.dromara.websocket.service.Impl.ChatHistoryServiceImpl; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.RequestMapping; | ||||
| import org.springframework.web.bind.annotation.RequestParam; | ||||
| import org.springframework.web.bind.annotation.RestController; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
|  | ||||
| @RestController | ||||
| @RequestMapping("/chatGroup") | ||||
| public class ChatGroupController { | ||||
|  | ||||
|     @Autowired | ||||
|     private ChatGroupServiceImpl chatGroupService; | ||||
|     @Autowired | ||||
|     private ChatHistoryServiceImpl chatHistoryService; | ||||
|     @Autowired | ||||
|     private SysUserServiceImpl sysUserService; | ||||
|  | ||||
|     /*** | ||||
|      * 新建聊天房间 不论单群 | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:create:add") | ||||
|     @GetMapping("/create") | ||||
|     public R<ChatGroup> createChatGroup(@RequestParam String type, @RequestParam Long[] ids, @RequestParam(required = false) String name) { | ||||
|         Long userId = LoginHelper.getLoginUser().getUserId(); | ||||
|         List<Long> idList = new ArrayList<>(Arrays.asList(ids)); | ||||
|         idList.add(userId); | ||||
|  | ||||
|         //在点击聊天 新建房间之前 判断是否已经有该房间 没有则创建 有再判断是否是隐藏 修改状态更新 | ||||
|         boolean isHave = false; | ||||
|         LambdaQueryWrapper<ChatGroup> queryWrapper = new LambdaQueryWrapper<>(); | ||||
|         if (type.equals("0")){ | ||||
|             //单聊 | ||||
|             queryWrapper.eq(ChatGroup::getType,"0").eq(ChatGroup::getMembers,idList.toString()); | ||||
|             ChatGroup one = chatGroupService.getOne(queryWrapper); | ||||
|             if (one!=null){ | ||||
|                 return R.ok(one); | ||||
|             } | ||||
|         }else if (type.equals("1")){ | ||||
|             //群聊 | ||||
|             queryWrapper.clear(); | ||||
|             queryWrapper.eq(ChatGroup::getType,"1").eq(ChatGroup::getMembers,idList.toString()); | ||||
|             queryWrapper.eq(ChatGroup::getOwerId,userId); | ||||
|             ChatGroup one = chatGroupService.getOne(queryWrapper); | ||||
|             if (one!=null){ | ||||
|                 return R.ok(one); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         ChatGroup chatGroup = new ChatGroup(); | ||||
|         chatGroup.setMembers(idList.toString()); | ||||
|         if (type.equals("1")){ | ||||
|             if (name == null){ | ||||
|                 return R.fail("群聊名称不能为空"); | ||||
|             } | ||||
|             chatGroup.setOwerId(userId); | ||||
|             chatGroup.setName(name); | ||||
|         }else { | ||||
|             chatGroup.setName(null); | ||||
|             chatGroup.setOwerId(null); | ||||
|         } | ||||
|  | ||||
|         boolean save = chatGroupService.save(chatGroup); | ||||
|         if (save) { | ||||
|             return R.ok(chatGroup); | ||||
|         }else { | ||||
|             return R.fail("创建群聊关系失败"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /*** | ||||
|      * 查看与自己有关聊天房间 不论单群 | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:list:getList") | ||||
|     @GetMapping("/list") | ||||
|     public R<List<ChatGroup>> listChatGroup() { | ||||
|         Long userId = LoginHelper.getLoginUser().getUserId(); | ||||
|         LambdaQueryWrapper<ChatGroup> queryWrapper = new LambdaQueryWrapper<>(); | ||||
|         //无论单群聊 群聊 成员都会有自己 | ||||
|         queryWrapper.like(ChatGroup::getMembers,userId+",").or().like(ChatGroup::getMembers,userId+"]");//.eq(ChatGroup::getOwerId,userId).or() | ||||
|         //按最后聊天时间排序 | ||||
|         queryWrapper.orderByDesc(ChatGroup::getLastMessageTime); | ||||
|         List<ChatGroup> list = chatGroupService.list(queryWrapper); | ||||
|         for (ChatGroup chatGroup : list) { | ||||
|             setValue(chatGroup,userId); | ||||
|         } | ||||
|         return R.ok(list); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查看某个房间的详情信息 传递房间ID | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:list:getInfo") | ||||
|     @GetMapping("/getInfo") | ||||
|     public R<ChatGroup> getInfo(@RequestParam Long id){ | ||||
|         Long userId = LoginHelper.getLoginUser().getUserId(); | ||||
|  | ||||
|         ChatGroup byId = chatGroupService.getById(id); | ||||
|         setValue(byId,userId); | ||||
|  | ||||
|         return R.ok(byId); | ||||
|     } | ||||
|  | ||||
|     /*** | ||||
|      * 获取房间聊天记录 传递房间ID 获取发送给该房间的所有聊天记录 | ||||
|      */ | ||||
| //    @SaCheckPermission("chatGroup:list:getHistory") | ||||
|     @GetMapping("/groupChatRecord") | ||||
|     public R<List<ChatHistory>> groupChatRecord(@RequestParam Long id) { | ||||
|         LambdaQueryWrapper<ChatHistory> lambdaQueryWrapper = new LambdaQueryWrapper<>(); | ||||
| //        lambdaQueryWrapper.eq(ChatHistory::getGroupId,id).eq(ChatHistory::getType,"1"); | ||||
|         lambdaQueryWrapper.eq(ChatHistory::getGeterId, id); | ||||
|         List<ChatHistory> list = chatHistoryService.list(lambdaQueryWrapper); | ||||
|         for (ChatHistory chatHistory : list) { | ||||
|             SysUserVo sysUserVo = sysUserService.selectUserById(chatHistory.getSenderId()); | ||||
|             if (sysUserVo != null){ | ||||
|                 chatHistory.setAvatar(sysUserVo.getAvatar()); | ||||
|                 chatHistory.setNickName(sysUserVo.getNickName()); | ||||
|             } | ||||
|         } | ||||
|         return R.ok(chatHistoryService.list(lambdaQueryWrapper)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 将房间进行返回前的处理 | ||||
|      */ | ||||
|     private void setValue(ChatGroup byId, Long userId){ | ||||
|         if (byId.getType().equals("0")){ | ||||
|             //单聊 要获取对方头像 对方的名称作为聊天昵称 | ||||
|             String members = byId.getMembers(); | ||||
|             List<Long> list = JSONObject.parseArray(members, Long.class); | ||||
|             list.remove(userId); | ||||
|             //如果单聊 则集合只剩有一人 | ||||
|             SysUserVo sysUserVo = sysUserService.selectUserById(list.get(0)); | ||||
|             byId.setName(sysUserVo.getNickName()); | ||||
|             byId.setAvatar(sysUserVo.getAvatar()); | ||||
|         }else { | ||||
|             //群聊 则只需要将群主头像赋值给群聊头像 | ||||
|             SysUserVo sysUserVo = sysUserService.selectUserById(byId.getOwerId()); | ||||
|             byId.setAvatar(sysUserVo.getAvatar()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,22 @@ | ||||
| package org.dromara.websocket.domain; | ||||
|  | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Data | ||||
| @TableName("chat_friendship") | ||||
| public class ChatFriendship { | ||||
|  | ||||
|     @TableId("id") | ||||
|     private Long id; | ||||
|  | ||||
|     private Long ourSide; | ||||
|  | ||||
|     private Long otherSide; | ||||
|  | ||||
|     private Long fromDept; | ||||
|  | ||||
|     private String type; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,46 @@ | ||||
| package org.dromara.websocket.domain; | ||||
|  | ||||
| import com.baomidou.mybatisplus.annotation.TableField; | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| import lombok.Data; | ||||
| import org.dromara.common.translation.annotation.Translation; | ||||
| import org.dromara.common.translation.constant.TransConstant; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
|  | ||||
| @TableName("chat_group") | ||||
| @Data | ||||
| public class ChatGroup implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     @TableId(value = "id") | ||||
|     private Long id; | ||||
|  | ||||
|     private String type; | ||||
|  | ||||
|     private String name; | ||||
|  | ||||
|     private Long owerId; | ||||
|  | ||||
|     private String members; | ||||
|  | ||||
|     private String lastMessage; | ||||
|  | ||||
|     private Date lastMessageTime; | ||||
|  | ||||
|     @TableField(exist = false) | ||||
|     @Translation(type = TransConstant.OSS_ID_TO_URL) | ||||
|     private Long avatar; | ||||
|  | ||||
|     /** | ||||
|      * 是否显示0显示1隐藏 | ||||
|      */ | ||||
|     private String isShowOut; | ||||
|  | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package org.dromara.websocket.domain; | ||||
|  | ||||
| import com.baomidou.mybatisplus.annotation.TableField; | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| import lombok.Data; | ||||
| import org.dromara.common.translation.annotation.Translation; | ||||
| import org.dromara.common.translation.constant.TransConstant; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.util.Date; | ||||
|  | ||||
| @Data | ||||
| @TableName("chat_history") | ||||
| public class ChatHistory { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     @TableId(value = "id") | ||||
|     private Long id; | ||||
|  | ||||
|     /*** | ||||
|      * 0私聊1群聊 | ||||
|      */ | ||||
| //    private String type; | ||||
|  | ||||
| //    private Long groupId; | ||||
|  | ||||
|     private Long senderId; | ||||
|  | ||||
|     /*** | ||||
|      * 接收房间id | ||||
|      */ | ||||
|     private Long geterId; | ||||
|  | ||||
|     private String message; | ||||
|  | ||||
|     private Date messageDate; | ||||
|  | ||||
|     /** | ||||
|      * 发送人头像 | ||||
|      */ | ||||
|     @TableField(exist = false) | ||||
|     @Translation(type = TransConstant.OSS_ID_TO_URL) | ||||
|     private Long avatar; | ||||
|  | ||||
|     /** | ||||
|      * 发送人昵称 | ||||
|      */ | ||||
|     @TableField(exist = false) | ||||
|     private String nickName; | ||||
|  | ||||
|     /*** | ||||
|      * 0读1未 | ||||
|      */ | ||||
|     private String isRead; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,10 @@ | ||||
| package org.dromara.websocket.mapper; | ||||
|  | ||||
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
| import org.dromara.websocket.domain.ChatFriendship; | ||||
|  | ||||
| @Mapper | ||||
| public interface ChatFriendshipMapper extends BaseMapper<ChatFriendship> { | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,9 @@ | ||||
| package org.dromara.websocket.mapper; | ||||
|  | ||||
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
| import org.dromara.websocket.domain.ChatGroup; | ||||
|  | ||||
| @Mapper | ||||
| public interface ChatGroupMapper extends BaseMapper<ChatGroup> { | ||||
| } | ||||
| @ -0,0 +1,9 @@ | ||||
| package org.dromara.websocket.mapper; | ||||
|  | ||||
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
| import org.dromara.websocket.domain.ChatHistory; | ||||
|  | ||||
| @Mapper | ||||
| public interface ChatHistoryMapper extends BaseMapper<ChatHistory> { | ||||
| } | ||||
| @ -0,0 +1,7 @@ | ||||
| package org.dromara.websocket.service; | ||||
|  | ||||
| import com.baomidou.mybatisplus.extension.service.IService; | ||||
| import org.dromara.websocket.domain.ChatHistory; | ||||
|  | ||||
| public interface IChatHistoryService extends IService<ChatHistory> { | ||||
| } | ||||
| @ -0,0 +1,11 @@ | ||||
| package org.dromara.websocket.service.Impl; | ||||
|  | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import org.dromara.websocket.domain.ChatFriendship; | ||||
| import org.dromara.websocket.mapper.ChatFriendshipMapper; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| @Service | ||||
| public class ChatFriendshipServiceImpl extends ServiceImpl<ChatFriendshipMapper, ChatFriendship> { | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,10 @@ | ||||
| package org.dromara.websocket.service.Impl; | ||||
|  | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import org.dromara.websocket.domain.ChatGroup; | ||||
| import org.dromara.websocket.mapper.ChatGroupMapper; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| @Service | ||||
| public class ChatGroupServiceImpl extends ServiceImpl<ChatGroupMapper, ChatGroup> { | ||||
| } | ||||
| @ -0,0 +1,13 @@ | ||||
| package org.dromara.websocket.service.Impl; | ||||
|  | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import org.dromara.tender.service.ITenderSupplierInputService; | ||||
| import org.dromara.websocket.domain.ChatHistory; | ||||
| import org.dromara.websocket.mapper.ChatHistoryMapper; | ||||
| import org.dromara.websocket.service.IChatHistoryService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| @Service | ||||
| public class ChatHistoryServiceImpl extends ServiceImpl<ChatHistoryMapper, ChatHistory> implements IChatHistoryService { | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user