├── easychat-user ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── easychat │ │ │ └── user │ │ │ ├── vo │ │ │ ├── ValidateUsernameRequest.java │ │ │ ├── SendCodeRequest.java │ │ │ ├── UpdateTagsRequest.java │ │ │ ├── ChangeStatusRequest.java │ │ │ ├── RemoveFriendRequest.java │ │ │ ├── ValidateCodeRequest.java │ │ │ ├── ValidatePasswordRequest.java │ │ │ ├── ChangePasswordRequest.java │ │ │ ├── EditFriendVerifyRequest.java │ │ │ ├── EditFriendRequest.java │ │ │ ├── RegisterRequest.java │ │ │ ├── AddFriendRequest.java │ │ │ ├── AddFriendVerifyRequest.java │ │ │ └── EditUserInfoRequest.java │ │ │ ├── dto │ │ │ ├── ValidationInfo.java │ │ │ ├── FriendInfo.java │ │ │ ├── VerifyInfo.java │ │ │ └── UserInfo.java │ │ │ ├── UserApplication.java │ │ │ ├── service │ │ │ ├── EmailService.java │ │ │ ├── FriendService.java │ │ │ ├── impl │ │ │ │ ├── EmailServiceImpl.java │ │ │ │ ├── FriendServiceImpl.java │ │ │ │ └── UserServiceImpl.java │ │ │ └── UserService.java │ │ │ ├── entity │ │ │ ├── FriendVerify.java │ │ │ ├── Friend.java │ │ │ └── User.java │ │ │ ├── mapper │ │ │ ├── UserMapper.java │ │ │ ├── FriendMapper.java │ │ │ └── FriendVerifyMapper.java │ │ │ ├── feign │ │ │ └── FileFeignService.java │ │ │ └── controller │ │ │ ├── FriendController.java │ │ │ └── UserController.java │ │ └── resources │ │ ├── application.yml │ │ ├── logback.xml │ │ └── mapper │ │ ├── FriendMapper.xml │ │ └── FriendVerifyMapper.xml └── pom.xml ├── easychat-chat ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── easychat │ │ │ └── chat │ │ │ ├── vo │ │ │ ├── AddChatRequest.java │ │ │ ├── ChangeStatusRequest.java │ │ │ ├── RemoveChatRequest.java │ │ │ ├── RemoveFriendRequest.java │ │ │ ├── EditFriendVerifyRequest.java │ │ │ ├── EditFriendRequest.java │ │ │ ├── AddFriendRequest.java │ │ │ └── AddFriendVerifyRequest.java │ │ │ ├── mapper │ │ │ ├── ChatGroupMapper.java │ │ │ └── ChatHistoryMapper.java │ │ │ ├── dto │ │ │ ├── FriendInfo.java │ │ │ ├── ChatInfo.java │ │ │ └── VerifyInfo.java │ │ │ ├── config │ │ │ ├── SocketIOProperties.java │ │ │ ├── MybatisPlusConfig.java │ │ │ └── SocketIOConfig.java │ │ │ ├── entity │ │ │ ├── ChatGroup.java │ │ │ └── ChatHistory.java │ │ │ ├── feign │ │ │ ├── FileFeignService.java │ │ │ └── UserFeignService.java │ │ │ ├── ChatApplication.java │ │ │ ├── service │ │ │ ├── UserOnlineService.java │ │ │ ├── impl │ │ │ │ ├── UserOnlineServiceImpl.java │ │ │ │ └── ChatServiceImpl.java │ │ │ └── ChatService.java │ │ │ ├── controller │ │ │ └── ChatController.java │ │ │ └── handler │ │ │ └── MessageEventHandler.java │ │ └── resources │ │ ├── application.yml │ │ ├── logback.xml │ │ └── mapper │ │ └── ChatHistoryMapper.xml └── pom.xml ├── easychat-auth ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── easychat │ │ │ └── auth │ │ │ ├── vo │ │ │ └── LoginRequest.java │ │ │ ├── dto │ │ │ └── UserJwt.java │ │ │ ├── AuthApplication.java │ │ │ ├── feign │ │ │ └── UserFeignService.java │ │ │ ├── config │ │ │ ├── CorsConfig.java │ │ │ └── SecurityConfig.java │ │ │ ├── service │ │ │ ├── AuthService.java │ │ │ └── impl │ │ │ │ └── AuthServiceImpl.java │ │ │ └── controller │ │ │ └── AuthController.java │ │ └── resources │ │ └── application.yml └── pom.xml ├── easychat-common ├── src │ └── main │ │ └── java │ │ └── com │ │ └── easychat │ │ └── common │ │ ├── util │ │ ├── SequenceIdGenerator.java │ │ ├── CookieUtil.java │ │ ├── JwtUtil.java │ │ ├── MD5Util.java │ │ └── SnowflakeIdWorker.java │ │ ├── protocol │ │ ├── ResultCode.java │ │ ├── ResponseResult.java │ │ └── CommonCode.java │ │ └── exception │ │ ├── CustomException.java │ │ └── GlobalExceptionHandler.java └── pom.xml ├── .gitignore ├── easychat-gateway ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── easychat │ │ │ └── gateway │ │ │ └── GatewayApplication.java │ │ └── resources │ │ └── application.yml └── pom.xml ├── easychat-filesystem ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── easychat │ │ │ └── filesystem │ │ │ ├── FileSystemApplication.java │ │ │ ├── service │ │ │ ├── FileService.java │ │ │ └── impl │ │ │ │ └── FileServiceImpl.java │ │ │ └── controller │ │ │ └── FileController.java │ │ └── resources │ │ ├── application.yml │ │ └── logback.xml └── pom.xml ├── LICENSE ├── README.md ├── pom.xml └── sql └── easychat.sql /easychat-user/src/main/java/com/easychat/user/vo/ValidateUsernameRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-01 19:05 8 | */ 9 | @Data 10 | public class ValidateUsernameRequest { 11 | 12 | private String username; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/dto/ValidationInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-01 7:40 8 | */ 9 | @Data 10 | public class ValidationInfo { 11 | 12 | private String userId; 13 | private String email; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/SendCodeRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-06-30 19:16 8 | */ 9 | @Data 10 | public class SendCodeRequest { 11 | 12 | private String email; 13 | private Integer type; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/AddChatRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-28 10:08 8 | */ 9 | @Data 10 | public class AddChatRequest { 11 | 12 | private String userId; 13 | private String friendUserId; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/UpdateTagsRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-26 8:45 8 | */ 9 | @Data 10 | public class UpdateTagsRequest { 11 | 12 | private String userId; 13 | private String tag; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/ChangeStatusRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-26 8:23 8 | */ 9 | @Data 10 | public class ChangeStatusRequest { 11 | 12 | private String userId; 13 | private Integer status; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/RemoveChatRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-28 10:11 8 | */ 9 | @Data 10 | public class RemoveChatRequest { 11 | 12 | private String userId; 13 | private String sessionId; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/ChangeStatusRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-26 8:23 8 | */ 9 | @Data 10 | public class ChangeStatusRequest { 11 | 12 | private String userId; 13 | private Integer status; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/RemoveFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-28 10:05 8 | */ 9 | @Data 10 | public class RemoveFriendRequest { 11 | 12 | private String userId; 13 | private String friendUserId; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/RemoveFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-28 10:05 8 | */ 9 | @Data 10 | public class RemoveFriendRequest { 11 | 12 | private String userId; 13 | private String friendUserId; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/ValidateCodeRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-06-30 18:05 8 | */ 9 | @Data 10 | public class ValidateCodeRequest { 11 | 12 | private String email; 13 | private String verifyCode; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/ValidatePasswordRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-01 7:54 8 | */ 9 | @Data 10 | public class ValidatePasswordRequest { 11 | 12 | private String userId; 13 | private String password; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/vo/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-28 10:00 8 | */ 9 | @Data 10 | public class LoginRequest { 11 | 12 | private String username; 13 | private String password; 14 | private Boolean loginFree; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/ChangePasswordRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-05-03 10:00 8 | */ 9 | @Data 10 | public class ChangePasswordRequest { 11 | 12 | private String userId; 13 | private String newPassword; 14 | private String checkPassword; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/EditFriendVerifyRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 18:15 8 | */ 9 | @Data 10 | public class EditFriendVerifyRequest { 11 | 12 | private String senderId; 13 | private String receiverId; 14 | private Integer status; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/util/SequenceIdGenerator.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.util; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public abstract class SequenceIdGenerator { 6 | 7 | private static final AtomicInteger ID = new AtomicInteger(); 8 | 9 | public static int nextId() { 10 | return ID.incrementAndGet(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/dto/UserJwt.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-05-01 14:05 8 | */ 9 | @Data 10 | public class UserJwt { 11 | 12 | private String id; 13 | private String username; 14 | private String nickName; 15 | private String avatar; 16 | private String jwt; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/EditFriendVerifyRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 18:15 8 | */ 9 | @Data 10 | public class EditFriendVerifyRequest { 11 | 12 | private String senderId; 13 | private String receiverId; 14 | private Integer status; 15 | private Integer hasRead; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/mapper/ChatGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.easychat.chat.entity.ChatGroup; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @Author: long 9 | * @Date: 2022-04-18 12:18 10 | */ 11 | @Mapper 12 | public interface ChatGroupMapper extends BaseMapper { 13 | } 14 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/EditFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 15:14 8 | */ 9 | @Data 10 | public class EditFriendRequest { 11 | 12 | private String userId; 13 | private String friendUserId; 14 | private String sessionId; 15 | private String sessionTime; 16 | private String remark; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/EditFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 15:14 8 | */ 9 | @Data 10 | public class EditFriendRequest { 11 | 12 | private String userId; 13 | private String friendUserId; 14 | private String sessionId; 15 | private String sessionTime; 16 | private String remark; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/protocol/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.protocol; 2 | 3 | /** 4 | * @Author: long 5 | * @Date: 2022-04-18 11:18 6 | */ 7 | public interface ResultCode { 8 | 9 | /** 10 | * 操作是否成功,true成功,false失败 11 | */ 12 | boolean success(); 13 | 14 | /** 15 | * 操作代码 16 | */ 17 | int code(); 18 | 19 | /** 20 | * 提示信息 21 | */ 22 | String message(); 23 | } 24 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/RegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-05-03 9:31 8 | */ 9 | @Data 10 | public class RegisterRequest { 11 | 12 | private String username; 13 | private String nickName; 14 | private String password; 15 | private String email; 16 | private String verifyCode; 17 | private Boolean isAgree; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # Intellij project files 8 | .idea 9 | *.iml 10 | out 11 | target 12 | logs 13 | 14 | # BlueJ files 15 | *.ctxt 16 | 17 | # Mobile Tools for Java (J2ME) 18 | .mtj.tmp/ 19 | 20 | # Package Files # 21 | *.jar 22 | *.war 23 | *.nar 24 | *.ear 25 | *.zip 26 | *.tar.gz 27 | *.rar 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/AddFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-20 12:33 8 | */ 9 | @Data 10 | public class AddFriendRequest { 11 | 12 | private String userId; 13 | private String sessionId; 14 | private String sessionTime; 15 | private String friendUserId; 16 | private String friendRemark; 17 | private String createTime; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/AddFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-20 12:33 8 | */ 9 | @Data 10 | public class AddFriendRequest { 11 | 12 | private String userId; 13 | private String sessionId; 14 | private String sessionTime; 15 | private String friendUserId; 16 | private String friendRemark; 17 | private String createTime; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/vo/AddFriendVerifyRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 10:14 8 | */ 9 | @Data 10 | public class AddFriendVerifyRequest { 11 | 12 | private String senderId; 13 | private String receiverId; 14 | private String applyReason; 15 | private String remark; 16 | private Integer status; 17 | private Integer hasRead; 18 | private String createTime; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /easychat-gateway/src/main/java/com/easychat/gateway/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.easychat.gateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @Author: long 8 | * @Date: 2022-07-01 12:46 9 | */ 10 | @SpringBootApplication 11 | public class GatewayApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(GatewayApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/AddFriendVerifyRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 10:14 8 | */ 9 | @Data 10 | public class AddFriendVerifyRequest { 11 | 12 | private String senderId; 13 | private String receiverId; 14 | private String applyReason; 15 | private String remark; 16 | private Integer status; 17 | private Integer hasRead; 18 | private String createTime; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/vo/EditUserInfoRequest.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-20 12:47 8 | */ 9 | @Data 10 | public class EditUserInfoRequest { 11 | 12 | private String userId; 13 | private String nickName; 14 | private Integer gender; 15 | private String birthday; 16 | private String region; 17 | private String email; 18 | private String phone; 19 | private String introduction; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/dto/FriendInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-21 14:09 8 | */ 9 | @Data 10 | public class FriendInfo { 11 | 12 | private String userId; 13 | private String sessionId; 14 | private String sessionTime; 15 | private String friendUserId; 16 | private String friendRemark; 17 | private String friendNickName; 18 | private String friendAvatar; 19 | private String createTime; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /easychat-auth/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 20020 3 | servlet: 4 | context-path: /auth 5 | session: 6 | tracking-modes: cookie 7 | 8 | spring: 9 | application: 10 | name: easychat-auth-service 11 | cloud: 12 | nacos: 13 | discovery: 14 | server-addr: localhost:8848 15 | namespace: ec0b2714-22be-45cc-800e-fa801b4e94db 16 | cluster-name: shanghai 17 | group: easychat 18 | redis: 19 | host: localhost 20 | port: 6379 21 | password: 123456 22 | connect-timeout: 5000 -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/dto/FriendInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-21 14:09 8 | */ 9 | @Data 10 | public class FriendInfo { 11 | 12 | private String userId; 13 | private String sessionId; 14 | private String sessionTime; 15 | private String friendUserId; 16 | private String friendRemark; 17 | private String friendNickName; 18 | private String friendAvatar; 19 | private String friendIntro; 20 | private String friendTags; 21 | private String createTime; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/dto/ChatInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.dto; 2 | 3 | import com.easychat.chat.entity.ChatHistory; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author: long 8 | * @Date: 2022-04-20 17:33 9 | */ 10 | @Data 11 | public class ChatInfo { 12 | 13 | private String userId; 14 | private String sessionId; 15 | private String sessionTime; 16 | private String friendUserId; 17 | private String friendRemark; 18 | private String friendNickName; 19 | private String friendAvatar; 20 | private ChatHistory latestChatHistory = new ChatHistory(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/dto/VerifyInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 9:16 8 | */ 9 | @Data 10 | public class VerifyInfo { 11 | 12 | private String senderId; 13 | private String senderNickName; 14 | private String senderAvatar; 15 | private String receiverId; 16 | private String receiverNickName; 17 | private String receiverAvatar; 18 | private String applyReason; 19 | private String remark; 20 | private Integer status; 21 | private Integer hasRead; 22 | private String createTime; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /easychat-filesystem/src/main/java/com/easychat/filesystem/FileSystemApplication.java: -------------------------------------------------------------------------------- 1 | package com.easychat.filesystem; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.ComponentScan; 6 | 7 | /** 8 | * @Author: long 9 | * @Date: 2022-04-29 12:56 10 | */ 11 | @SpringBootApplication 12 | @ComponentScan(basePackages = {"com.easychat"}) 13 | public class FileSystemApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(FileSystemApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /easychat-filesystem/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 20050 3 | servlet: 4 | context-path: /file 5 | 6 | spring: 7 | application: 8 | name: easychat-filesystem-service 9 | servlet: 10 | multipart: 11 | max-file-size: 100MB 12 | max-request-size: 100MB 13 | cloud: 14 | nacos: 15 | discovery: 16 | server-addr: localhost:8848 17 | namespace: ec0b2714-22be-45cc-800e-fa801b4e94db 18 | cluster-name: shanghai 19 | group: easychat 20 | 21 | minio: 22 | endpoint: "http://localhost:9000" 23 | accessKey: "******" 24 | secretKey: "******" 25 | bucketName: "easychat" -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/dto/VerifyInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-07-03 9:16 8 | */ 9 | @Data 10 | public class VerifyInfo { 11 | 12 | private String senderId; 13 | private String senderNickName; 14 | private String senderAvatar; 15 | private String receiverId; 16 | private String receiverNickName; 17 | private String receiverAvatar; 18 | private String applyReason; 19 | private String remark; 20 | private Integer status; 21 | private Integer hasRead; 22 | private String createTime; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/exception/CustomException.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.exception; 2 | 3 | import com.easychat.common.protocol.ResultCode; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-19 10:31 8 | */ 9 | public class CustomException extends RuntimeException { 10 | 11 | private final ResultCode resultCode; 12 | 13 | public CustomException(ResultCode resultCode) { 14 | super("错误代码:" + resultCode.code() + " 错误信息:" + resultCode.message()); 15 | this.resultCode = resultCode; 16 | } 17 | 18 | public ResultCode getResultCode() { 19 | return this.resultCode; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/dto/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.dto; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-18 10:35 8 | */ 9 | @Data 10 | public class UserInfo { 11 | 12 | private String id; 13 | private String username; 14 | private String nickName; 15 | private String avatar; 16 | private Integer gender; 17 | private Integer age; 18 | private String birthday; 19 | private String region; 20 | private String email; 21 | private String phone; 22 | private String introduction; 23 | private Integer status; 24 | private String tags; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/AuthApplication.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | import org.springframework.context.annotation.ComponentScan; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-04-30 12:51 11 | */ 12 | @EnableFeignClients 13 | @SpringBootApplication 14 | @ComponentScan(basePackages = {"com.easychat"}) 15 | public class AuthApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(AuthApplication.class, args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/UserApplication.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | import org.springframework.context.annotation.ComponentScan; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-06-30 17:04 11 | */ 12 | @EnableFeignClients 13 | @SpringBootApplication 14 | @ComponentScan(basePackages = {"com.easychat"}) 15 | public class UserApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(UserApplication.class, args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/config/SocketIOProperties.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * @Author: long 8 | * @Date: 2022-05-05 10:02 9 | */ 10 | @Data 11 | @ConfigurationProperties(prefix = "socketio") 12 | public class SocketIOProperties { 13 | 14 | private Integer port; 15 | 16 | private Integer workCount; 17 | 18 | private Boolean allowCustomRequests; 19 | 20 | private Integer upgradeTimeout; 21 | 22 | private Integer pingTimeout; 23 | 24 | private Integer pingInterval; 25 | 26 | private Integer maxFramePayloadLength; 27 | 28 | private Integer maxHttpContentLength; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/feign/UserFeignService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.feign; 2 | 3 | import com.easychat.auth.dto.UserJwt; 4 | import com.easychat.common.protocol.ResponseResult; 5 | import org.springframework.cloud.openfeign.FeignClient; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | 9 | /** 10 | * @Author: long 11 | * @Date: 2022-05-02 10:53 12 | */ 13 | @FeignClient("easychat-user-service") 14 | public interface UserFeignService { 15 | 16 | @GetMapping("/user/user/auth") 17 | ResponseResult getUserInfo(@RequestParam("username") String username, 18 | @RequestParam("password") String password); 19 | } 20 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/service/EmailService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.service; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import com.easychat.user.vo.SendCodeRequest; 5 | import com.easychat.user.vo.ValidateCodeRequest; 6 | 7 | /** 8 | * @Author: long 9 | * @Date: 2022-06-30 18:08 10 | */ 11 | public interface EmailService { 12 | 13 | /** 14 | * 发送验证码到指定邮箱 15 | * 16 | * @param request 验证码发送请求 17 | * @return 响应结果 18 | */ 19 | ResponseResult sendCodeToEmail(SendCodeRequest request); 20 | 21 | /** 22 | * 验证邮箱和验证码是否正确 23 | * 24 | * @param request 验证码验证请求 25 | * @return 响应结果 26 | */ 27 | ResponseResult validateEmailAndCode(ValidateCodeRequest request); 28 | } 29 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/entity/ChatGroup.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | import java.util.Set; 9 | 10 | /** 11 | * @Author: long 12 | * @Date: 2022-04-18 10:21 13 | */ 14 | @TableName("easychat_group") 15 | @Data 16 | public class ChatGroup { 17 | 18 | @TableId(value = "id", type = IdType.ASSIGN_ID) 19 | private String id; 20 | /** 21 | * 聊天组名 22 | */ 23 | private String groupName; 24 | /** 25 | * 成员 id 26 | */ 27 | private Set memberIds; 28 | /** 29 | * 创建时间 30 | */ 31 | private String createTime; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/config/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.config; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; 4 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-05-02 11:26 11 | */ 12 | @Configuration 13 | public class MybatisPlusConfig { 14 | 15 | @Bean 16 | public MybatisPlusInterceptor mybatisPlusInterceptor() { 17 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); 18 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 19 | return interceptor; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/entity/FriendVerify.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-07-03 8:51 11 | */ 12 | @TableName("easychat_friend_verify") 13 | @Data 14 | public class FriendVerify { 15 | 16 | @TableId(value = "id", type = IdType.ASSIGN_ID) 17 | private String id; 18 | private String senderId; 19 | private String receiverId; 20 | private String applyReason; 21 | private String remark; 22 | /** 23 | * 验证状态:0未处理,1同意,2拒绝,3过期 24 | */ 25 | private Integer status; 26 | /** 27 | * 是否已读:0未读,1已读 28 | */ 29 | private Integer hasRead; 30 | private String createTime; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.easychat.user.dto.UserInfo; 5 | import com.easychat.user.entity.User; 6 | import org.apache.ibatis.annotations.Mapper; 7 | import org.apache.ibatis.annotations.Select; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @Author: long 13 | * @Date: 2022-04-18 12:17 14 | */ 15 | @Mapper 16 | public interface UserMapper extends BaseMapper { 17 | 18 | /** 19 | * 根据用户名模糊查询用户列表 20 | * 21 | * @param username 用户名 22 | * @return 用户信息列表 23 | */ 24 | @Select("SELECT id,username,nick_name,avatar,gender,region,introduction,tags " + 25 | "FROM easychat_user " + 26 | "WHERE username LIKE CONCAT('%',#{username},'%')") 27 | List selectUserList(String username); 28 | } 29 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/config/CorsConfig.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-05-01 11:20 8 | */ 9 | @Configuration 10 | public class CorsConfig { 11 | 12 | // @Bean 13 | // public CorsWebFilter corsWebFilter() { 14 | // UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 15 | // CorsConfiguration config = new CorsConfiguration(); 16 | // config.addAllowedOrigin("*"); 17 | // config.addAllowedHeader("*"); 18 | // config.addAllowedMethod("*"); 19 | // config.setAllowCredentials(true); 20 | // config.setMaxAge(3600L); 21 | // source.registerCorsConfiguration("/**", config); 22 | // return new CorsWebFilter(source); 23 | // } 24 | } 25 | -------------------------------------------------------------------------------- /easychat-filesystem/src/main/java/com/easychat/filesystem/service/FileService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.filesystem.service; 2 | 3 | import com.easychat.common.exception.CustomException; 4 | import com.easychat.common.protocol.ResponseResult; 5 | import org.springframework.web.multipart.MultipartFile; 6 | 7 | /** 8 | * @Author: long 9 | * @Date: 2022-04-30 10:17 10 | */ 11 | public interface FileService { 12 | 13 | /** 14 | * 上传文件到 MinIO 15 | * 16 | * @param file 文件 17 | * @param filePath 文件路径 18 | * @return 响应结果 19 | * @throws CustomException 20 | */ 21 | ResponseResult uploadFile(MultipartFile file, String filePath) throws CustomException; 22 | 23 | /** 24 | * 检查文件是否存在 25 | * 26 | * @param filePath 文件路径 27 | * @return 响应结果 28 | * @throws CustomException 29 | */ 30 | ResponseResult checkFile(String filePath) throws CustomException; 31 | } 32 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/feign/FileFeignService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.feign; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.bind.annotation.RequestPart; 9 | import org.springframework.web.multipart.MultipartFile; 10 | 11 | /** 12 | * @Author: long 13 | * @Date: 2022-07-21 15:12 14 | */ 15 | @FeignClient("easychat-filesystem-service") 16 | public interface FileFeignService { 17 | 18 | @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) 19 | ResponseResult uploadFileToMinio(@RequestPart("file") MultipartFile file, 20 | @RequestParam("path") String filePath); 21 | } 22 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/entity/Friend.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-04-19 13:00 11 | */ 12 | @TableName("easychat_friend") 13 | @Data 14 | public class Friend { 15 | 16 | @TableId(value = "id", type = IdType.ASSIGN_ID) 17 | private String id; 18 | /** 19 | * 所属用户 id 20 | */ 21 | private String userId; 22 | /** 23 | * 会话 id 24 | */ 25 | private String sessionId; 26 | /** 27 | * 会话创建时间 28 | */ 29 | private String sessionTime; 30 | /** 31 | * 好友用户 id 32 | */ 33 | private String friendUserId; 34 | /** 35 | * 好友备注 36 | */ 37 | private String friendRemark; 38 | /** 39 | * 创建时间 40 | */ 41 | private String createTime; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/mapper/FriendMapper.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.easychat.user.dto.FriendInfo; 5 | import com.easychat.user.entity.Friend; 6 | import org.apache.ibatis.annotations.Mapper; 7 | import org.apache.ibatis.annotations.Param; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @Author: long 13 | * @Date: 2022-04-20 9:45 14 | */ 15 | @Mapper 16 | public interface FriendMapper extends BaseMapper { 17 | 18 | /** 19 | * 根据用户 id 查询其好友信息列表 20 | * 21 | * @param userId 用户 id 22 | * @return 好友信息列表 23 | */ 24 | List selectFriendInfoList(@Param("userId") String userId); 25 | 26 | /** 27 | * 根据用户 id 和好友用户 id 查询好友信息 28 | * 29 | * @param userId 用户 id 30 | * @param friendUserId 好友用户 id 31 | * @return 好友信息 32 | */ 33 | FriendInfo selectFriendInfo(@Param("userId") String userId, @Param("friendUserId") String friendUserId); 34 | } 35 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/service/AuthService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.service; 2 | 3 | import com.easychat.auth.dto.UserJwt; 4 | import com.easychat.auth.vo.LoginRequest; 5 | import com.easychat.common.exception.CustomException; 6 | 7 | /** 8 | * @Author: long 9 | * @Date: 2022-05-02 10:05 10 | */ 11 | public interface AuthService { 12 | 13 | /** 14 | * 用户登录认证 15 | * 16 | * @param request 登录请求 17 | * @return 用户认证信息 18 | * @throws CustomException 19 | */ 20 | UserJwt loginAuth(LoginRequest request) throws CustomException; 21 | 22 | /** 23 | * 从 redis 中获取用户认证信息 24 | * 25 | * @param userId 用户 id 26 | * @return 用户认证信息 27 | * @throws CustomException 28 | */ 29 | UserJwt getUserJwt(String userId) throws CustomException; 30 | 31 | /** 32 | * 从 redis 中删除用户的 jwt 33 | * 34 | * @param userId 用户 id 35 | * @return 结果 36 | * @throws CustomException 37 | */ 38 | boolean deleteJwt(String userId) throws CustomException; 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 toollong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/feign/FileFeignService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.feign; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RequestPart; 10 | import org.springframework.web.multipart.MultipartFile; 11 | 12 | /** 13 | * @Author: long 14 | * @Date: 2022-07-21 15:12 15 | */ 16 | @FeignClient("easychat-filesystem-service") 17 | public interface FileFeignService { 18 | 19 | @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) 20 | ResponseResult uploadFileToMinio(@RequestPart("file") MultipartFile file, 21 | @RequestParam("path") String filePath); 22 | 23 | @GetMapping("/file/isExist") 24 | ResponseResult checkFileIsExist(@RequestParam("path") String filePath); 25 | } 26 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/entity/ChatHistory.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-04-19 13:40 11 | */ 12 | @TableName("easychat_history") 13 | @Data 14 | public class ChatHistory { 15 | 16 | @TableId(value = "id", type = IdType.ASSIGN_ID) 17 | private String id; 18 | /** 19 | * 发送者 id 20 | */ 21 | private String senderId; 22 | /** 23 | * 接收者 id 24 | */ 25 | private String receiverId; 26 | /** 27 | * 所属会话 id 28 | */ 29 | private String sessionId; 30 | /** 31 | * 内容类型(0 文本,1 图片,2 文件,3 语音) 32 | */ 33 | private Integer type; 34 | /** 35 | * 内容 36 | */ 37 | private String content; 38 | /** 39 | * 创建时间 40 | */ 41 | private String createTime; 42 | /** 43 | * 是否显示时间(1 显示,0 不显示) 44 | */ 45 | private Integer showTime; 46 | /** 47 | * 是否已读(1 已读,0 未读) 48 | */ 49 | private Integer hasRead; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/ChatApplication.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat; 2 | 3 | import com.corundumstudio.socketio.SocketIOServer; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.ApplicationArguments; 7 | import org.springframework.boot.ApplicationRunner; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.cloud.openfeign.EnableFeignClients; 11 | import org.springframework.context.annotation.ComponentScan; 12 | 13 | /** 14 | * @Author: long 15 | * @Date: 2022-04-18 9:59 16 | */ 17 | @EnableFeignClients 18 | @SpringBootApplication 19 | @ComponentScan(basePackages = {"com.easychat"}) 20 | @Slf4j 21 | public class ChatApplication implements ApplicationRunner { 22 | 23 | public static void main(String[] args) { 24 | SpringApplication.run(ChatApplication.class, args); 25 | } 26 | 27 | @Autowired 28 | private SocketIOServer socketIOServer; 29 | 30 | @Override 31 | public void run(ApplicationArguments args) throws Exception { 32 | socketIOServer.start(); 33 | log.info("Socket.IO已启动..."); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /easychat-filesystem/src/main/java/com/easychat/filesystem/controller/FileController.java: -------------------------------------------------------------------------------- 1 | package com.easychat.filesystem.controller; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import com.easychat.filesystem.service.FileService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | import org.springframework.web.multipart.MultipartFile; 11 | 12 | /** 13 | * @Author: long 14 | * @Date: 2022-04-30 10:07 15 | */ 16 | @RestController 17 | public class FileController { 18 | 19 | @Autowired 20 | FileService fileService; 21 | 22 | @PostMapping("/upload") 23 | public ResponseResult uploadFileToMinio(@RequestParam("file") MultipartFile file, 24 | @RequestParam("path") String filePath) { 25 | return fileService.uploadFile(file, filePath); 26 | } 27 | 28 | @GetMapping("/isExist") 29 | public ResponseResult checkFileIsExist(@RequestParam("path") String filePath) { 30 | return fileService.checkFile(filePath); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /easychat-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easychat 7 | com.easychat 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | easychat-gateway 12 | 13 | 14 | 8 15 | 8 16 | 17 | 18 | 19 | 20 | com.alibaba.cloud 21 | spring-cloud-starter-alibaba-nacos-discovery 22 | 23 | 24 | 25 | org.springframework.cloud 26 | spring-cloud-starter-gateway 27 | 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-loadbalancer 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /easychat-user/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 20030 3 | servlet: 4 | context-path: /user 5 | 6 | spring: 7 | application: 8 | name: easychat-user-service 9 | servlet: 10 | multipart: 11 | max-file-size: 2MB 12 | cloud: 13 | nacos: 14 | discovery: 15 | server-addr: localhost:8848 16 | namespace: ec0b2714-22be-45cc-800e-fa801b4e94db 17 | cluster-name: shanghai 18 | group: easychat 19 | datasource: 20 | druid: 21 | driver-class-name: com.mysql.cj.jdbc.Driver 22 | url: jdbc:mysql://localhost:3306/easychat?characterEncoding=utf-8 23 | username: root 24 | password: 123456 25 | initial-size: 5 26 | min-idle: 5 27 | max-active: 20 28 | max-wait: 10000 29 | test-while-idle: true 30 | test-on-borrow: false 31 | test-on-return: false 32 | validation-query: select 1 33 | time-between-eviction-runs-millis: 60000 34 | min-evictable-idle-time-millis: 300000 35 | redis: 36 | host: localhost 37 | port: 6379 38 | password: 123456 39 | connect-timeout: 5000 40 | 41 | mybatis-plus: 42 | configuration: 43 | local-cache-scope: statement # 一级缓存 44 | cache-enabled: false # 二级缓存 45 | map-underscore-to-camel-case: true 46 | global-config: 47 | db-config: 48 | id-type: assign_id 49 | mapper-locations: classpath:/mapper/*.xml 50 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | import lombok.Data; 7 | 8 | /** 9 | * @Author: long 10 | * @Date: 2022-04-18 10:05 11 | */ 12 | @TableName("easychat_user") 13 | @Data 14 | public class User { 15 | 16 | @TableId(value = "id", type = IdType.ASSIGN_ID) 17 | private String id; 18 | private String username; 19 | private String password; 20 | /** 21 | * 昵称 22 | */ 23 | private String nickName; 24 | /** 25 | * 头像 26 | */ 27 | private String avatar = "/avatar/default.jpg"; 28 | /** 29 | * 性别(0 女,1 男,2 保密) 30 | */ 31 | private Integer gender = 2; 32 | private Integer age; 33 | private String birthday; 34 | /** 35 | * 地区 36 | */ 37 | private String region; 38 | private String email; 39 | private String phone; 40 | /** 41 | * 简介 42 | */ 43 | private String introduction; 44 | /** 45 | * 状态(0 隐身,1 在线) 46 | */ 47 | private Integer status = 1; 48 | /** 49 | * 标签 50 | */ 51 | private String tags; 52 | /** 53 | * 加入的聊天组 id 54 | */ 55 | private String groupIds; 56 | private String createTime; 57 | private String updateTime; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /easychat-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 20010 3 | 4 | spring: 5 | application: 6 | name: easychat-gateway-service 7 | cloud: 8 | nacos: 9 | discovery: 10 | server-addr: localhost:8848 11 | namespace: ec0b2714-22be-45cc-800e-fa801b4e94db 12 | cluster-name: shanghai 13 | group: easychat 14 | gateway: 15 | # httpclient: 16 | # connect-timeout: 1000 17 | # response-timeout: 5s 18 | globalcors: 19 | cors-configurations: 20 | '[/**]': 21 | allowedOrigins: "https://toollong.icu" 22 | allowedMethods: "*" 23 | routes: 24 | - id: easychat_user_route 25 | uri: lb://easychat-user-service 26 | predicates: 27 | - Path=/api/user/** 28 | filters: 29 | - RewritePath=/api/user/(?.*),/user/$\{segment} 30 | - id: easychat_auth_route 31 | uri: lb://easychat-auth-service 32 | predicates: 33 | - Path=/api/auth/** 34 | filters: 35 | - RewritePath=/api/auth/(?.*),/auth/$\{segment} 36 | - id: easychat_chat_route 37 | uri: lb://easychat-chat-service 38 | predicates: 39 | - Path=/api/chat/** 40 | - Cookie=uid,\d{19} 41 | filters: 42 | - RewritePath=/api/chat/(?.*),/chat/$\{segment} 43 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-04-30 12:53 8 | */ 9 | @Configuration 10 | public class SecurityConfig { 11 | 12 | // @Bean 13 | // public PasswordEncoder passwordEncoder() { 14 | // return new BCryptPasswordEncoder(); 15 | // } 16 | 17 | // @Bean 18 | // public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 19 | // http 20 | // .cors(Customizer.withDefaults()) 21 | // .csrf(AbstractHttpConfigurer::disable) 22 | // .sessionManagement(session -> session 23 | // .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) 24 | // .authorizeHttpRequests(authorize -> authorize 25 | // .antMatchers("/login*", "/logout*").permitAll() 26 | // .anyRequest().authenticated()) 27 | // .formLogin(login -> login 28 | // .loginProcessingUrl("/login")) 29 | // .logout(logout -> logout 30 | // .logoutUrl("/logout")) 31 | // .httpBasic(Customizer.withDefaults()); 32 | // return http.build(); 33 | // } 34 | } 35 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/mapper/FriendVerifyMapper.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.easychat.user.dto.VerifyInfo; 5 | import com.easychat.user.entity.FriendVerify; 6 | import org.apache.ibatis.annotations.Mapper; 7 | import org.apache.ibatis.annotations.Param; 8 | import org.apache.ibatis.annotations.Update; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: long 14 | * @Date: 2022-07-03 9:37 15 | */ 16 | @Mapper 17 | public interface FriendVerifyMapper extends BaseMapper { 18 | 19 | /** 20 | * 根据用户 id 查询其好友验证信息列表 21 | * 22 | * @param userId 用户 id 23 | * @return 好友验证信息列表 24 | */ 25 | List selectVerifyInfoList(@Param("userId") String userId); 26 | 27 | /** 28 | * 根据发送者 id 和接收者 id 查询好友验证信息 29 | * 30 | * @param senderId 发送者 id 31 | * @param receiverId 接收者 id 32 | * @return 好友验证信息 33 | */ 34 | VerifyInfo selectVerifyInfo(@Param("senderId") String senderId, 35 | @Param("receiverId") String receiverId); 36 | 37 | /** 38 | * 将用户接收到的所有未读好友验证更新为已读 39 | * 40 | * @param userId 用户 id 41 | * @return 更新记录数 42 | */ 43 | @Update("UPDATE easychat_friend_verify " + 44 | "SET has_read = 1 " + 45 | "WHERE receiver_id = #{userId}") 46 | int updateFriendVerify(String userId); 47 | } 48 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/mapper/ChatHistoryMapper.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.mapper; 2 | 3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 | import com.easychat.chat.dto.ChatInfo; 5 | import com.easychat.chat.entity.ChatHistory; 6 | import org.apache.ibatis.annotations.Mapper; 7 | import org.apache.ibatis.annotations.Param; 8 | import org.apache.ibatis.annotations.Update; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: long 14 | * @Date: 2022-04-20 9:46 15 | */ 16 | @Mapper 17 | public interface ChatHistoryMapper extends BaseMapper { 18 | 19 | /** 20 | * 根据用户 id 查询聊天信息列表 21 | * 22 | * @param userId 用户 id 23 | * @return 聊天信息列表 24 | */ 25 | List selectChatInfoList(@Param("userId") String userId); 26 | 27 | /** 28 | * 根据用户 id 和好友用户 id 查询聊天信息 29 | * 30 | * @param userId 用户 id 31 | * @param friendUserId 好友用户 id 32 | * @return 聊天信息 33 | */ 34 | ChatInfo selectChatInfo(@Param("userId") String userId, @Param("friendUserId") String friendUserId); 35 | 36 | /** 37 | * 将用户在会话中接收到的所有未读消息设为已读 38 | * 39 | * @param sessionId 会话 id 40 | * @param userId 用户 id 41 | * @return 更新记录数 42 | */ 43 | @Update("UPDATE easychat_history " + 44 | "SET has_read = 1 " + 45 | "WHERE session_id = #{sessionId} AND receiver_id = #{userId}") 46 | int updateChatHistory(String sessionId, String userId); 47 | } 48 | -------------------------------------------------------------------------------- /easychat-filesystem/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easychat 7 | com.easychat 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | easychat-filesystem 12 | 13 | 14 | 8 15 | 8 16 | 17 | 18 | 19 | 20 | com.easychat 21 | easychat-common 22 | 1.0-SNAPSHOT 23 | 24 | 25 | 26 | com.alibaba.cloud 27 | spring-cloud-starter-alibaba-nacos-discovery 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-web 33 | 34 | 35 | 36 | io.minio 37 | minio 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/util/CookieUtil.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.util; 2 | 3 | import javax.servlet.http.Cookie; 4 | import javax.servlet.http.HttpServletRequest; 5 | import javax.servlet.http.HttpServletResponse; 6 | 7 | /** 8 | * @Author: long 9 | * @Date: 2022-05-02 13:05 10 | */ 11 | public class CookieUtil { 12 | 13 | /** 14 | * 添加 cookie 15 | * 16 | * @param name cookie名 17 | * @param value cookie值 18 | * @param maxAge cookie生命周期(秒) 19 | */ 20 | public static void addCookie(HttpServletResponse response, String domain, String path, String name, 21 | String value, int maxAge, boolean httpOnly) { 22 | Cookie cookie = new Cookie(name, value); 23 | cookie.setDomain(domain); 24 | cookie.setPath(path); 25 | cookie.setMaxAge(maxAge); 26 | cookie.setHttpOnly(httpOnly); 27 | response.addCookie(cookie); 28 | } 29 | 30 | /** 31 | * 根据 cookie名获取 cookie值 32 | * 33 | * @param cookieName cookie名 34 | * @return cookie值 35 | */ 36 | public static String getCookieValue(HttpServletRequest request, String cookieName) { 37 | Cookie[] cookies = request.getCookies(); 38 | if (cookies != null) { 39 | for (Cookie cookie : cookies) { 40 | if (cookieName.equals(cookie.getName())) { 41 | return cookie.getValue(); 42 | } 43 | } 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/service/UserOnlineService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.service; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * @Author: long 7 | * @Date: 2022-05-03 11:06 8 | */ 9 | public interface UserOnlineService { 10 | 11 | /** 12 | * 将登录的用户与对应的 socket-client 保存到 redis (userId:clientId) 13 | * 14 | * @param userId 用户 id 15 | * @param clientId 客户端 id 16 | */ 17 | void saveUserAndClient(String userId, String clientId); 18 | 19 | /** 20 | * 根据用户 id 获取 socket-client id 21 | * 22 | * @param userId 用户 id 23 | * @return 客户端 id 24 | */ 25 | String getClientIdByUserId(String userId); 26 | 27 | /** 28 | * 从 redis 中删除用户及对应的 socket-client 29 | * 30 | * @param userId 用户 id 31 | */ 32 | void removeUserAndClient(String userId); 33 | 34 | /** 35 | * 将在线用户添加到 redis 的 set集合中 36 | * 37 | * @param userId 用户 id 38 | */ 39 | void addOnlineUser(String userId); 40 | 41 | /** 42 | * 获取在线的用户集合 43 | * 44 | * @return 用户 Set 集合 45 | */ 46 | Set getOnlineUsers(); 47 | 48 | /** 49 | * 用户下线时从在线集合中删除其信息 50 | * 51 | * @param userId 用户 id 52 | */ 53 | void removeOnlineUser(String userId); 54 | 55 | /** 56 | * 获取在线的用户数量 57 | * 58 | * @return 在线用户数 59 | */ 60 | Integer getOnlineCount(); 61 | 62 | /** 63 | * 检查用户是否在线 64 | * 65 | * @param userId 用户 id 66 | * @return 结果 67 | */ 68 | boolean checkUserIsOnline(String userId); 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easychat-server 2 | 3 | ## 介绍 4 | 5 | easychat-server 是 EasyChat 项目的后端部分,采用微服务架构,使用 Java 语言,基于 Spring Cloud 开发。 6 | 7 | EasyChat 是一个可以在线聊天的即时通讯平台,完全由个人设计和开发,初衷主要是觉得好玩儿,顺便学习一些新东西,所以网站有些简陋,属实是本人的能力和财力有限。网站没有任何付费内容,所有内容完全免费,欢迎大家使用体验,也期待大佬们的交流与反馈。 8 | 9 | 体验地址:[https://toollong.icu](https://toollong.icu)(网站已于 2023.08.18 下线,运行时长 382 天) 10 | 11 | > ### 功能介绍 12 | 13 | - 注册 14 | - 登录 15 | - 找回密码 16 | - 添加聊天 17 | - 删除聊天 18 | - 发送文本消息 19 | - 发送 Emoji 表情(Windows 7 可能无法正常显示) 20 | - 发送图片(批量发送) 21 | - 发送文件(同步发送,有点慢) 22 | - 新消息通知(有提示音) 23 | - 搜索用户 24 | - 修改好友备注 25 | - 好友申请 26 | - 好友验证 27 | - 好友删除(单向删除) 28 | - 验证消息通知(有提示音) 29 | - 查看资料 30 | - 编辑资料 31 | - 设置(头像、隐身、标签、修改密码) 32 | - 夜间模式 33 | - 小抽屉(搜一搜、日历) 34 | 35 | 36 | > ### 技术栈 37 | 38 | - 前端:Vue 3,Vue Router,Vuex,Element Plus,Socket.IO,Axios,VueUse... 39 | 40 | - 后端:Spring Cloud,Nacos,MyBatis-Plus,Netty-socketio,MinIO,Gson,MySQL,Redis,Docker... 41 | 42 | > ### 注意 43 | 44 | - 本网站仅供学习交流使用,由于网站的安全保障和加密措施并不完善,**请勿在网站中输入敏感信息**,避免信息泄露的风险。 45 | 46 | - 我的邮箱:toollong@163.com 47 | 48 | - 我的博客:[https://blog.csdn.net/weixin_49523761](https://blog.csdn.net/weixin_49523761) 49 | 50 | ## 导入 51 | 52 | - 将项目导入喜欢的 IDE 中,等待相关依赖和环境加载完成。 53 | - 在 MySQL 数据库中新建数据库并导入 sql 文件夹中的表结构。 54 | 55 | ## 运行 56 | 57 | 需要修改的配置: 58 | 59 | - 各服务的配置文件 application.yml 中的 mysql 配置、redis 配置、nacos 配置、minio 配置; 60 | - easychat-gateway 服务的配置文件 application.yml 中的 CORS 配置; 61 | - easychat-auth 服务的 AuthController 类中的两处 Cookie 作用域改为自己的域名或ip; 62 | - easychat-user 服务的 UserController 类中的 Cookie 作用域改为自己的域名或ip,还有 EmailServiceImpl 类中的邮箱设置也需要修改。 63 | 64 | 配置完成后启动运行各个服务的启动类即可。 65 | 66 | ## 打包 67 | 68 | ``` 69 | mvn clean install 70 | ``` 71 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/protocol/ResponseResult.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.protocol; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | /** 7 | * @Author: long 8 | * @Date: 2022-04-18 11:13 9 | */ 10 | @Data 11 | @NoArgsConstructor 12 | public class ResponseResult { 13 | 14 | boolean success = true; 15 | int code = 10000; 16 | String message; 17 | T data; 18 | 19 | public ResponseResult(ResultCode resultCode) { 20 | this.success = resultCode.success(); 21 | this.code = resultCode.code(); 22 | this.message = resultCode.message(); 23 | } 24 | 25 | public ResponseResult(boolean success, int code, String message) { 26 | this.success = success; 27 | this.code = code; 28 | this.message = message; 29 | } 30 | 31 | public ResponseResult(ResultCode resultCode, T data) { 32 | this.success = resultCode.success(); 33 | this.code = resultCode.code(); 34 | this.message = resultCode.message(); 35 | this.data = data; 36 | } 37 | 38 | public static ResponseResult success() { 39 | return new ResponseResult<>(CommonCode.SUCCESS); 40 | } 41 | 42 | public static ResponseResult success(T data) { 43 | return new ResponseResult<>(CommonCode.SUCCESS, data); 44 | } 45 | 46 | public static ResponseResult error(ResultCode resultCode) { 47 | return new ResponseResult<>(resultCode); 48 | } 49 | 50 | public static ResponseResult fail() { 51 | return new ResponseResult<>(CommonCode.FAIL); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/protocol/CommonCode.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.protocol; 2 | 3 | /** 4 | * @Author: long 5 | * @Date: 2022-04-18 11:24 6 | */ 7 | public enum CommonCode implements ResultCode { 8 | 9 | //================================== common ===================================== 10 | 11 | SUCCESS(true, 10000, "操作成功!"), 12 | FAIL(false, 11111, "操作失败!"), 13 | NOT_LOGIN(false, 10001, "此操作需要登录系统!"), 14 | UNAUTHORISED(false, 10002, "权限不足,无权操作!"), 15 | INVALID_PARAM(false, 10003, "非法参数!"), 16 | EMPTY_ERROR(false, 10004, "传入对象为空或缺少必要的参数!"), 17 | UNKNOWN_ERROR(false, 99999, "系统未知异常!"), 18 | 19 | //================================== user ======================================= 20 | 21 | USER_NOT_EXISTS(false, 20001, "用户不存在!"), 22 | USER_NOT_FRIEND(false, 20002, "你还不是他(她)的好友!"), 23 | 24 | //================================== upload ======================================= 25 | 26 | UPLOAD_IMAGE_FORMAT_ERROR(false, 30001, "上传图片只支持 JPG 或 PNG 格式!"), 27 | UPLOAD_IMAGE_SIZE_ERROR(false, 30002, "上传图片不能超过 2MB !"), 28 | UPLOAD_FILE_SIZE_ERROR(false, 30003, "上传文件不能超过 100MB !"); 29 | 30 | boolean success; 31 | int code; 32 | String message; 33 | 34 | CommonCode(boolean success, int code, String message) { 35 | this.success = success; 36 | this.code = code; 37 | this.message = message; 38 | } 39 | 40 | @Override 41 | public boolean success() { 42 | return success; 43 | } 44 | 45 | @Override 46 | public int code() { 47 | return code; 48 | } 49 | 50 | @Override 51 | public String message() { 52 | return message; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /easychat-auth/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easychat 7 | com.easychat 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | easychat-auth 12 | 13 | 14 | 8 15 | 8 16 | 17 | 18 | 19 | 20 | com.easychat 21 | easychat-common 22 | 1.0-SNAPSHOT 23 | 24 | 25 | 26 | com.alibaba.cloud 27 | spring-cloud-starter-alibaba-nacos-discovery 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-openfeign 33 | 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-loadbalancer 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-web 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-data-redis 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /easychat-chat/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 20040 3 | servlet: 4 | context-path: /chat 5 | 6 | spring: 7 | application: 8 | name: easychat-chat-service 9 | servlet: 10 | multipart: 11 | max-file-size: 100MB 12 | max-request-size: 100MB 13 | cloud: 14 | nacos: 15 | discovery: 16 | server-addr: localhost:8848 17 | namespace: ec0b2714-22be-45cc-800e-fa801b4e94db 18 | cluster-name: shanghai 19 | group: easychat 20 | datasource: 21 | druid: 22 | driver-class-name: com.mysql.cj.jdbc.Driver 23 | url: jdbc:mysql://localhost:3306/easychat?characterEncoding=utf-8 24 | username: root 25 | password: 123456 26 | initial-size: 5 27 | min-idle: 5 28 | max-active: 20 29 | max-wait: 10000 30 | test-while-idle: true 31 | test-on-borrow: false 32 | test-on-return: false 33 | validation-query: select 1 34 | time-between-eviction-runs-millis: 60000 35 | min-evictable-idle-time-millis: 300000 36 | redis: 37 | host: localhost 38 | port: 6379 39 | password: 123456 40 | connect-timeout: 5000 41 | 42 | mybatis-plus: 43 | configuration: 44 | local-cache-scope: statement # 一级缓存 45 | cache-enabled: false # 二级缓存 46 | map-underscore-to-camel-case: true 47 | global-config: 48 | db-config: 49 | id-type: assign_id 50 | mapper-locations: classpath:/mapper/*.xml 51 | 52 | # SocketIO配置 53 | socketio: 54 | # SocketIO端口 55 | port: 9092 56 | # 连接数大小 57 | workCount: 100 58 | # 允许客户请求 59 | allowCustomRequests: true 60 | # 协议升级超时时间(毫秒),默认10秒,HTTP握手升级为ws协议超时时间 61 | upgradeTimeout: 10000 62 | # Ping消息超时时间(毫秒),默认60秒,这个时间间隔内没有接收到心跳消息就会发送超时事件 63 | pingTimeout: 60000 64 | # Ping消息间隔(毫秒),默认25秒。客户端向服务器发送一条心跳消息间隔 65 | pingInterval: 25000 66 | # 设置HTTP交互最大内容长度 67 | maxHttpContentLength: 1048576 68 | # 设置最大每帧处理数据的长度,防止他人利用大数据来攻击服务器 69 | maxFramePayloadLength: 1048576 70 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/config/SocketIOConfig.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.config; 2 | 3 | import com.corundumstudio.socketio.SocketConfig; 4 | import com.corundumstudio.socketio.SocketIOServer; 5 | import com.corundumstudio.socketio.Transport; 6 | import com.corundumstudio.socketio.annotation.SpringAnnotationScanner; 7 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import javax.annotation.Resource; 12 | 13 | /** 14 | * @Author: long 15 | * @Date: 2022-05-05 9:57 16 | */ 17 | @EnableConfigurationProperties(SocketIOProperties.class) 18 | @Configuration 19 | public class SocketIOConfig { 20 | 21 | @Resource 22 | SocketIOProperties properties; 23 | 24 | @Bean 25 | public SocketIOServer socketIOServer() { 26 | com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration(); 27 | config.setPort(properties.getPort()); 28 | SocketConfig socketConfig = new SocketConfig(); 29 | socketConfig.setReuseAddress(true); 30 | config.setSocketConfig(socketConfig); 31 | config.setAllowCustomRequests(properties.getAllowCustomRequests()); 32 | config.setUpgradeTimeout(properties.getUpgradeTimeout()); 33 | config.setPingTimeout(properties.getPingTimeout()); 34 | config.setPingInterval(properties.getPingInterval()); 35 | config.setMaxHttpContentLength(properties.getMaxHttpContentLength()); 36 | config.setMaxFramePayloadLength(properties.getMaxFramePayloadLength()); 37 | config.setTransports(Transport.WEBSOCKET); 38 | return new SocketIOServer(config); 39 | } 40 | 41 | /** 42 | * 开启 SocketIOServer 注解支持 43 | */ 44 | @Bean 45 | public SpringAnnotationScanner springAnnotationScanner() { 46 | return new SpringAnnotationScanner(this.socketIOServer()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /easychat-chat/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 14 | utf8 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ${LOG_HOME}/${SERVICE_NAME}_%d{yyyy-MM-dd}.log 23 | 24 | 25 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 34 | 512 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /easychat-user/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 14 | utf8 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ${LOG_HOME}/${SERVICE_NAME}_%d{yyyy-MM-dd}.log 23 | 24 | 25 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 34 | 512 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /easychat-filesystem/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 14 | utf8 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ${LOG_HOME}/${SERVICE_NAME}_%d{yyyy-MM-dd}.log 23 | 24 | 25 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 34 | 512 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/feign/UserFeignService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.feign; 2 | 3 | import com.easychat.chat.dto.FriendInfo; 4 | import com.easychat.chat.dto.VerifyInfo; 5 | import com.easychat.chat.vo.*; 6 | import com.easychat.common.protocol.ResponseResult; 7 | import org.springframework.cloud.openfeign.FeignClient; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | 13 | /** 14 | * @Author: long 15 | * @Date: 2022-05-02 10:53 16 | */ 17 | @FeignClient("easychat-user-service") 18 | public interface UserFeignService { 19 | 20 | @PostMapping("/user/user/changeStatus") 21 | ResponseResult changeStatus(@RequestBody ChangeStatusRequest request); 22 | 23 | @GetMapping("/user/friends/friend") 24 | ResponseResult getFriendInfo(@RequestParam("id") String userId, 25 | @RequestParam("friendId") String friendUserId); 26 | 27 | @PostMapping("/user/friends/add") 28 | ResponseResult addFriend(@RequestBody AddFriendRequest request); 29 | 30 | @PostMapping("/user/friends/edit") 31 | ResponseResult editFriend(@RequestBody EditFriendRequest request); 32 | 33 | @PostMapping("/user/friends/remove") 34 | ResponseResult removeFriend(@RequestBody RemoveFriendRequest request); 35 | 36 | @GetMapping("/user/friendVerify/info") 37 | ResponseResult getFriendVerify(@RequestParam("senderId") String senderId, 38 | @RequestParam("receiverId") String receiverId); 39 | 40 | @PostMapping("/user/friendVerify/add") 41 | ResponseResult addFriendVerify(@RequestBody AddFriendVerifyRequest request); 42 | 43 | @PostMapping("/user/friendVerify/edit") 44 | ResponseResult editFriendVerify(@RequestBody EditFriendVerifyRequest request); 45 | 46 | @PostMapping("/user/friendVerify/read") 47 | ResponseResult readFriendVerify(@RequestBody String userId); 48 | } 49 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/exception/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.exception; 2 | 3 | import com.easychat.common.protocol.CommonCode; 4 | import com.easychat.common.protocol.ResponseResult; 5 | import com.easychat.common.protocol.ResultCode; 6 | import com.google.common.collect.ImmutableMap; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.converter.HttpMessageNotReadableException; 11 | import org.springframework.web.bind.annotation.ExceptionHandler; 12 | import org.springframework.web.bind.annotation.ResponseStatus; 13 | import org.springframework.web.bind.annotation.RestControllerAdvice; 14 | 15 | /** 16 | * @Author: long 17 | * @Date: 2022-04-19 10:33 18 | */ 19 | @RestControllerAdvice 20 | public class GlobalExceptionHandler { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class); 23 | 24 | private static ImmutableMap, ResultCode> EXCEPTIONS; 25 | protected static ImmutableMap.Builder, ResultCode> builder = ImmutableMap.builder(); 26 | 27 | @ExceptionHandler(Exception.class) 28 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 29 | public ResponseResult exceptionHandle(Exception e) { 30 | LOGGER.error("catch exception : {}\r\nexception: ", e.getMessage(), e); 31 | if (e instanceof CustomException) { 32 | CustomException customException = (CustomException) e; 33 | ResultCode resultCode = customException.getResultCode(); 34 | return ResponseResult.error(resultCode); 35 | } 36 | if (EXCEPTIONS == null) { 37 | EXCEPTIONS = builder.build(); 38 | } 39 | final ResultCode resultCode = EXCEPTIONS.get(e.getClass()); 40 | if (resultCode != null) { 41 | return ResponseResult.error(resultCode); 42 | } 43 | return ResponseResult.error(CommonCode.UNKNOWN_ERROR); 44 | } 45 | 46 | static { 47 | builder.put(HttpMessageNotReadableException.class, CommonCode.INVALID_PARAM); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/service/impl/UserOnlineServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.service.impl; 2 | 3 | import com.easychat.chat.service.UserOnlineService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.data.redis.core.StringRedisTemplate; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.Set; 9 | import java.util.concurrent.TimeUnit; 10 | 11 | /** 12 | * @Author: long 13 | * @Date: 2022-05-03 11:06 14 | */ 15 | @Service 16 | public class UserOnlineServiceImpl implements UserOnlineService { 17 | 18 | @Autowired 19 | StringRedisTemplate redisTemplate; 20 | 21 | @Override 22 | public void saveUserAndClient(String userId, String clientId) { 23 | String key = "user:" + userId; 24 | redisTemplate.opsForValue().set(key, clientId, 60 * 60 * 24, TimeUnit.SECONDS); 25 | } 26 | 27 | @Override 28 | public String getClientIdByUserId(String userId) { 29 | String key = "user:" + userId; 30 | return redisTemplate.opsForValue().get(key); 31 | } 32 | 33 | @Override 34 | public void removeUserAndClient(String userId) { 35 | String key = "user:" + userId; 36 | redisTemplate.delete(key); 37 | } 38 | 39 | @Override 40 | public void addOnlineUser(String userId) { 41 | String key = "online:userSet"; 42 | redisTemplate.opsForSet().remove(key, userId); 43 | redisTemplate.opsForSet().add(key, userId); 44 | } 45 | 46 | @Override 47 | public Set getOnlineUsers() { 48 | return redisTemplate.opsForSet().members("online:userSet"); 49 | } 50 | 51 | @Override 52 | public void removeOnlineUser(String userId) { 53 | redisTemplate.opsForSet().remove("online:userSet", userId); 54 | } 55 | 56 | @Override 57 | public Integer getOnlineCount() { 58 | Set members = redisTemplate.opsForSet().members("online:userSet"); 59 | return members == null ? 0 : members.size(); 60 | } 61 | 62 | @Override 63 | public boolean checkUserIsOnline(String userId) { 64 | Boolean result = redisTemplate.opsForSet().isMember("online:userSet", userId); 65 | return result != null && result; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /easychat-user/src/main/resources/mapper/FriendMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 36 | 37 | 54 | 55 | -------------------------------------------------------------------------------- /easychat-user/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easychat 7 | com.easychat 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | easychat-user 12 | 13 | 14 | 8 15 | 8 16 | 17 | 18 | 19 | 20 | com.easychat 21 | easychat-common 22 | 1.0-SNAPSHOT 23 | 24 | 25 | 26 | com.alibaba.cloud 27 | spring-cloud-starter-alibaba-nacos-discovery 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-openfeign 33 | 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-loadbalancer 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-web 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-data-redis 48 | 49 | 50 | 51 | mysql 52 | mysql-connector-java 53 | 54 | 55 | 56 | com.alibaba 57 | druid-spring-boot-starter 58 | 59 | 60 | 61 | com.baomidou 62 | mybatis-plus-boot-starter 63 | 64 | 65 | 66 | org.apache.commons 67 | commons-email 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/util/JwtUtil.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.util; 2 | 3 | import io.jsonwebtoken.Claims; 4 | import io.jsonwebtoken.JwtException; 5 | import io.jsonwebtoken.Jwts; 6 | import io.jsonwebtoken.security.Keys; 7 | 8 | import javax.crypto.SecretKey; 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.Date; 11 | import java.util.Map; 12 | 13 | /** 14 | * @Author: long 15 | * @Date: 2022-05-01 12:09 16 | */ 17 | public class JwtUtil { 18 | 19 | private static final String KEY = MD5Util.getStringMD5("easypay"); 20 | 21 | public static String createJwt(Map claims, long expireTime) { 22 | return Jwts.builder() 23 | .setClaims(claims) 24 | .setIssuedAt(new Date()) 25 | .setExpiration(new Date(System.currentTimeMillis() + expireTime)) 26 | .signWith(getSecretKey()) 27 | .compact(); 28 | } 29 | 30 | public static boolean verifyJwt(String jwt) { 31 | try { 32 | Jwts.parserBuilder() 33 | .setAllowedClockSkewSeconds(60) 34 | .setSigningKey(getSecretKey()) 35 | .build() 36 | .parseClaimsJws(jwt); 37 | } catch (JwtException e) { 38 | return false; 39 | } 40 | return true; 41 | } 42 | 43 | public static Map parseJwt(String jwt) { 44 | Claims claims = Jwts.parserBuilder() 45 | .setAllowedClockSkewSeconds(60) 46 | .setSigningKey(getSecretKey()) 47 | .build() 48 | .parseClaimsJws(jwt) 49 | .getBody(); 50 | claims.remove("iat"); 51 | claims.remove("exp"); 52 | return claims; 53 | } 54 | 55 | private static SecretKey getSecretKey() { 56 | return Keys.hmacShaKeyFor(KEY.getBytes(StandardCharsets.UTF_8)); 57 | } 58 | 59 | // public static void main(String[] args) { 60 | // Map map = new HashMap<>(); 61 | // map.put("张三", "123456"); 62 | // map.put("李四", "456789"); 63 | // String jwt = createJwt(map, 60 * 1000); 64 | // System.out.println(jwt); 65 | // String jwt = "eyJhbGciOiJIUzI1NiJ9.eyLmnY7lm5siOiI0NTY3ODkiLCLlvKDkuIkiOiIxMjM0NTYiLCJpYXQiOjE2NTY3NTAxOTMsImV4cCI6MTY1Njc1MDI1M30._ue7gE7moWa2SDIeq3Wr_FIAzFpKruPIvm7JMtcI95c"; 66 | // boolean result = verifyJwt(jwt); 67 | // if (result) { 68 | // System.out.println(parseJwt(jwt).toString()); 69 | // } 70 | // } 71 | } 72 | -------------------------------------------------------------------------------- /easychat-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easychat 7 | com.easychat 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | easychat-common 12 | 13 | 14 | 8 15 | 8 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | 25 | io.netty 26 | netty-all 27 | 28 | 29 | 30 | org.projectlombok 31 | lombok 32 | 33 | 34 | 35 | com.google.guava 36 | guava 37 | 38 | 39 | 40 | com.google.code.gson 41 | gson 42 | 43 | 44 | 45 | org.apache.commons 46 | commons-lang3 47 | 48 | 49 | 50 | io.jsonwebtoken 51 | jjwt-api 52 | 0.11.5 53 | 54 | 55 | 56 | io.jsonwebtoken 57 | jjwt-impl 58 | 0.11.5 59 | runtime 60 | 61 | 62 | 63 | io.jsonwebtoken 64 | jjwt-gson 65 | 0.11.5 66 | runtime 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-maven-plugin 75 | 76 | true 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /easychat-chat/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | easychat 7 | com.easychat 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | easychat-chat 12 | 13 | 14 | 8 15 | 8 16 | 17 | 18 | 19 | 20 | com.easychat 21 | easychat-common 22 | 1.0-SNAPSHOT 23 | 24 | 25 | 26 | com.alibaba.cloud 27 | spring-cloud-starter-alibaba-nacos-discovery 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-openfeign 33 | 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-loadbalancer 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-web 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-data-redis 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-configuration-processor 53 | true 54 | 55 | 56 | 57 | com.corundumstudio.socketio 58 | netty-socketio 59 | 60 | 61 | 62 | mysql 63 | mysql-connector-java 64 | 65 | 66 | 67 | com.alibaba 68 | druid-spring-boot-starter 69 | 70 | 71 | 72 | com.baomidou 73 | mybatis-plus-boot-starter 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/controller/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.controller; 2 | 3 | import com.easychat.auth.dto.UserJwt; 4 | import com.easychat.auth.service.AuthService; 5 | import com.easychat.auth.vo.LoginRequest; 6 | import com.easychat.common.protocol.ResponseResult; 7 | import com.easychat.common.util.CookieUtil; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | 18 | /** 19 | * 前端访问首页时,判断浏览器是否有 cookie uid(用户 id), 20 | * 如果没有,则跳转到登录页,登录成功后把用户信息存储到 redis,并将用户 id 放到 cookie uid 中,然后跳转到首页; 21 | * 22 | * @Author: long 23 | * @Date: 2022-05-01 16:33 24 | */ 25 | @RestController 26 | public class AuthController { 27 | 28 | @Autowired 29 | AuthService authService; 30 | 31 | @PostMapping("/login") 32 | public ResponseResult login(@RequestBody LoginRequest loginRequest, 33 | HttpServletResponse response) { 34 | UserJwt userJwt = authService.loginAuth(loginRequest); 35 | if (userJwt != null) { 36 | int maxAge = -1; 37 | if (loginRequest.getLoginFree()) { 38 | maxAge = 7 * 24 * 60 * 60; 39 | } 40 | CookieUtil.addCookie(response, "toollong.icu", "/", 41 | "uid", userJwt.getId(), maxAge, false); 42 | return ResponseResult.success(); 43 | } 44 | return ResponseResult.fail(); 45 | } 46 | 47 | @GetMapping("/userJwt") 48 | public ResponseResult getUserJwt(HttpServletRequest request) { 49 | String userId = CookieUtil.getCookieValue(request, "uid"); 50 | UserJwt userJwt = authService.getUserJwt(userId); 51 | if (userJwt != null) { 52 | return ResponseResult.success(userJwt); 53 | } 54 | return ResponseResult.fail(); 55 | } 56 | 57 | @PostMapping("/logout") 58 | public ResponseResult logout(HttpServletRequest request, HttpServletResponse response) { 59 | String userId = CookieUtil.getCookieValue(request, "uid"); 60 | if (StringUtils.isNotBlank(userId)) { 61 | boolean result = authService.deleteJwt(userId); 62 | if (result) { 63 | CookieUtil.addCookie(response, "toollong.icu", "/", 64 | "uid", userId, 0, false); 65 | return ResponseResult.success(); 66 | } 67 | } 68 | return ResponseResult.fail(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/controller/FriendController.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.controller; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import com.easychat.user.dto.FriendInfo; 5 | import com.easychat.user.dto.VerifyInfo; 6 | import com.easychat.user.service.FriendService; 7 | import com.easychat.user.vo.*; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * @Author: long 15 | * @Date: 2022-05-03 10:43 16 | */ 17 | @RestController 18 | public class FriendController { 19 | 20 | @Autowired 21 | FriendService friendService; 22 | 23 | @GetMapping("/friends") 24 | public ResponseResult> getUserFriends(@RequestParam("id") String userId) { 25 | return friendService.queryUserFriends(userId); 26 | } 27 | 28 | @GetMapping("/friends/friend") 29 | public ResponseResult getFriendInfo(@RequestParam("id") String userId, 30 | @RequestParam("friendId") String friendUserId) { 31 | return friendService.queryFriendInfo(userId, friendUserId); 32 | } 33 | 34 | @PostMapping("/friends/add") 35 | public ResponseResult addFriend(@RequestBody AddFriendRequest request) { 36 | return friendService.createFriend(request); 37 | } 38 | 39 | @PostMapping("/friends/edit") 40 | public ResponseResult editFriend(@RequestBody EditFriendRequest request) { 41 | return friendService.updateFriend(request); 42 | } 43 | 44 | @PostMapping("/friends/remove") 45 | public ResponseResult removeFriend(@RequestBody RemoveFriendRequest request) { 46 | return friendService.deleteFriend(request); 47 | } 48 | 49 | @GetMapping("/friendVerify") 50 | public ResponseResult> getFriendVerifyList(@RequestParam("id") String userId) { 51 | return friendService.queryFriendVerifyList(userId); 52 | } 53 | 54 | @GetMapping("/friendVerify/info") 55 | public ResponseResult getFriendVerify(@RequestParam("senderId") String senderId, 56 | @RequestParam("receiverId") String receiverId) { 57 | return friendService.queryFriendVerify(senderId, receiverId); 58 | } 59 | 60 | @PostMapping("/friendVerify/add") 61 | public ResponseResult addFriendVerify(@RequestBody AddFriendVerifyRequest request) { 62 | return friendService.createFriendVerify(request); 63 | } 64 | 65 | @PostMapping("/friendVerify/edit") 66 | public ResponseResult editFriendVerify(@RequestBody EditFriendVerifyRequest request) { 67 | return friendService.updateFriendVerify(request); 68 | } 69 | 70 | @PostMapping("/friendVerify/read") 71 | public ResponseResult readFriendVerify(@RequestBody String userId) { 72 | return friendService.updateFriendVerify(userId); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /easychat-user/src/main/resources/mapper/FriendVerifyMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 41 | 42 | 62 | 63 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/service/FriendService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.service; 2 | 3 | import com.easychat.common.exception.CustomException; 4 | import com.easychat.common.protocol.ResponseResult; 5 | import com.easychat.user.dto.FriendInfo; 6 | import com.easychat.user.dto.VerifyInfo; 7 | import com.easychat.user.vo.*; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @Author: long 13 | * @Date: 2022-05-03 10:44 14 | */ 15 | public interface FriendService { 16 | 17 | /** 18 | * 查询用户好友列表 19 | * 20 | * @param userId 用户 id 21 | * @return 好友信息列表 22 | * @throws CustomException 23 | */ 24 | ResponseResult> queryUserFriends(String userId) throws CustomException; 25 | 26 | /** 27 | * 查询用户好友信息 28 | * 29 | * @param userId 用户 id 30 | * @param friendUserId 好友用户 id 31 | * @return 好友信息 32 | * @throws CustomException 33 | */ 34 | ResponseResult queryFriendInfo(String userId, String friendUserId) throws CustomException; 35 | 36 | /** 37 | * 创建好友信息 38 | * 39 | * @param request 请求信息 40 | * @return 响应结果 41 | * @throws CustomException 42 | */ 43 | ResponseResult createFriend(AddFriendRequest request) throws CustomException; 44 | 45 | /** 46 | * 更新好友信息 47 | * 48 | * @param request 请求信息 49 | * @return 响应结果 50 | * @throws CustomException 51 | */ 52 | ResponseResult updateFriend(EditFriendRequest request) throws CustomException; 53 | 54 | /** 55 | * 删除好友信息 56 | * 57 | * @param request 请求信息 58 | * @return 响应结果 59 | * @throws CustomException 60 | */ 61 | ResponseResult deleteFriend(RemoveFriendRequest request) throws CustomException; 62 | 63 | /** 64 | * 查询好友验证信息列表 65 | * 66 | * @param userId 用户 id 67 | * @return 好友验证信息列表 68 | * @throws CustomException 69 | */ 70 | ResponseResult> queryFriendVerifyList(String userId) throws CustomException; 71 | 72 | /** 73 | * 查询好友验证信息 74 | * 75 | * @param senderId 发送者 id 76 | * @param receiverId 接收者 id 77 | * @return 好友验证信息 78 | * @throws CustomException 79 | */ 80 | ResponseResult queryFriendVerify(String senderId, String receiverId) throws CustomException; 81 | 82 | /** 83 | * 创建好友验证信息 84 | * 85 | * @param request 请求信息 86 | * @return 响应结果 87 | * @throws CustomException 88 | */ 89 | ResponseResult createFriendVerify(AddFriendVerifyRequest request) throws CustomException; 90 | 91 | /** 92 | * 更新好友验证信息 93 | * 94 | * @param request 请求信息 95 | * @return 备注 96 | * @throws CustomException 97 | */ 98 | ResponseResult updateFriendVerify(EditFriendVerifyRequest request) throws CustomException; 99 | 100 | /** 101 | * 将用户接收到的所有未读好友验证更新为已读 102 | * 103 | * @param userId 用户 id 104 | * @return 响应结果 105 | * @throws CustomException 106 | */ 107 | ResponseResult updateFriendVerify(String userId) throws CustomException; 108 | } 109 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/service/ChatService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.service; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.easychat.chat.dto.ChatInfo; 5 | import com.easychat.chat.entity.ChatHistory; 6 | import com.easychat.common.exception.CustomException; 7 | import com.easychat.common.protocol.ResponseResult; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: long 14 | * @Date: 2022-04-20 17:20 15 | */ 16 | public interface ChatService { 17 | 18 | /** 19 | * 查询聊天列表(包含最新聊天记录) 20 | * 21 | * @param userId 用户 id 22 | * @return 聊天列表 23 | * @throws CustomException 24 | */ 25 | ResponseResult> queryChatList(String userId) throws CustomException; 26 | 27 | /** 28 | * 查询聊天信息(包含最新聊天记录) 29 | * 30 | * @param userId 用户 id 31 | * @param friendUserId 好友用户 id 32 | * @return 聊天信息 33 | * @throws CustomException 34 | */ 35 | ResponseResult queryChatInfo(String userId, String friendUserId) throws CustomException; 36 | 37 | /** 38 | * 添加会话到好友信息 39 | * 40 | * @param userId 用户 id 41 | * @param friendUserId 好友用户 id 42 | * @param sessionTime 会话时间 43 | * @return 响应结果 44 | * @throws CustomException 45 | */ 46 | ResponseResult addFriendSession( 47 | String userId, String friendUserId, String sessionTime) throws CustomException; 48 | 49 | /** 50 | * 在好友信息中删除会话信息 51 | * 52 | * @param userId 用户 id 53 | * @param friendUserId 好友用户 id 54 | * @return 响应结果 55 | * @throws CustomException 56 | */ 57 | ResponseResult removeFriendSession(String userId, String friendUserId) throws CustomException; 58 | 59 | /** 60 | * 修改好友备注 61 | * 62 | * @param userId 用户 id 63 | * @param friendUserId 好友用户 id 64 | * @param remark 好友备注 65 | * @return 响应结果 66 | * @throws CustomException 67 | */ 68 | ResponseResult updateFriendRemark( 69 | String userId, String friendUserId, String remark) throws CustomException; 70 | 71 | /** 72 | * 分页查询聊天记录 73 | * 74 | * @param userId 用户 id 75 | * @param sessionId 会话 id 76 | * @param page 页码(默认为 1) 77 | * @param size 每页记录数(默认为 15) 78 | * @return 聊天记录 79 | * @throws CustomException 80 | */ 81 | ResponseResult> queryChatHistoryByPage( 82 | String userId, String sessionId, int page, int size) throws CustomException; 83 | 84 | /** 85 | * 新增一条聊天记录 86 | * 87 | * @param chatHistory 聊天记录 88 | * @param files 文件列表(发送非文字消息时使用) 89 | * @return 新增的聊天记录列表 90 | * @throws CustomException 91 | */ 92 | ResponseResult> createChatHistory( 93 | ChatHistory chatHistory, MultipartFile[] files) throws CustomException; 94 | 95 | /** 96 | * 用户读取会话中接收到的所有未读消息 97 | * 98 | * @param sessionId 会话 id 99 | * @param userId 用户 id 100 | * @return 响应结果 101 | * @throws CustomException 102 | */ 103 | ResponseResult readChatHistory(String sessionId, String userId) throws CustomException; 104 | } 105 | -------------------------------------------------------------------------------- /easychat-filesystem/src/main/java/com/easychat/filesystem/service/impl/FileServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.filesystem.service.impl; 2 | 3 | import com.easychat.common.exception.CustomException; 4 | import com.easychat.common.protocol.CommonCode; 5 | import com.easychat.common.protocol.ResponseResult; 6 | import com.easychat.filesystem.service.FileService; 7 | import io.minio.*; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.multipart.MultipartFile; 13 | 14 | import java.io.InputStream; 15 | 16 | /** 17 | * @Author: long 18 | * @Date: 2022-04-30 10:18 19 | */ 20 | @Service 21 | @Slf4j 22 | public class FileServiceImpl implements FileService { 23 | 24 | @Value("${minio.endpoint}") 25 | private String endpoint; 26 | @Value("${minio.accessKey}") 27 | private String accessKey; 28 | @Value("${minio.secretKey}") 29 | private String secretKey; 30 | @Value("${minio.bucketName}") 31 | private String bucketName; 32 | 33 | @Override 34 | public ResponseResult uploadFile(MultipartFile file, String filePath) throws CustomException { 35 | if (file.isEmpty() || StringUtils.isBlank(filePath)) { 36 | throw new CustomException(CommonCode.EMPTY_ERROR); 37 | } 38 | try (InputStream inputStream = file.getInputStream()) { 39 | MinioClient minioClient = 40 | MinioClient.builder() 41 | .endpoint(endpoint) 42 | .credentials(accessKey, secretKey) 43 | .build(); 44 | boolean isExist = minioClient 45 | .bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); 46 | if (!isExist) { 47 | minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); 48 | } 49 | minioClient.putObject( 50 | PutObjectArgs.builder() 51 | .bucket(bucketName) 52 | .object(filePath) 53 | .stream(inputStream, inputStream.available(), -1) 54 | .build()); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | return ResponseResult.fail(); 58 | } 59 | return ResponseResult.success(); 60 | } 61 | 62 | @Override 63 | public ResponseResult checkFile(String filePath) throws CustomException { 64 | if (StringUtils.isBlank(filePath)) { 65 | throw new CustomException(CommonCode.EMPTY_ERROR); 66 | } 67 | try { 68 | MinioClient minioClient = 69 | MinioClient.builder() 70 | .endpoint(endpoint) 71 | .credentials(accessKey, secretKey) 72 | .build(); 73 | try { 74 | minioClient.statObject( 75 | StatObjectArgs.builder().bucket(bucketName).object(filePath).build()); 76 | } catch (Exception e) { 77 | return ResponseResult.fail(); 78 | } 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | return ResponseResult.success(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/service/impl/EmailServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.service.impl; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import com.easychat.user.service.EmailService; 5 | import com.easychat.user.vo.SendCodeRequest; 6 | import com.easychat.user.vo.ValidateCodeRequest; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.apache.commons.mail.HtmlEmail; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.data.redis.core.StringRedisTemplate; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.Random; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * @Author: long 18 | * @Date: 2022-06-30 18:09 19 | */ 20 | @Service 21 | public class EmailServiceImpl implements EmailService { 22 | 23 | @Autowired 24 | StringRedisTemplate redisTemplate; 25 | 26 | @Override 27 | public ResponseResult sendCodeToEmail(SendCodeRequest request) { 28 | if (request == null 29 | || StringUtils.isBlank(request.getEmail()) 30 | || request.getType() == null) { 31 | return ResponseResult.fail(); 32 | } 33 | try { 34 | HtmlEmail mail = new HtmlEmail(); 35 | /*发送邮件的服务器 126邮箱为smtp.126.com,163邮箱为smtp.163.com,QQ为smtp.qq.com*/ 36 | mail.setHostName("smtp.163.com"); 37 | /*不设置发送的消息有可能是乱码*/ 38 | mail.setCharset("UTF-8"); 39 | /*IMAP/SMTP服务的密码*/ 40 | mail.setAuthentication("******", "******"); 41 | /*发送邮件的邮箱和发件人*/ 42 | mail.setFrom("******", "EasyChat"); 43 | /*使用安全链接*/ 44 | mail.setSSLOnConnect(true); 45 | /*接收的邮箱*/ 46 | mail.addTo(request.getEmail()); 47 | /*验证码*/ 48 | String code = this.generateVerifyCode(6); 49 | if (request.getType() == 0) { 50 | /*设置邮件的主题*/ 51 | mail.setSubject("EasyChat | 注册验证码"); 52 | /*设置邮件的内容*/ 53 | mail.setMsg("您好,欢迎使用EasyChat,验证码为:" + code + 54 | ",该验证码5分钟内有效,请及时输入。如非本人操作,请忽略。"); 55 | } 56 | if (request.getType() == 1) { 57 | /*设置邮件的主题*/ 58 | mail.setSubject("EasyChat | 找回密码"); 59 | /*设置邮件的内容*/ 60 | mail.setMsg("尊敬的用户,您好!您正在进行找回密码操作,验证码为:" + code + 61 | ",打死也不要告诉别人哦。如非本人操作,请检查账号安全。"); 62 | } 63 | mail.send();//发送 64 | redisTemplate.opsForValue() 65 | .set("verifyCode:" + request.getEmail(), code, 5, TimeUnit.MINUTES); 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | return ResponseResult.fail(); 69 | } 70 | return ResponseResult.success(); 71 | } 72 | 73 | @Override 74 | public ResponseResult validateEmailAndCode(ValidateCodeRequest request) { 75 | if (request == null 76 | || StringUtils.isBlank(request.getEmail()) 77 | || StringUtils.isBlank(request.getVerifyCode())) { 78 | return ResponseResult.fail(); 79 | } 80 | String code = redisTemplate.opsForValue().get("verifyCode:" + request.getEmail()); 81 | if (request.getVerifyCode().equals(code)) { 82 | return ResponseResult.success(); 83 | } 84 | return ResponseResult.fail(); 85 | } 86 | 87 | private String generateVerifyCode(int number) { 88 | Random random = new Random(); 89 | StringBuilder builder = new StringBuilder(); 90 | for (int i = 1; i <= number; i++) { 91 | builder.append(random.nextInt(10)); 92 | } 93 | return builder.toString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.service; 2 | 3 | import com.easychat.common.exception.CustomException; 4 | import com.easychat.common.protocol.ResponseResult; 5 | import com.easychat.user.dto.UserInfo; 6 | import com.easychat.user.dto.ValidationInfo; 7 | import com.easychat.user.vo.*; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: long 14 | * @Date: 2022-04-18 11:08 15 | */ 16 | public interface UserService { 17 | 18 | /** 19 | * 验证用户名是否存在,若存在则返回用户 id 和邮箱 20 | * 21 | * @param request 验证请求 22 | * @return 响应结果 23 | * @throws CustomException 24 | */ 25 | ResponseResult validateUserUsername( 26 | ValidateUsernameRequest request) throws CustomException; 27 | 28 | /** 29 | * 根据用户 id 验证其密码是否正确 30 | * 31 | * @param request 验证请求 32 | * @return 响应结果 33 | * @throws CustomException 34 | */ 35 | ResponseResult validateUserPassword(ValidatePasswordRequest request) throws CustomException; 36 | 37 | /** 38 | * 注册用户 39 | * 40 | * @param request 请求信息 41 | * @return 响应结果 42 | * @throws CustomException 43 | */ 44 | ResponseResult registerUser(RegisterRequest request) throws CustomException; 45 | 46 | /** 47 | * 根据用户名模糊查询用户列表 48 | * 49 | * @param username 用户名 50 | * @return 用户信息列表 51 | * @throws CustomException 52 | */ 53 | ResponseResult> queryUserList(String username) throws CustomException; 54 | 55 | /** 56 | * 根据用户 id 查询用户信息 57 | * 58 | * @param userId 用户 id 59 | * @return 用户信息 60 | * @throws CustomException 61 | */ 62 | ResponseResult queryUserInfo(String userId) throws CustomException; 63 | 64 | /** 65 | * 根据用户名和密码查询用户信息 66 | * 67 | * @param username 用户名 68 | * @param password 密码 69 | * @return 用户信息 70 | * @throws CustomException 71 | */ 72 | ResponseResult queryUserInfo(String username, String password) throws CustomException; 73 | 74 | /** 75 | * 更新用户信息 76 | * 77 | * @param request 请求信息 78 | * @return 更新后的用户信息 79 | * @throws CustomException 80 | */ 81 | ResponseResult updateUserInfo(EditUserInfoRequest request) throws CustomException; 82 | 83 | /** 84 | * 更新用户头像 85 | * 86 | * @param userId 用户 id 87 | * @param image 头像图片 88 | * @return 图片路径 89 | * @throws CustomException 90 | */ 91 | ResponseResult updateAvatar(String userId, MultipartFile image) throws CustomException; 92 | 93 | /** 94 | * 更新用户状态 95 | * 96 | * @param request 请求信息 97 | * @return 响应结果 98 | * @throws CustomException 99 | */ 100 | ResponseResult updateStatus(ChangeStatusRequest request) throws CustomException; 101 | 102 | /** 103 | * 修改用户密码 104 | * 105 | * @param request 请求信息 106 | * @return 响应结果 107 | * @throws CustomException 108 | */ 109 | ResponseResult updatePassword(ChangePasswordRequest request) throws CustomException; 110 | 111 | /** 112 | * 用户添加标签 113 | * 114 | * @param request 请求信息 115 | * @return 响应结果 116 | * @throws CustomException 117 | */ 118 | ResponseResult updateTagsAdd(UpdateTagsRequest request) throws CustomException; 119 | 120 | /** 121 | * 用户删除标签 122 | * 123 | * @param request 请求信息 124 | * @return 响应结果 125 | * @throws CustomException 126 | */ 127 | ResponseResult updateTagsRemove(UpdateTagsRequest request) throws CustomException; 128 | } 129 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/controller/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.controller; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.easychat.chat.dto.ChatInfo; 5 | import com.easychat.chat.entity.ChatHistory; 6 | import com.easychat.chat.service.ChatService; 7 | import com.easychat.common.exception.CustomException; 8 | import com.easychat.common.protocol.ResponseResult; 9 | import com.easychat.common.protocol.ResultCode; 10 | import com.google.gson.Gson; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.RequestParam; 16 | import org.springframework.web.bind.annotation.RestController; 17 | import org.springframework.web.multipart.MultipartFile; 18 | 19 | import java.util.List; 20 | 21 | /** 22 | * @Author: long 23 | * @Date: 2022-04-19 13:18 24 | */ 25 | @RestController 26 | public class ChatController { 27 | 28 | @Autowired 29 | ChatService chatService; 30 | 31 | @GetMapping("/chats") 32 | public ResponseResult> getChatList(@RequestParam("id") String userId) { 33 | return chatService.queryChatList(userId); 34 | } 35 | 36 | @GetMapping("/chats/chatHistory") 37 | public ResponseResult> getChatHistories(@RequestParam("id") String userId, 38 | @RequestParam("session") String sessionId, 39 | @RequestParam("page") Integer page, 40 | @RequestParam("size") Integer size) { 41 | page = page == null ? 0 : page; 42 | size = size == null ? 0 : size; 43 | return chatService.queryChatHistoryByPage(userId, sessionId, page, size); 44 | } 45 | 46 | @PostMapping("/chats/savePictureMsg") 47 | public ResponseResult> savePictureMsg(@RequestParam("file") MultipartFile[] files, 48 | @RequestParam("message") String message) { 49 | if (StringUtils.isNotBlank(message)) { 50 | ChatHistory chatHistory = new Gson().fromJson(message, ChatHistory.class); 51 | try { 52 | return chatService.createChatHistory(chatHistory, files); 53 | } catch (CustomException e) { 54 | ResultCode resultCode = e.getResultCode(); 55 | if (resultCode.code() == 20002) { 56 | return ResponseResult.success(null); 57 | } 58 | } 59 | } 60 | return ResponseResult.fail(); 61 | } 62 | 63 | @PostMapping("/chats/saveFileMsg") 64 | public ResponseResult saveFileMsg(@RequestParam("file") MultipartFile[] files, 65 | @RequestParam("message") String message) { 66 | if (StringUtils.isNotBlank(message)) { 67 | ChatHistory chatHistory = new Gson().fromJson(message, ChatHistory.class); 68 | try { 69 | ResponseResult> result = chatService.createChatHistory(chatHistory, files); 70 | if (result.isSuccess()) { 71 | return ResponseResult.success(result.getData().get(0)); 72 | } 73 | } catch (CustomException e) { 74 | ResultCode resultCode = e.getResultCode(); 75 | if (resultCode.code() == 20002) { 76 | return ResponseResult.success(null); 77 | } 78 | } 79 | } 80 | return ResponseResult.fail(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /easychat-auth/src/main/java/com/easychat/auth/service/impl/AuthServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.auth.service.impl; 2 | 3 | import com.easychat.auth.dto.UserJwt; 4 | import com.easychat.auth.feign.UserFeignService; 5 | import com.easychat.auth.service.AuthService; 6 | import com.easychat.auth.vo.LoginRequest; 7 | import com.easychat.common.exception.CustomException; 8 | import com.easychat.common.protocol.CommonCode; 9 | import com.easychat.common.protocol.ResponseResult; 10 | import com.easychat.common.util.JwtUtil; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.data.redis.core.StringRedisTemplate; 14 | import org.springframework.stereotype.Service; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /** 21 | * @Author: long 22 | * @Date: 2022-05-02 10:05 23 | */ 24 | @Service 25 | public class AuthServiceImpl implements AuthService { 26 | 27 | @Autowired 28 | UserFeignService userFeignService; 29 | @Autowired 30 | StringRedisTemplate redisTemplate; 31 | 32 | @Override 33 | public UserJwt loginAuth(LoginRequest request) throws CustomException { 34 | if (request == null 35 | || StringUtils.isBlank(request.getUsername()) 36 | || StringUtils.isBlank(request.getPassword())) { 37 | throw new CustomException(CommonCode.EMPTY_ERROR); 38 | } 39 | ResponseResult result = userFeignService 40 | .getUserInfo(request.getUsername(), request.getPassword()); 41 | UserJwt userJwt = result.getData(); 42 | if (result.isSuccess() && userJwt != null) { 43 | String key = "user_id:" + userJwt.getId(); 44 | String jwt = redisTemplate.opsForValue().get(key); 45 | if (StringUtils.isNotBlank(jwt)) { 46 | redisTemplate.delete(key); 47 | } 48 | Map claims = new HashMap<>(); 49 | claims.put("userId", userJwt.getId()); 50 | claims.put("username", userJwt.getUsername()); 51 | claims.put("nickName", userJwt.getNickName()); 52 | claims.put("avatar", userJwt.getAvatar()); 53 | long expireTime = 24 * 60 * 60 * 1000; 54 | if (request.getLoginFree()) { 55 | expireTime = expireTime * 7; 56 | } 57 | jwt = JwtUtil.createJwt(claims, expireTime); 58 | redisTemplate.opsForValue().set(key, jwt, expireTime, TimeUnit.MILLISECONDS); 59 | userJwt.setJwt(jwt); 60 | } 61 | return userJwt; 62 | } 63 | 64 | @Override 65 | public UserJwt getUserJwt(String userId) throws CustomException { 66 | UserJwt userJwt = null; 67 | if (StringUtils.isNotBlank(userId)) { 68 | String key = "user_id:" + userId; 69 | String jwt = redisTemplate.opsForValue().get(key); 70 | if (StringUtils.isNotBlank(jwt)) { 71 | boolean result = JwtUtil.verifyJwt(jwt); 72 | if (result) { 73 | Map claims = JwtUtil.parseJwt(jwt); 74 | userJwt = new UserJwt(); 75 | userJwt.setId((String) claims.get("userId")); 76 | userJwt.setUsername((String) claims.get("username")); 77 | userJwt.setNickName((String) claims.get("nickName")); 78 | userJwt.setAvatar((String) claims.get("avatar")); 79 | } 80 | } 81 | } 82 | return userJwt; 83 | } 84 | 85 | @Override 86 | public boolean deleteJwt(String userId) throws CustomException { 87 | String key = "user_id:" + userId; 88 | Boolean result = redisTemplate.delete(key); 89 | return result != null && result; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /easychat-chat/src/main/resources/mapper/ChatHistoryMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 48 | 49 | 72 | 73 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/util/MD5Util.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.nio.charset.StandardCharsets; 7 | import java.security.MessageDigest; 8 | import java.security.NoSuchAlgorithmException; 9 | 10 | public class MD5Util { 11 | 12 | /** 13 | * The M d5. 14 | */ 15 | static MessageDigest MD5 = null; 16 | 17 | /** 18 | * The Constant HEX_DIGITS. 19 | */ 20 | private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', 21 | '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 22 | 23 | static { 24 | try { 25 | MD5 = MessageDigest.getInstance("MD5"); 26 | } catch (NoSuchAlgorithmException ne) { 27 | ne.printStackTrace(); 28 | } 29 | } 30 | 31 | /** 32 | * 获取文件md5值. 33 | * 34 | * @param file the file 35 | * @return md5串 36 | * @throws IOException 37 | */ 38 | public static String getFileMD5String(File file) throws IOException { 39 | try (FileInputStream fileInputStream = new FileInputStream(file)) { 40 | byte[] buffer = new byte[8192]; 41 | int length; 42 | while ((length = fileInputStream.read(buffer)) != -1) { 43 | MD5.update(buffer, 0, length); 44 | } 45 | return new String(encodeHex(MD5.digest())); 46 | } catch (IOException e) { 47 | throw e; 48 | } 49 | } 50 | 51 | /** 52 | * 获取文件md5值. 53 | * 54 | * @param data the byte[] data 55 | * @return md5串 56 | * @throws IOException 57 | */ 58 | public static String getFileMD5String(byte[] data) throws IOException { 59 | MD5.update(data); 60 | return new String(encodeHex(MD5.digest())); 61 | } 62 | 63 | /** 64 | * Encode hex. 65 | * 66 | * @param bytes the bytes 67 | * @return the string 68 | */ 69 | public static String encodeHex(byte[] bytes) { 70 | return bytesToHex(bytes, 0, bytes.length); 71 | } 72 | 73 | /** 74 | * Bytes to hex. 75 | * 76 | * @param bytes the bytes 77 | * @param start the start 78 | * @param end the end 79 | * @return the string 80 | */ 81 | public static String bytesToHex(byte[] bytes, int start, int end) { 82 | StringBuilder sb = new StringBuilder(); 83 | for (int i = start; i < start + end; i++) { 84 | sb.append(byteToHex(bytes[i])); 85 | } 86 | return sb.toString(); 87 | } 88 | 89 | /** 90 | * Byte to hex. 91 | * 92 | * @param bt the bt 93 | * @return the string 94 | */ 95 | public static String byteToHex(byte bt) { 96 | return HEX_DIGITS[(bt & 0xf0) >> 4] + "" + HEX_DIGITS[bt & 0xf]; 97 | } 98 | 99 | /** 100 | * 获取md5值. 101 | * 102 | * @param str the string 103 | * @return md5串 104 | * @throws IOException 105 | */ 106 | public static String getStringMD5(String str) { 107 | StringBuilder sb = new StringBuilder(); 108 | try { 109 | byte[] data = str.getBytes(StandardCharsets.UTF_8); 110 | MessageDigest MD5 = MessageDigest.getInstance("MD5"); 111 | MD5.update(data); 112 | data = MD5.digest(); 113 | for (byte datum : data) { 114 | sb.append(HEX_DIGITS[(datum & 0xf0) >> 4]).append(HEX_DIGITS[datum & 0xf]); 115 | } 116 | } catch (Exception ignored) { 117 | } 118 | return sb.toString(); 119 | } 120 | 121 | /** 122 | * The main method. 123 | * 124 | * @param args the arguments 125 | */ 126 | // public static void main(String[] args) { 127 | 128 | // long beginTime = System.currentTimeMillis(); 129 | // File fileZIP = new File("D:\\BaiduNetdiskDownload\\test1.avi"); 130 | // 131 | // String md5 = ""; 132 | // try { 133 | // md5 = getFileMD5String(fileZIP); 134 | // } catch (IOException e) { 135 | // e.printStackTrace(); 136 | // } 137 | // long endTime = System.currentTimeMillis(); 138 | // System.out.println("MD5:" + md5 + "\n time:" + ((endTime - beginTime)) + "ms"); 139 | 140 | // System.out.println(getStringMD5("12345678")); 141 | // } 142 | } 143 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.controller; 2 | 3 | import com.easychat.common.protocol.ResponseResult; 4 | import com.easychat.common.util.CookieUtil; 5 | import com.easychat.user.dto.UserInfo; 6 | import com.easychat.user.dto.ValidationInfo; 7 | import com.easychat.user.service.EmailService; 8 | import com.easychat.user.service.UserService; 9 | import com.easychat.user.vo.*; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.*; 12 | import org.springframework.web.multipart.MultipartFile; 13 | 14 | import javax.servlet.http.HttpServletResponse; 15 | import java.util.List; 16 | import java.util.UUID; 17 | 18 | /** 19 | * @Author: long 20 | * @Date: 2022-04-18 10:03 21 | */ 22 | @RestController 23 | public class UserController { 24 | 25 | @Autowired 26 | UserService userService; 27 | @Autowired 28 | EmailService emailService; 29 | 30 | @PostMapping("/verifyCode/send") 31 | public ResponseResult sendCode(@RequestBody SendCodeRequest request, 32 | HttpServletResponse response) { 33 | ResponseResult responseResult = emailService.sendCodeToEmail(request); 34 | if (responseResult.isSuccess()) { 35 | CookieUtil.addCookie(response, "toollong.icu", "/", 36 | "verify", UUID.randomUUID().toString(), 60, false); 37 | return ResponseResult.success(); 38 | } 39 | return ResponseResult.fail(); 40 | } 41 | 42 | @PostMapping("/verifyCode/validate") 43 | public ResponseResult validateCode(@RequestBody ValidateCodeRequest request) { 44 | return emailService.validateEmailAndCode(request); 45 | } 46 | 47 | @PostMapping("/username/validate") 48 | public ResponseResult validateUsername(@RequestBody ValidateUsernameRequest request) { 49 | return userService.validateUserUsername(request); 50 | } 51 | 52 | @PostMapping("/password/validate") 53 | public ResponseResult validatePassword(@RequestBody ValidatePasswordRequest request) { 54 | return userService.validateUserPassword(request); 55 | } 56 | 57 | @PostMapping("/register") 58 | public ResponseResult register(@RequestBody RegisterRequest request) { 59 | return userService.registerUser(request); 60 | } 61 | 62 | @GetMapping("/search") 63 | public ResponseResult> searchUsers(@RequestParam("username") String username) { 64 | return userService.queryUserList(username); 65 | } 66 | 67 | @GetMapping("/user") 68 | public ResponseResult getUserInfo(@RequestParam("id") String userId) { 69 | return userService.queryUserInfo(userId); 70 | } 71 | 72 | @GetMapping("/user/auth") 73 | public ResponseResult getUserInfo(@RequestParam("username") String username, 74 | @RequestParam("password") String password) { 75 | return userService.queryUserInfo(username, password); 76 | } 77 | 78 | @PostMapping("/user/edit") 79 | public ResponseResult editUserInfo(@RequestBody EditUserInfoRequest request) { 80 | return userService.updateUserInfo(request); 81 | } 82 | 83 | @PostMapping("/user/changeAvatar") 84 | public ResponseResult changeAvatar(@RequestParam("file") MultipartFile image, 85 | @RequestParam("id") String userId) { 86 | return userService.updateAvatar(userId, image); 87 | } 88 | 89 | @PostMapping("/user/changeStatus") 90 | public ResponseResult changeStatus(@RequestBody ChangeStatusRequest request) { 91 | return userService.updateStatus(request); 92 | } 93 | 94 | @PostMapping("/user/changePassword") 95 | public ResponseResult changePassword(@RequestBody ChangePasswordRequest request) { 96 | return userService.updatePassword(request); 97 | } 98 | 99 | @PostMapping("/user/addTag") 100 | public ResponseResult addTag(@RequestBody UpdateTagsRequest request) { 101 | return userService.updateTagsAdd(request); 102 | } 103 | 104 | @PostMapping("/user/removeTag") 105 | public ResponseResult removeTag(@RequestBody UpdateTagsRequest request) { 106 | return userService.updateTagsRemove(request); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.6.6 10 | 11 | com.easychat 12 | easychat 13 | pom 14 | 1.0-SNAPSHOT 15 | 16 | easychat-chat 17 | easychat-common 18 | easychat-filesystem 19 | easychat-auth 20 | easychat-user 21 | easychat-gateway 22 | 23 | 24 | 25 | 8 26 | 8 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-dependencies 34 | 2021.0.2 35 | pom 36 | import 37 | 38 | 39 | 40 | com.alibaba.cloud 41 | spring-cloud-alibaba-dependencies 42 | 2021.0.1.0 43 | pom 44 | import 45 | 46 | 47 | 48 | io.netty 49 | netty-all 50 | 4.1.76.Final 51 | 52 | 53 | 54 | com.corundumstudio.socketio 55 | netty-socketio 56 | 1.7.19 57 | 58 | 59 | 60 | org.projectlombok 61 | lombok 62 | 1.18.22 63 | 64 | 65 | 66 | mysql 67 | mysql-connector-java 68 | 8.0.29 69 | 70 | 71 | 72 | com.alibaba 73 | druid-spring-boot-starter 74 | 1.2.9 75 | 76 | 77 | 78 | com.baomidou 79 | mybatis-plus-boot-starter 80 | 3.5.1 81 | 82 | 83 | 84 | io.minio 85 | minio 86 | 8.3.9 87 | 88 | 89 | 90 | com.squareup.okhttp3 91 | okhttp 92 | 4.10.0 93 | 94 | 95 | 96 | com.google.guava 97 | guava 98 | 31.1-jre 99 | 100 | 101 | 102 | com.google.code.gson 103 | gson 104 | 2.9.0 105 | 106 | 107 | 108 | org.apache.commons 109 | commons-lang3 110 | 3.12.0 111 | 112 | 113 | 114 | org.apache.commons 115 | commons-email 116 | 1.5 117 | 118 | 119 | 120 | ch.qos.logback 121 | logback-classic 122 | 1.2.11 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | org.springframework.boot 131 | spring-boot-maven-plugin 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /easychat-common/src/main/java/com/easychat/common/util/SnowflakeIdWorker.java: -------------------------------------------------------------------------------- 1 | package com.easychat.common.util; 2 | 3 | /** 4 | * Twitter_Snowflake
5 | * SnowFlake的结构如下(每部分用-分开):
6 | * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
7 | * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
8 | * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) 9 | * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69
10 | * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId
11 | * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
12 | * 加起来刚好64位,为一个Long型。
13 | * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。 14 | */ 15 | public class SnowflakeIdWorker { 16 | 17 | // ==============================Fields=========================================== 18 | /** 开始时间截 (2015-01-01) */ 19 | private final long twepoch = 1420041600000L; 20 | 21 | /** 机器id所占的位数 */ 22 | private final long workerIdBits = 5L; 23 | 24 | /** 数据标识id所占的位数 */ 25 | private final long datacenterIdBits = 5L; 26 | 27 | /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */ 28 | private final long maxWorkerId = -1L ^ (-1L << workerIdBits); 29 | 30 | /** 支持的最大数据标识id,结果是31 */ 31 | private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); 32 | 33 | /** 序列在id中占的位数 */ 34 | private final long sequenceBits = 12L; 35 | 36 | /** 机器ID向左移12位 */ 37 | private final long workerIdShift = sequenceBits; 38 | 39 | /** 数据标识id向左移17位(12+5) */ 40 | private final long datacenterIdShift = sequenceBits + workerIdBits; 41 | 42 | /** 时间截向左移22位(5+5+12) */ 43 | private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; 44 | 45 | /** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */ 46 | private final long sequenceMask = -1L ^ (-1L << sequenceBits); 47 | 48 | /** 工作机器ID(0~31) */ 49 | private long workerId; 50 | 51 | /** 数据中心ID(0~31) */ 52 | private long datacenterId; 53 | 54 | /** 毫秒内序列(0~4095) */ 55 | private long sequence = 0L; 56 | 57 | /** 上次生成ID的时间截 */ 58 | private long lastTimestamp = -1L; 59 | 60 | //==============================Constructors===================================== 61 | 62 | /** 63 | * 构造函数 64 | * @param workerId 工作ID (0~31) 65 | * @param datacenterId 数据中心ID (0~31) 66 | */ 67 | public SnowflakeIdWorker(long workerId, long datacenterId) { 68 | if (workerId > maxWorkerId || workerId < 0) { 69 | throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); 70 | } 71 | if (datacenterId > maxDatacenterId || datacenterId < 0) { 72 | throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); 73 | } 74 | this.workerId = workerId; 75 | this.datacenterId = datacenterId; 76 | } 77 | 78 | // ==============================Methods========================================== 79 | 80 | /** 81 | * 获得下一个ID (该方法是线程安全的) 82 | * @return SnowflakeId 83 | */ 84 | public synchronized long nextId() { 85 | long timestamp = timeGen(); 86 | 87 | //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 88 | if (timestamp < lastTimestamp) { 89 | throw new RuntimeException( 90 | String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); 91 | } 92 | 93 | //如果是同一时间生成的,则进行毫秒内序列 94 | if (lastTimestamp == timestamp) { 95 | sequence = (sequence + 1) & sequenceMask; 96 | //毫秒内序列溢出 97 | if (sequence == 0) { 98 | //阻塞到下一个毫秒,获得新的时间戳 99 | timestamp = tilNextMillis(lastTimestamp); 100 | } 101 | } 102 | //时间戳改变,毫秒内序列重置 103 | else { 104 | sequence = 0L; 105 | } 106 | 107 | //上次生成ID的时间截 108 | lastTimestamp = timestamp; 109 | 110 | //移位并通过或运算拼到一起组成64位的ID 111 | return ((timestamp - twepoch) << timestampLeftShift) // 112 | | (datacenterId << datacenterIdShift) // 113 | | (workerId << workerIdShift) // 114 | | sequence; 115 | } 116 | 117 | /** 118 | * 阻塞到下一个毫秒,直到获得新的时间戳 119 | * @param lastTimestamp 上次生成ID的时间截 120 | * @return 当前时间戳 121 | */ 122 | protected long tilNextMillis(long lastTimestamp) { 123 | long timestamp = timeGen(); 124 | while (timestamp <= lastTimestamp) { 125 | timestamp = timeGen(); 126 | } 127 | return timestamp; 128 | } 129 | 130 | /** 131 | * 返回以毫秒为单位的当前时间 132 | * @return 当前时间(毫秒) 133 | */ 134 | protected long timeGen() { 135 | return System.currentTimeMillis(); 136 | } 137 | 138 | /** 139 | * 雪花算法生成唯一id 140 | * @return id字符串 141 | */ 142 | public static String getId() { 143 | SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1); 144 | return String.valueOf(idWorker.nextId()); 145 | } 146 | 147 | //==============================Test============================================= 148 | 149 | /** 测试 */ 150 | // public static void main(String[] args) { 151 | // System.out.println(Long.toBinaryString(5)); 152 | // SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1); 153 | // for (int i = 0; i < 1000; i++) { 154 | // long id = idWorker.nextId(); 155 | // System.out.println(Long.toBinaryString(id)); 156 | // System.out.println(id); 157 | // } 158 | // } 159 | } 160 | -------------------------------------------------------------------------------- /sql/easychat.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : MySQL 5 | Source Server Type : MySQL 6 | Source Server Version : 80011 7 | Source Host : localhost:3306 8 | Source Schema : easychat 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 80011 12 | File Encoding : 65001 13 | 14 | Date: 01/08/2022 10:31:38 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for easychat_friend 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `easychat_friend`; 24 | CREATE TABLE `easychat_friend` ( 25 | `id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', 26 | `user_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属用户 id', 27 | `session_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会话 id', 28 | `session_time` datetime(0) NULL DEFAULT NULL COMMENT '会话创建时间', 29 | `friend_user_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '好友用户 id', 30 | `friend_remark` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '好友备注', 31 | `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', 32 | PRIMARY KEY (`id`) USING BTREE 33 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 34 | 35 | -- ---------------------------- 36 | -- Table structure for easychat_friend_verify 37 | -- ---------------------------- 38 | DROP TABLE IF EXISTS `easychat_friend_verify`; 39 | CREATE TABLE `easychat_friend_verify` ( 40 | `id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', 41 | `sender_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '发送者id', 42 | `receiver_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '接收者id', 43 | `apply_reason` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '申请理由', 44 | `remark` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', 45 | `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '状态,0 未处理 1 同意 2 拒绝 3 过期', 46 | `has_read` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否已读,0 未读 1 已读', 47 | `create_time` datetime(0) NOT NULL COMMENT '创建时间', 48 | PRIMARY KEY (`id`) USING BTREE 49 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 50 | 51 | -- ---------------------------- 52 | -- Table structure for easychat_group 53 | -- ---------------------------- 54 | DROP TABLE IF EXISTS `easychat_group`; 55 | CREATE TABLE `easychat_group` ( 56 | `id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', 57 | `group_name` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '聊天组名', 58 | `member_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '成员 id', 59 | `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', 60 | PRIMARY KEY (`id`) USING BTREE 61 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 62 | 63 | -- ---------------------------- 64 | -- Table structure for easychat_history 65 | -- ---------------------------- 66 | DROP TABLE IF EXISTS `easychat_history`; 67 | CREATE TABLE `easychat_history` ( 68 | `id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', 69 | `sender_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '发送者 id', 70 | `receiver_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '接收者 id', 71 | `session_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属会话 id', 72 | `type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内容类型,0 文本 1 图片 2 文件 3 语音', 73 | `content` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内容', 74 | `create_time` datetime(0) NOT NULL COMMENT '创建时间', 75 | `show_time` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '是否显示时间,1 显示 0 不显示', 76 | `has_read` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '是否已读,1 已读 0 未读', 77 | PRIMARY KEY (`id`) USING BTREE 78 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 79 | 80 | -- ---------------------------- 81 | -- Table structure for easychat_user 82 | -- ---------------------------- 83 | DROP TABLE IF EXISTS `easychat_user`; 84 | CREATE TABLE `easychat_user` ( 85 | `id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户 id', 86 | `username` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名', 87 | `password` varchar(24) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码', 88 | `nick_name` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '昵称', 89 | `avatar` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户头像', 90 | `gender` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '性别,0 女 1 男 2 保密', 91 | `age` int(4) NULL DEFAULT NULL COMMENT '年龄', 92 | `birthday` date NULL DEFAULT NULL COMMENT '生日', 93 | `region` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '地区', 94 | `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '电子邮箱', 95 | `phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系方式', 96 | `introduction` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '简介', 97 | `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '状态,0 隐身 1在线', 98 | `tags` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '标签', 99 | `group_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '加入的聊天组 id', 100 | `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', 101 | `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', 102 | PRIMARY KEY (`id`) USING BTREE, 103 | UNIQUE INDEX `uk_easychat_user_username`(`username`) USING BTREE 104 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 105 | 106 | SET FOREIGN_KEY_CHECKS = 1; 107 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/service/impl/FriendServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.easychat.common.exception.CustomException; 5 | import com.easychat.common.protocol.CommonCode; 6 | import com.easychat.common.protocol.ResponseResult; 7 | import com.easychat.user.dto.FriendInfo; 8 | import com.easychat.user.dto.VerifyInfo; 9 | import com.easychat.user.entity.Friend; 10 | import com.easychat.user.entity.FriendVerify; 11 | import com.easychat.user.entity.User; 12 | import com.easychat.user.mapper.FriendMapper; 13 | import com.easychat.user.mapper.FriendVerifyMapper; 14 | import com.easychat.user.mapper.UserMapper; 15 | import com.easychat.user.service.FriendService; 16 | import com.easychat.user.vo.*; 17 | import org.apache.commons.lang3.StringUtils; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Service; 20 | import org.springframework.transaction.annotation.Transactional; 21 | 22 | import java.util.List; 23 | 24 | /** 25 | * @Author: long 26 | * @Date: 2022-05-03 10:44 27 | */ 28 | @Service 29 | public class FriendServiceImpl implements FriendService { 30 | 31 | @Autowired 32 | FriendMapper friendMapper; 33 | @Autowired 34 | FriendVerifyMapper friendVerifyMapper; 35 | @Autowired 36 | UserMapper userMapper; 37 | 38 | @Override 39 | public ResponseResult> queryUserFriends(String userId) throws CustomException { 40 | if (StringUtils.isBlank(userId)) { 41 | throw new CustomException(CommonCode.EMPTY_ERROR); 42 | } 43 | List friendList = friendMapper.selectFriendInfoList(userId); 44 | return ResponseResult.success(friendList); 45 | } 46 | 47 | @Override 48 | public ResponseResult queryFriendInfo(String userId, String friendUserId) 49 | throws CustomException { 50 | if (StringUtils.isBlank(userId) || StringUtils.isBlank(friendUserId)) { 51 | throw new CustomException(CommonCode.EMPTY_ERROR); 52 | } 53 | FriendInfo friendInfo = friendMapper.selectFriendInfo(userId, friendUserId); 54 | if (friendInfo != null) { 55 | return ResponseResult.success(friendInfo); 56 | } 57 | return ResponseResult.fail(); 58 | } 59 | 60 | @Override 61 | @Transactional(rollbackFor = Exception.class) 62 | public ResponseResult createFriend(AddFriendRequest request) throws CustomException { 63 | if (request == null 64 | || StringUtils.isBlank(request.getUserId()) 65 | || StringUtils.isBlank(request.getSessionId()) 66 | || StringUtils.isBlank(request.getSessionTime()) 67 | || StringUtils.isBlank(request.getFriendUserId())) { 68 | throw new CustomException(CommonCode.EMPTY_ERROR); 69 | } 70 | Long count = userMapper 71 | .selectCount(new LambdaQueryWrapper() 72 | .eq(User::getId, request.getFriendUserId())); 73 | if (count > 0) { 74 | Long result = friendMapper 75 | .selectCount(new LambdaQueryWrapper() 76 | .eq(Friend::getUserId, request.getUserId()) 77 | .eq(Friend::getFriendUserId, request.getFriendUserId())); 78 | if (result < 1) { 79 | Friend friend = new Friend(); 80 | friend.setUserId(request.getUserId()); 81 | friend.setSessionId(request.getSessionId()); 82 | friend.setSessionTime(request.getSessionTime()); 83 | friend.setFriendUserId(request.getFriendUserId()); 84 | friend.setFriendRemark(request.getFriendRemark()); 85 | friend.setCreateTime(request.getCreateTime()); 86 | friendMapper.insert(friend); 87 | } 88 | return ResponseResult.success(); 89 | } 90 | return ResponseResult.fail(); 91 | } 92 | 93 | @Override 94 | @Transactional(rollbackFor = Exception.class) 95 | public ResponseResult updateFriend(EditFriendRequest request) throws CustomException { 96 | if (request == null 97 | || StringUtils.isBlank(request.getUserId()) 98 | || StringUtils.isBlank(request.getFriendUserId())) { 99 | throw new CustomException(CommonCode.EMPTY_ERROR); 100 | } 101 | Friend friend = friendMapper 102 | .selectOne(new LambdaQueryWrapper() 103 | .eq(Friend::getUserId, request.getUserId()) 104 | .eq(Friend::getFriendUserId, request.getFriendUserId())); 105 | if (friend != null) { 106 | if (StringUtils.isNotBlank(request.getSessionId())) { 107 | friend.setSessionId(request.getSessionId()); 108 | friend.setSessionTime(request.getSessionTime()); 109 | } 110 | if (request.getRemark() != null) { 111 | friend.setFriendRemark(request.getRemark()); 112 | } 113 | int result = friendMapper.updateById(friend); 114 | if (result > 0) { 115 | return ResponseResult.success(); 116 | } 117 | } 118 | return ResponseResult.fail(); 119 | } 120 | 121 | @Override 122 | @Transactional(rollbackFor = Exception.class) 123 | public ResponseResult deleteFriend(RemoveFriendRequest request) throws CustomException { 124 | if (request == null 125 | || StringUtils.isBlank(request.getUserId()) 126 | || StringUtils.isBlank(request.getFriendUserId())) { 127 | throw new CustomException(CommonCode.EMPTY_ERROR); 128 | } 129 | friendMapper.delete(new LambdaQueryWrapper() 130 | .eq(Friend::getUserId, request.getUserId()) 131 | .eq(Friend::getFriendUserId, request.getFriendUserId())); 132 | return ResponseResult.success(); 133 | } 134 | 135 | @Override 136 | public ResponseResult> queryFriendVerifyList(String userId) throws CustomException { 137 | if (StringUtils.isBlank(userId)) { 138 | throw new CustomException(CommonCode.EMPTY_ERROR); 139 | } 140 | List verifyInfoList = friendVerifyMapper.selectVerifyInfoList(userId); 141 | return ResponseResult.success(verifyInfoList); 142 | } 143 | 144 | @Override 145 | public ResponseResult queryFriendVerify(String senderId, String receiverId) 146 | throws CustomException { 147 | if (StringUtils.isBlank(senderId) || StringUtils.isBlank(receiverId)) { 148 | throw new CustomException(CommonCode.EMPTY_ERROR); 149 | } 150 | VerifyInfo verifyInfo = friendVerifyMapper.selectVerifyInfo(senderId, receiverId); 151 | if (verifyInfo != null) { 152 | return ResponseResult.success(verifyInfo); 153 | } 154 | return ResponseResult.fail(); 155 | } 156 | 157 | @Override 158 | @Transactional(rollbackFor = Exception.class) 159 | public ResponseResult createFriendVerify(AddFriendVerifyRequest request) throws CustomException { 160 | if (request == null 161 | || StringUtils.isBlank(request.getSenderId()) 162 | || StringUtils.isBlank(request.getReceiverId()) 163 | || request.getStatus() == null) { 164 | throw new CustomException(CommonCode.EMPTY_ERROR); 165 | } 166 | FriendVerify friendVerify = friendVerifyMapper 167 | .selectOne(new LambdaQueryWrapper() 168 | .eq(FriendVerify::getSenderId, request.getSenderId()) 169 | .eq(FriendVerify::getReceiverId, request.getReceiverId())); 170 | if (friendVerify == null) { 171 | friendVerify = new FriendVerify(); 172 | friendVerify.setSenderId(request.getSenderId()); 173 | friendVerify.setReceiverId(request.getReceiverId()); 174 | friendVerify.setApplyReason(request.getApplyReason()); 175 | friendVerify.setRemark(request.getRemark()); 176 | friendVerify.setStatus(request.getStatus()); 177 | friendVerify.setHasRead(request.getHasRead()); 178 | friendVerify.setCreateTime(request.getCreateTime()); 179 | friendVerifyMapper.insert(friendVerify); 180 | return ResponseResult.success(); 181 | } 182 | friendVerify.setApplyReason(request.getApplyReason()); 183 | friendVerify.setRemark(request.getRemark()); 184 | friendVerify.setStatus(request.getStatus()); 185 | friendVerify.setHasRead(request.getHasRead()); 186 | friendVerify.setCreateTime(request.getCreateTime()); 187 | friendVerifyMapper.updateById(friendVerify); 188 | return ResponseResult.success(); 189 | } 190 | 191 | @Override 192 | @Transactional(rollbackFor = Exception.class) 193 | public ResponseResult updateFriendVerify(EditFriendVerifyRequest request) 194 | throws CustomException { 195 | if (request == null 196 | || StringUtils.isBlank(request.getSenderId()) 197 | || StringUtils.isBlank(request.getReceiverId()) 198 | || request.getStatus() == null) { 199 | throw new CustomException(CommonCode.EMPTY_ERROR); 200 | } 201 | FriendVerify friendVerify = friendVerifyMapper 202 | .selectOne(new LambdaQueryWrapper() 203 | .eq(FriendVerify::getSenderId, request.getSenderId()) 204 | .eq(FriendVerify::getReceiverId, request.getReceiverId())); 205 | if (friendVerify != null) { 206 | friendVerify.setStatus(request.getStatus()); 207 | int result = friendVerifyMapper.updateById(friendVerify); 208 | if (result > 0) { 209 | return ResponseResult.success(friendVerify.getRemark()); 210 | } 211 | } 212 | return ResponseResult.fail(); 213 | } 214 | 215 | @Override 216 | @Transactional(rollbackFor = Exception.class) 217 | public ResponseResult updateFriendVerify(String userId) throws CustomException { 218 | if (StringUtils.isBlank(userId)) { 219 | throw new CustomException(CommonCode.EMPTY_ERROR); 220 | } 221 | friendVerifyMapper.updateFriendVerify(userId); 222 | return ResponseResult.success(); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/service/impl/ChatServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.toolkit.IdWorker; 5 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 6 | import com.easychat.chat.dto.ChatInfo; 7 | import com.easychat.chat.dto.FriendInfo; 8 | import com.easychat.chat.entity.ChatHistory; 9 | import com.easychat.chat.feign.FileFeignService; 10 | import com.easychat.chat.feign.UserFeignService; 11 | import com.easychat.chat.mapper.ChatHistoryMapper; 12 | import com.easychat.chat.service.ChatService; 13 | import com.easychat.chat.vo.EditFriendRequest; 14 | import com.easychat.common.exception.CustomException; 15 | import com.easychat.common.protocol.CommonCode; 16 | import com.easychat.common.protocol.ResponseResult; 17 | import org.apache.commons.lang3.StringUtils; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Service; 20 | import org.springframework.transaction.annotation.Transactional; 21 | import org.springframework.web.multipart.MultipartFile; 22 | 23 | import java.time.LocalDateTime; 24 | import java.time.format.DateTimeFormatter; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * @Author: long 30 | * @Date: 2022-04-20 17:20 31 | */ 32 | @Service 33 | public class ChatServiceImpl implements ChatService { 34 | 35 | @Autowired 36 | ChatHistoryMapper chatHistoryMapper; 37 | @Autowired 38 | UserFeignService userFeignService; 39 | @Autowired 40 | FileFeignService fileFeignService; 41 | 42 | @Override 43 | public ResponseResult> queryChatList(String userId) throws CustomException { 44 | if (StringUtils.isBlank(userId)) { 45 | throw new CustomException(CommonCode.EMPTY_ERROR); 46 | } 47 | List chatInfoList = chatHistoryMapper.selectChatInfoList(userId); 48 | return ResponseResult.success(chatInfoList); 49 | } 50 | 51 | @Override 52 | public ResponseResult queryChatInfo(String userId, String friendUserId) 53 | throws CustomException { 54 | if (StringUtils.isBlank(userId) || StringUtils.isBlank(friendUserId)) { 55 | throw new CustomException(CommonCode.EMPTY_ERROR); 56 | } 57 | ChatInfo chatInfo = chatHistoryMapper.selectChatInfo(userId, friendUserId); 58 | if (chatInfo != null) { 59 | return ResponseResult.success(chatInfo); 60 | } 61 | return ResponseResult.fail(); 62 | } 63 | 64 | @Override 65 | public ResponseResult addFriendSession(String userId, String friendUserId, String sessionTime) 66 | throws CustomException { 67 | if (StringUtils.isBlank(userId) || StringUtils.isBlank(friendUserId)) { 68 | throw new CustomException(CommonCode.EMPTY_ERROR); 69 | } 70 | ResponseResult myResult = userFeignService.getFriendInfo(userId, friendUserId); 71 | if (myResult.isSuccess()) { 72 | FriendInfo friendInfo = myResult.getData(); 73 | String sessionId = friendInfo.getSessionId(); 74 | if ("0".equals(sessionId)) { 75 | sessionId = IdWorker.getIdStr(); 76 | ResponseResult friendResult = 77 | userFeignService.getFriendInfo(friendUserId, userId); 78 | if (friendResult.isSuccess() 79 | && !"0".equals(friendResult.getData().getSessionId())) { 80 | sessionId = friendResult.getData().getSessionId(); 81 | } 82 | EditFriendRequest request = new EditFriendRequest(); 83 | request.setUserId(userId); 84 | request.setFriendUserId(friendUserId); 85 | request.setSessionId(sessionId); 86 | request.setSessionTime(sessionTime); 87 | return userFeignService.editFriend(request); 88 | } 89 | return ResponseResult.success("exist"); 90 | } 91 | return ResponseResult.fail(); 92 | } 93 | 94 | @Override 95 | public ResponseResult removeFriendSession(String userId, String friendUserId) 96 | throws CustomException { 97 | if (StringUtils.isBlank(userId) || StringUtils.isBlank(friendUserId)) { 98 | throw new CustomException(CommonCode.EMPTY_ERROR); 99 | } 100 | EditFriendRequest request = new EditFriendRequest(); 101 | request.setUserId(userId); 102 | request.setFriendUserId(friendUserId); 103 | request.setSessionId("0"); 104 | request.setSessionTime(null); 105 | return userFeignService.editFriend(request); 106 | } 107 | 108 | @Override 109 | public ResponseResult updateFriendRemark(String userId, String friendUserId, String remark) 110 | throws CustomException { 111 | if (StringUtils.isBlank(userId) || StringUtils.isBlank(friendUserId)) { 112 | throw new CustomException(CommonCode.EMPTY_ERROR); 113 | } 114 | EditFriendRequest request = new EditFriendRequest(); 115 | request.setUserId(userId); 116 | request.setFriendUserId(friendUserId); 117 | request.setRemark(remark); 118 | return userFeignService.editFriend(request); 119 | } 120 | 121 | @Override 122 | public ResponseResult> queryChatHistoryByPage( 123 | String userId, String sessionId, int page, int size) throws CustomException { 124 | if (StringUtils.isBlank(userId) || StringUtils.isBlank(sessionId)) { 125 | throw new CustomException(CommonCode.EMPTY_ERROR); 126 | } 127 | page = Math.max(page, 1); 128 | size = size > 0 ? size : 15; 129 | Page chatHistoryPage = chatHistoryMapper 130 | .selectPage(new Page<>(page, size), new LambdaQueryWrapper() 131 | .eq(ChatHistory::getSessionId, sessionId) 132 | .orderByDesc(ChatHistory::getCreateTime)); 133 | return ResponseResult.success(chatHistoryPage); 134 | } 135 | 136 | @Override 137 | @Transactional(rollbackFor = Exception.class) 138 | public ResponseResult> createChatHistory(ChatHistory chatHistory, MultipartFile[] files) 139 | throws CustomException { 140 | if (chatHistory == null 141 | || StringUtils.isBlank(chatHistory.getSenderId()) 142 | || StringUtils.isBlank(chatHistory.getReceiverId()) 143 | || StringUtils.isBlank(chatHistory.getSessionId())) { 144 | throw new CustomException(CommonCode.EMPTY_ERROR); 145 | } 146 | ResponseResult result = userFeignService 147 | .getFriendInfo(chatHistory.getReceiverId(), chatHistory.getSenderId()); 148 | if (!result.isSuccess()) { 149 | throw new CustomException(CommonCode.USER_NOT_FRIEND); 150 | } 151 | if (chatHistory.getType() == 0) { 152 | int insert = chatHistoryMapper.insert(chatHistory); 153 | if (insert > 0) { 154 | List list = new ArrayList<>(); 155 | list.add(chatHistory); 156 | return ResponseResult.success(list); 157 | } 158 | } 159 | if (chatHistory.getType() == 1) { 160 | if (files.length < 1 || files.length > 5) { 161 | throw new CustomException(CommonCode.INVALID_PARAM); 162 | } 163 | List list = new ArrayList<>(); 164 | for (int i = 0; i < files.length; i++) { 165 | if (!"image/png".equals(files[i].getContentType()) 166 | && !"image/jpeg".equals(files[i].getContentType())) { 167 | throw new CustomException(CommonCode.UPLOAD_IMAGE_FORMAT_ERROR); 168 | } 169 | if (files[i].getSize() / 1024 / 1024 > 2) { 170 | throw new CustomException(CommonCode.UPLOAD_IMAGE_SIZE_ERROR); 171 | } 172 | String filePath = "/pictures/" + chatHistory.getSessionId() + "/" + IdWorker.getIdStr(); 173 | String filename = files[i].getOriginalFilename(); 174 | if (StringUtils.isNotBlank(filename)) { 175 | filePath = filePath + filename.substring(filename.lastIndexOf(".")); 176 | } 177 | ResponseResult uploadResult = fileFeignService.uploadFileToMinio(files[i], filePath); 178 | if (uploadResult.isSuccess()) { 179 | chatHistory.setId(null); 180 | chatHistory.setContent(filePath); 181 | chatHistory.setCreateTime(LocalDateTime.now() 182 | .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 183 | if (i > 0) { 184 | chatHistory.setShowTime(0); 185 | } 186 | int insert = chatHistoryMapper.insert(chatHistory); 187 | if (insert > 0) { 188 | list.add(chatHistory); 189 | } 190 | } 191 | } 192 | return ResponseResult.success(list); 193 | } 194 | if (chatHistory.getType() == 2) { 195 | if (files.length != 1) { 196 | throw new CustomException(CommonCode.INVALID_PARAM); 197 | } 198 | if (files[0].getSize() / 1024 / 1024 > 100) { 199 | throw new CustomException(CommonCode.UPLOAD_FILE_SIZE_ERROR); 200 | } 201 | String folderPath = "/files/" + chatHistory.getSessionId() + "/"; 202 | String filename = files[0].getOriginalFilename(); 203 | assert filename != null; 204 | String prefix = filename.substring(0, filename.lastIndexOf(".")); 205 | String suffix = filename.substring(filename.lastIndexOf(".")); 206 | String filePath = folderPath + filename; 207 | for (int i = 1; i < Integer.MAX_VALUE; i++) { 208 | ResponseResult isExist = fileFeignService.checkFileIsExist(filePath); 209 | if (!isExist.isSuccess()) { 210 | break; 211 | } 212 | filePath = folderPath + prefix + "(" + i + ")" + suffix; 213 | } 214 | ResponseResult uploadResult = fileFeignService.uploadFileToMinio(files[0], filePath); 215 | if (uploadResult.isSuccess()) { 216 | chatHistory.setContent(filePath); 217 | int insert = chatHistoryMapper.insert(chatHistory); 218 | if (insert > 0) { 219 | List list = new ArrayList<>(); 220 | list.add(chatHistory); 221 | return ResponseResult.success(list); 222 | } 223 | } 224 | } 225 | return ResponseResult.fail(); 226 | } 227 | 228 | @Override 229 | @Transactional(rollbackFor = Exception.class) 230 | public ResponseResult readChatHistory(String sessionId, String userId) 231 | throws CustomException { 232 | if (StringUtils.isBlank(sessionId) || StringUtils.isBlank(userId)) { 233 | throw new CustomException(CommonCode.EMPTY_ERROR); 234 | } 235 | chatHistoryMapper.updateChatHistory(sessionId, userId); 236 | return ResponseResult.success(); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /easychat-user/src/main/java/com/easychat/user/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.easychat.user.service.impl; 2 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 | import com.baomidou.mybatisplus.core.toolkit.EncryptUtils; 5 | import com.easychat.common.exception.CustomException; 6 | import com.easychat.common.protocol.CommonCode; 7 | import com.easychat.common.protocol.ResponseResult; 8 | import com.easychat.user.dto.UserInfo; 9 | import com.easychat.user.dto.ValidationInfo; 10 | import com.easychat.user.entity.User; 11 | import com.easychat.user.feign.FileFeignService; 12 | import com.easychat.user.mapper.UserMapper; 13 | import com.easychat.user.service.UserService; 14 | import com.easychat.user.vo.*; 15 | import lombok.extern.slf4j.Slf4j; 16 | import org.apache.commons.lang3.StringUtils; 17 | import org.springframework.beans.BeanUtils; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Service; 20 | import org.springframework.transaction.annotation.Transactional; 21 | import org.springframework.web.multipart.MultipartFile; 22 | 23 | import java.text.ParseException; 24 | import java.text.SimpleDateFormat; 25 | import java.time.LocalDateTime; 26 | import java.time.format.DateTimeFormatter; 27 | import java.util.*; 28 | 29 | /** 30 | * @Author: long 31 | * @Date: 2022-04-18 11:08 32 | */ 33 | @Service 34 | @Slf4j 35 | public class UserServiceImpl implements UserService { 36 | 37 | @Autowired 38 | UserMapper userMapper; 39 | @Autowired 40 | FileFeignService fileFeignService; 41 | 42 | @Override 43 | public ResponseResult validateUserUsername(ValidateUsernameRequest request) 44 | throws CustomException { 45 | if (request == null || StringUtils.isBlank(request.getUsername())) { 46 | throw new CustomException(CommonCode.EMPTY_ERROR); 47 | } 48 | if (request.getUsername().length() < 6 || request.getUsername().length() > 11) { 49 | return ResponseResult.fail(); 50 | } 51 | User user = userMapper 52 | .selectOne(new LambdaQueryWrapper() 53 | .eq(User::getUsername, request.getUsername())); 54 | if (user != null) { 55 | ValidationInfo validationInfo = new ValidationInfo(); 56 | validationInfo.setUserId(user.getId()); 57 | validationInfo.setEmail(user.getEmail()); 58 | return ResponseResult.success(validationInfo); 59 | } 60 | return ResponseResult.fail(); 61 | } 62 | 63 | @Override 64 | public ResponseResult validateUserPassword(ValidatePasswordRequest request) 65 | throws CustomException { 66 | if (request == null 67 | || StringUtils.isBlank(request.getUserId()) 68 | || StringUtils.isBlank(request.getPassword())) { 69 | throw new CustomException(CommonCode.EMPTY_ERROR); 70 | } 71 | if (request.getPassword().length() < 8 || request.getPassword().length() > 16) { 72 | return ResponseResult.fail(); 73 | } 74 | Long count = userMapper.selectCount(new LambdaQueryWrapper() 75 | .eq(User::getId, request.getUserId()) 76 | .eq(User::getPassword, EncryptUtils.md5Base64(request.getPassword()))); 77 | if (count > 0) { 78 | return ResponseResult.success(); 79 | } 80 | return ResponseResult.fail(); 81 | } 82 | 83 | @Override 84 | @Transactional(rollbackFor = Exception.class) 85 | public ResponseResult registerUser(RegisterRequest request) throws CustomException { 86 | if (request == null 87 | || StringUtils.isBlank(request.getUsername()) 88 | || StringUtils.isBlank(request.getPassword()) 89 | || StringUtils.isBlank(request.getNickName()) 90 | || StringUtils.isBlank(request.getEmail()) 91 | || StringUtils.isBlank(request.getVerifyCode()) 92 | || !request.getIsAgree()) { 93 | throw new CustomException(CommonCode.EMPTY_ERROR); 94 | } 95 | if (request.getUsername().length() < 6 || request.getUsername().length() > 11 96 | || request.getPassword().length() < 8 || request.getPassword().length() > 16 97 | || request.getNickName().length() > 11) { 98 | throw new CustomException(CommonCode.INVALID_PARAM); 99 | } 100 | Long count = userMapper 101 | .selectCount(new LambdaQueryWrapper() 102 | .eq(User::getUsername, request.getUsername())); 103 | if (count < 1) { 104 | User user = new User(); 105 | user.setUsername(request.getUsername()); 106 | user.setPassword(EncryptUtils.md5Base64(request.getPassword())); 107 | user.setNickName(request.getNickName()); 108 | user.setEmail(request.getEmail()); 109 | user.setCreateTime(LocalDateTime.now() 110 | .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 111 | userMapper.insert(user); 112 | log.info("用户注册成功:{}", user); 113 | return ResponseResult.success(); 114 | } 115 | return ResponseResult.fail(); 116 | } 117 | 118 | @Override 119 | public ResponseResult> queryUserList(String username) throws CustomException { 120 | if (StringUtils.isBlank(username)) { 121 | throw new CustomException(CommonCode.EMPTY_ERROR); 122 | } 123 | List userInfoList = userMapper.selectUserList(username); 124 | return ResponseResult.success(userInfoList); 125 | } 126 | 127 | @Override 128 | public ResponseResult queryUserInfo(String userId) throws CustomException { 129 | if (StringUtils.isBlank(userId)) { 130 | throw new CustomException(CommonCode.EMPTY_ERROR); 131 | } 132 | User user = userMapper.selectById(userId); 133 | if (user == null) { 134 | return ResponseResult.fail(); 135 | } 136 | UserInfo userInfo = new UserInfo(); 137 | BeanUtils.copyProperties(user, userInfo); 138 | return ResponseResult.success(userInfo); 139 | } 140 | 141 | @Override 142 | public ResponseResult queryUserInfo(String username, String password) throws CustomException { 143 | if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { 144 | throw new CustomException(CommonCode.EMPTY_ERROR); 145 | } 146 | if (username.length() < 6 || username.length() > 11 147 | || password.length() < 8 || password.length() > 16) { 148 | return ResponseResult.fail(); 149 | } 150 | User user = userMapper 151 | .selectOne(new LambdaQueryWrapper() 152 | .eq(User::getUsername, username) 153 | .eq(User::getPassword, EncryptUtils.md5Base64(password))); 154 | if (user != null) { 155 | UserInfo userInfo = new UserInfo(); 156 | BeanUtils.copyProperties(user, userInfo); 157 | return ResponseResult.success(userInfo); 158 | } 159 | return ResponseResult.fail(); 160 | } 161 | 162 | @Override 163 | @Transactional(rollbackFor = Exception.class) 164 | public ResponseResult updateUserInfo(EditUserInfoRequest request) throws CustomException { 165 | if (request == null 166 | || StringUtils.isBlank(request.getUserId()) 167 | || StringUtils.isBlank(request.getNickName()) 168 | || StringUtils.isBlank(request.getEmail())) { 169 | throw new CustomException(CommonCode.EMPTY_ERROR); 170 | } 171 | if (request.getNickName().length() > 11) { 172 | throw new CustomException(CommonCode.INVALID_PARAM); 173 | } 174 | User user = userMapper.selectById(request.getUserId()); 175 | if (user == null) { 176 | throw new CustomException(CommonCode.USER_NOT_EXISTS); 177 | } 178 | user.setNickName(request.getNickName()); 179 | user.setGender(request.getGender()); 180 | user.setAge(this.getAgeByBirthday(request.getBirthday())); 181 | user.setBirthday(request.getBirthday()); 182 | user.setEmail(request.getEmail()); 183 | user.setPhone(request.getPhone()); 184 | user.setRegion(request.getRegion()); 185 | user.setIntroduction(request.getIntroduction()); 186 | user.setUpdateTime(LocalDateTime.now() 187 | .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 188 | int result = userMapper.updateById(user); 189 | if (result > 0) { 190 | UserInfo userInfo = new UserInfo(); 191 | BeanUtils.copyProperties(user, userInfo); 192 | return ResponseResult.success(userInfo); 193 | } 194 | return ResponseResult.fail(); 195 | } 196 | 197 | @Override 198 | @Transactional(rollbackFor = Exception.class) 199 | public ResponseResult updateAvatar(String userId, MultipartFile image) throws CustomException { 200 | if (StringUtils.isBlank(userId) || image == null || image.isEmpty()) { 201 | throw new CustomException(CommonCode.EMPTY_ERROR); 202 | } 203 | if (!"image/png".equals(image.getContentType()) 204 | && !"image/jpeg".equals(image.getContentType())) { 205 | throw new CustomException(CommonCode.UPLOAD_IMAGE_FORMAT_ERROR); 206 | } 207 | if (image.getSize() / 1024 / 1024 > 2) { 208 | throw new CustomException(CommonCode.UPLOAD_IMAGE_SIZE_ERROR); 209 | } 210 | User user = userMapper.selectById(userId); 211 | if (user == null) { 212 | throw new CustomException(CommonCode.USER_NOT_EXISTS); 213 | } 214 | String filePath = "/avatar/" + userId; 215 | String filename = image.getOriginalFilename(); 216 | if (StringUtils.isNotBlank(filename)) { 217 | filePath = filePath + filename.substring(filename.lastIndexOf(".")); 218 | } 219 | ResponseResult result = fileFeignService.uploadFileToMinio(image, filePath); 220 | if (result.isSuccess()) { 221 | user.setAvatar(filePath); 222 | int update = userMapper.updateById(user); 223 | if (update > 0) { 224 | return ResponseResult.success(filePath); 225 | } 226 | } 227 | return ResponseResult.fail(); 228 | } 229 | 230 | @Override 231 | @Transactional(rollbackFor = Exception.class) 232 | public ResponseResult updateStatus(ChangeStatusRequest request) throws CustomException { 233 | if (request == null 234 | || request.getStatus() == null 235 | || StringUtils.isBlank(request.getUserId())) { 236 | throw new CustomException(CommonCode.EMPTY_ERROR); 237 | } 238 | User user = userMapper.selectById(request.getUserId()); 239 | if (user == null) { 240 | throw new CustomException(CommonCode.USER_NOT_EXISTS); 241 | } 242 | user.setStatus(request.getStatus()); 243 | int update = userMapper.updateById(user); 244 | if (update > 0) { 245 | return ResponseResult.success(); 246 | } 247 | return ResponseResult.fail(); 248 | } 249 | 250 | @Override 251 | @Transactional(rollbackFor = Exception.class) 252 | public ResponseResult updatePassword(ChangePasswordRequest request) throws CustomException { 253 | if (request == null 254 | || StringUtils.isBlank(request.getUserId()) 255 | || StringUtils.isBlank(request.getNewPassword()) 256 | || StringUtils.isBlank(request.getCheckPassword())) { 257 | throw new CustomException(CommonCode.EMPTY_ERROR); 258 | } 259 | if (request.getNewPassword().length() < 8 260 | || request.getNewPassword().length() > 16 261 | || !request.getNewPassword().equals(request.getCheckPassword())) { 262 | throw new CustomException(CommonCode.INVALID_PARAM); 263 | } 264 | User user = userMapper.selectById(request.getUserId()); 265 | if (user == null) { 266 | throw new CustomException(CommonCode.USER_NOT_EXISTS); 267 | } 268 | user.setPassword(EncryptUtils.md5Base64(request.getNewPassword())); 269 | user.setUpdateTime(LocalDateTime.now() 270 | .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 271 | int result = userMapper.updateById(user); 272 | if (result > 0) { 273 | return ResponseResult.success(); 274 | } 275 | return ResponseResult.fail(); 276 | } 277 | 278 | @Override 279 | @Transactional(rollbackFor = Exception.class) 280 | public ResponseResult updateTagsAdd(UpdateTagsRequest request) throws CustomException { 281 | if (request == null 282 | || StringUtils.isBlank(request.getUserId()) 283 | || StringUtils.isBlank(request.getTag())) { 284 | throw new CustomException(CommonCode.EMPTY_ERROR); 285 | } 286 | if (request.getTag().length() > 10) { 287 | throw new CustomException(CommonCode.INVALID_PARAM); 288 | } 289 | User user = userMapper.selectById(request.getUserId()); 290 | if (user == null) { 291 | throw new CustomException(CommonCode.USER_NOT_EXISTS); 292 | } 293 | if (StringUtils.isBlank(user.getTags())) { 294 | user.setTags(request.getTag()); 295 | int update = userMapper.updateById(user); 296 | if (update > 0) { 297 | return ResponseResult.success(); 298 | } 299 | } 300 | if (StringUtils.isNotBlank(user.getTags())) { 301 | String[] tags = user.getTags().split(","); 302 | if (tags.length < 3) { 303 | user.setTags(user.getTags() + "," + request.getTag()); 304 | int update = userMapper.updateById(user); 305 | if (update > 0) { 306 | return ResponseResult.success(); 307 | } 308 | } 309 | } 310 | return ResponseResult.fail(); 311 | } 312 | 313 | @Override 314 | @Transactional(rollbackFor = Exception.class) 315 | public ResponseResult updateTagsRemove(UpdateTagsRequest request) throws CustomException { 316 | if (request == null 317 | || StringUtils.isBlank(request.getUserId()) 318 | || StringUtils.isBlank(request.getTag())) { 319 | throw new CustomException(CommonCode.EMPTY_ERROR); 320 | } 321 | User user = userMapper.selectById(request.getUserId()); 322 | if (user == null) { 323 | throw new CustomException(CommonCode.USER_NOT_EXISTS); 324 | } 325 | if (StringUtils.isBlank(user.getTags())) { 326 | return ResponseResult.success(); 327 | } 328 | if (StringUtils.isNotBlank(user.getTags())) { 329 | String[] tags = user.getTags().split(","); 330 | List tagList = new ArrayList<>(Arrays.asList(tags)); 331 | tagList.remove(request.getTag()); 332 | if (tagList.isEmpty()) { 333 | user.setTags(""); 334 | } 335 | if (tagList.size() == 1) { 336 | user.setTags(tagList.get(0)); 337 | } 338 | if (tagList.size() == 2) { 339 | user.setTags(tagList.get(0) + "," + tagList.get(1)); 340 | } 341 | int update = userMapper.updateById(user); 342 | if (update > 0) { 343 | return ResponseResult.success(); 344 | } 345 | } 346 | return ResponseResult.fail(); 347 | } 348 | 349 | /** 350 | * 根据生日计算年龄 351 | * 352 | * @param birthdayStr 生日字符串:yyyy-MM-dd 353 | * @return 年龄 354 | */ 355 | private int getAgeByBirthday(String birthdayStr) { 356 | if (StringUtils.isNotBlank(birthdayStr)) { 357 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 358 | try { 359 | Date birthday = sdf.parse(birthdayStr); 360 | //Calendar:日历 361 | /*从Calendar对象中或得一个Date对象*/ 362 | Calendar cal = Calendar.getInstance(); 363 | /*把出生日期放入Calendar类型的bir对象中,进行Calendar和Date类型进行转换*/ 364 | Calendar bir = Calendar.getInstance(); 365 | bir.setTime(birthday); 366 | /*如果生日大于当前日期,则抛出异常:出生日期不能大于当前日期*/ 367 | if (cal.before(birthday)) { 368 | throw new CustomException(CommonCode.INVALID_PARAM); 369 | } 370 | /*取出当前年月日*/ 371 | int yearNow = cal.get(Calendar.YEAR); 372 | int monthNow = cal.get(Calendar.MONTH); 373 | int dayNow = cal.get(Calendar.DAY_OF_MONTH); 374 | /*取出出生年月日*/ 375 | int yearBirth = bir.get(Calendar.YEAR); 376 | int monthBirth = bir.get(Calendar.MONTH); 377 | int dayBirth = bir.get(Calendar.DAY_OF_MONTH); 378 | /*大概年龄是当前年减去出生年*/ 379 | int age = yearNow - yearBirth; 380 | /*如果出当前月小与出生月,或者当前月等于出生月但是当前日小于出生日,那么年龄age就减一岁*/ 381 | if (monthNow < monthBirth || (monthNow == monthBirth && dayNow < dayBirth)) { 382 | age--; 383 | } 384 | return age; 385 | } catch (ParseException e) { 386 | e.printStackTrace(); 387 | } 388 | } 389 | return -1; 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /easychat-chat/src/main/java/com/easychat/chat/handler/MessageEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.easychat.chat.handler; 2 | 3 | import com.corundumstudio.socketio.AckRequest; 4 | import com.corundumstudio.socketio.SocketIOClient; 5 | import com.corundumstudio.socketio.SocketIOServer; 6 | import com.corundumstudio.socketio.VoidAckCallback; 7 | import com.corundumstudio.socketio.annotation.OnConnect; 8 | import com.corundumstudio.socketio.annotation.OnDisconnect; 9 | import com.corundumstudio.socketio.annotation.OnEvent; 10 | import com.easychat.chat.dto.ChatInfo; 11 | import com.easychat.chat.dto.FriendInfo; 12 | import com.easychat.chat.dto.VerifyInfo; 13 | import com.easychat.chat.entity.ChatHistory; 14 | import com.easychat.chat.feign.UserFeignService; 15 | import com.easychat.chat.service.ChatService; 16 | import com.easychat.chat.service.UserOnlineService; 17 | import com.easychat.chat.vo.*; 18 | import com.easychat.common.exception.CustomException; 19 | import com.easychat.common.protocol.ResponseResult; 20 | import com.easychat.common.protocol.ResultCode; 21 | import lombok.extern.slf4j.Slf4j; 22 | import org.apache.commons.lang3.StringUtils; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.stereotype.Component; 25 | 26 | import java.time.LocalDateTime; 27 | import java.time.format.DateTimeFormatter; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.UUID; 31 | 32 | /** 33 | * @Author: long 34 | * @Date: 2022-06-14 9:22 35 | */ 36 | @Component 37 | @Slf4j 38 | public class MessageEventHandler { 39 | 40 | @Autowired 41 | private SocketIOServer socketIOServer; 42 | @Autowired 43 | private UserOnlineService userOnlineService; 44 | @Autowired 45 | private ChatService chatService; 46 | @Autowired 47 | private UserFeignService userFeignService; 48 | 49 | @OnConnect 50 | public void onConnect(SocketIOClient client) { 51 | Map> urlParams = client.getHandshakeData().getUrlParams(); 52 | log.info("客户端:{} 已连接,urlParams:{}", client.getSessionId(), urlParams); 53 | } 54 | 55 | @OnDisconnect 56 | public void onDisconnect(SocketIOClient client) { 57 | Map> urlParams = client.getHandshakeData().getUrlParams(); 58 | log.info("客户端:{} 断开连接,urlParams:{}", client.getSessionId(), urlParams); 59 | String userId = client.get("userId"); 60 | if (StringUtils.isNotBlank(userId)) { 61 | userOnlineService.removeOnlineUser(userId); 62 | userOnlineService.removeUserAndClient(userId); 63 | } 64 | socketIOServer.getBroadcastOperations() 65 | .sendEvent("onlineUsers", userOnlineService.getOnlineUsers()); 66 | log.info("当前在线人数:{}", userOnlineService.getOnlineCount()); 67 | } 68 | 69 | @OnEvent("online") 70 | public void onEventOnline(SocketIOClient client, String userId, Integer status) { 71 | log.info("用户:{} 已上线...", userId); 72 | client.set("userId", userId); 73 | userOnlineService.saveUserAndClient(userId, client.getSessionId().toString()); 74 | if (status == 1) { 75 | userOnlineService.addOnlineUser(userId); 76 | socketIOServer.getBroadcastOperations() 77 | .sendEvent("onlineUsers", userOnlineService.getOnlineUsers()); 78 | log.info("当前在线人数:{}", userOnlineService.getOnlineCount()); 79 | } 80 | } 81 | 82 | @OnEvent("offline") 83 | public void onEventOffline(SocketIOClient client, String userId) { 84 | log.info("用户:{} 已下线...", userId); 85 | userOnlineService.removeOnlineUser(userId); 86 | userOnlineService.removeUserAndClient(userId); 87 | socketIOServer.getBroadcastOperations() 88 | .sendEvent("onlineUsers", userOnlineService.getOnlineUsers()); 89 | log.info("当前在线人数:{}", userOnlineService.getOnlineCount()); 90 | } 91 | 92 | @OnEvent("changeStatus") 93 | public void onEventChangeStatus(SocketIOClient client, 94 | String userId, Integer status, 95 | AckRequest ackRequest) { 96 | log.info("用户:{} 修改状态为 {}", userId, status); 97 | ChangeStatusRequest request = new ChangeStatusRequest(); 98 | request.setUserId(userId); 99 | request.setStatus(status); 100 | ResponseResult result = userFeignService.changeStatus(request); 101 | if (result.isSuccess()) { 102 | if (status == 1) { 103 | userOnlineService.addOnlineUser(userId); 104 | } 105 | if (status == 0) { 106 | userOnlineService.removeOnlineUser(userId); 107 | } 108 | socketIOServer.getBroadcastOperations() 109 | .sendEvent("onlineUsers", userOnlineService.getOnlineUsers()); 110 | log.info("当前在线人数:{}", userOnlineService.getOnlineCount()); 111 | if (ackRequest.isAckRequested()) { 112 | ackRequest.sendAckData("ok"); 113 | } 114 | } 115 | } 116 | 117 | @OnEvent("sendVerify") 118 | public void onEventSendVerify(SocketIOClient client, 119 | AddFriendVerifyRequest request, 120 | AckRequest ackRequest) { 121 | log.info("用户:{} 发送好友请求:{}", request.getSenderId(), request); 122 | ResponseResult addResult = userFeignService.addFriendVerify(request); 123 | if (addResult.isSuccess()) { 124 | ResponseResult result = userFeignService 125 | .getFriendVerify(request.getSenderId(), request.getReceiverId()); 126 | if (result.isSuccess()) { 127 | if (ackRequest.isAckRequested()) { 128 | ackRequest.sendAckData(result.getData()); 129 | } 130 | String receiverClientId = userOnlineService.getClientIdByUserId(request.getReceiverId()); 131 | if (StringUtils.isNotBlank(receiverClientId)) { 132 | SocketIOClient receiverClient = socketIOServer.getClient(UUID.fromString(receiverClientId)); 133 | if (receiverClient != null && receiverClient.isChannelOpen()) { 134 | receiverClient.sendEvent("receiveVerify", new VoidAckCallback() { 135 | @Override 136 | protected void onSuccess() { 137 | log.info("用户:{} 收到好友请求:{}", request.getReceiverId(), result.getData()); 138 | } 139 | }, result.getData()); 140 | } 141 | } else { 142 | // 将好友请求保存到redis,等用户上线后发送 143 | } 144 | } 145 | } 146 | } 147 | 148 | @OnEvent("readVerify") 149 | public void onEventReadVerify(SocketIOClient client, String userId) { 150 | log.info("用户:{} 查看新朋友列表...", userId); 151 | ResponseResult result = userFeignService.readFriendVerify(userId); 152 | if (result.isSuccess()) { 153 | log.info("用户:{} 已读好友请求列表...", userId); 154 | } 155 | } 156 | 157 | @OnEvent("rejectApply") 158 | public void onEventRejectApply(SocketIOClient client, String senderId, String receiverId) { 159 | log.info("用户:{} 拒绝好友请求...", receiverId); 160 | EditFriendVerifyRequest request = new EditFriendVerifyRequest(); 161 | request.setSenderId(senderId); 162 | request.setReceiverId(receiverId); 163 | request.setStatus(2); 164 | ResponseResult result = userFeignService.editFriendVerify(request); 165 | if (result.isSuccess()) { 166 | String senderClientId = userOnlineService.getClientIdByUserId(senderId); 167 | if (StringUtils.isNotBlank(senderClientId)) { 168 | SocketIOClient senderClient = socketIOServer.getClient(UUID.fromString(senderClientId)); 169 | if (senderClient != null && senderClient.isChannelOpen()) { 170 | senderClient.sendEvent("applyFailed", senderId, receiverId); 171 | } 172 | } else { 173 | // 将拒绝好友请求保存到redis,等用户上线后发送 174 | } 175 | } 176 | } 177 | 178 | @OnEvent("agreeApply") 179 | public void onEventAgreeApply(SocketIOClient client, AddFriendRequest request, AckRequest ackRequest) { 180 | log.info("用户:{} 同意好友请求...", request.getUserId()); 181 | EditFriendVerifyRequest verifyRequest = new EditFriendVerifyRequest(); 182 | verifyRequest.setSenderId(request.getFriendUserId()); 183 | verifyRequest.setReceiverId(request.getUserId()); 184 | verifyRequest.setStatus(1); 185 | ResponseResult result = userFeignService.editFriendVerify(verifyRequest); 186 | if (result.isSuccess()) { 187 | ResponseResult senderFriend = userFeignService 188 | .getFriendInfo(request.getFriendUserId(), request.getUserId()); 189 | boolean senderAddResult = senderFriend.isSuccess(); 190 | if (!senderAddResult) { 191 | AddFriendRequest toSender = new AddFriendRequest(); 192 | toSender.setUserId(request.getFriendUserId()); 193 | toSender.setSessionId("0"); 194 | toSender.setSessionTime(request.getCreateTime()); 195 | toSender.setFriendUserId(request.getUserId()); 196 | toSender.setFriendRemark(result.getData()); 197 | toSender.setCreateTime(request.getCreateTime()); 198 | ResponseResult addFriendResult = userFeignService.addFriend(toSender); 199 | if (addFriendResult.isSuccess()) { 200 | ResponseResult addSessionResult = 201 | chatService.addFriendSession( 202 | request.getFriendUserId(), request.getUserId(), request.getCreateTime()); 203 | if (addSessionResult.isSuccess()) { 204 | senderAddResult = true; 205 | } 206 | } 207 | } 208 | ResponseResult receiverFriend = userFeignService 209 | .getFriendInfo(request.getUserId(), request.getFriendUserId()); 210 | boolean receiverAddResult = receiverFriend.isSuccess(); 211 | if (!receiverAddResult) { 212 | AddFriendRequest toReceiver = new AddFriendRequest(); 213 | toReceiver.setUserId(request.getUserId()); 214 | toReceiver.setSessionId("0"); 215 | toReceiver.setSessionTime(request.getCreateTime()); 216 | toReceiver.setFriendUserId(request.getFriendUserId()); 217 | toReceiver.setFriendRemark(request.getFriendRemark()); 218 | toReceiver.setCreateTime(request.getCreateTime()); 219 | ResponseResult addFriendResult = userFeignService.addFriend(toReceiver); 220 | if (addFriendResult.isSuccess()) { 221 | ResponseResult addSessionResult = 222 | chatService.addFriendSession( 223 | request.getUserId(), request.getFriendUserId(), request.getCreateTime()); 224 | if (addSessionResult.isSuccess()) { 225 | receiverAddResult = true; 226 | } 227 | } 228 | } 229 | if (senderAddResult && receiverAddResult) { 230 | ResponseResult senderResult = chatService 231 | .queryChatInfo(request.getFriendUserId(), request.getUserId()); 232 | ResponseResult receiverResult = chatService 233 | .queryChatInfo(request.getUserId(), request.getFriendUserId()); 234 | if (senderResult.isSuccess() && receiverResult.isSuccess()) { 235 | if (ackRequest.isAckRequested()) { 236 | ackRequest.sendAckData(receiverResult.getData()); 237 | } 238 | String receiverClientId = userOnlineService 239 | .getClientIdByUserId(request.getFriendUserId()); 240 | if (StringUtils.isNotBlank(receiverClientId)) { 241 | SocketIOClient receiverClient = socketIOServer 242 | .getClient(UUID.fromString(receiverClientId)); 243 | if (receiverClient != null && receiverClient.isChannelOpen()) { 244 | receiverClient.sendEvent("applySucceed", senderResult.getData()); 245 | } 246 | } else { 247 | // 将同意好友请求保存到redis,等用户上线后发送 248 | } 249 | } 250 | } 251 | } 252 | } 253 | 254 | @OnEvent("removeFriend") 255 | public void onEventRemoveFriend(SocketIOClient client, 256 | String userId, String friendUserId, 257 | AckRequest ackRequest) { 258 | log.info("用户:{} 删除好友 {}", userId, friendUserId); 259 | RemoveFriendRequest request = new RemoveFriendRequest(); 260 | request.setUserId(userId); 261 | request.setFriendUserId(friendUserId); 262 | ResponseResult result = userFeignService.removeFriend(request); 263 | if (result.isSuccess() && ackRequest.isAckRequested()) { 264 | ackRequest.sendAckData("ok"); 265 | } 266 | } 267 | 268 | @OnEvent("resetRemark") 269 | public void onEventResetRemark(SocketIOClient client, 270 | String userId, String friendUserId, String remark, 271 | AckRequest ackRequest) { 272 | log.info("用户:{} 修改好友:{} 的备注为:{}", userId, friendUserId, remark); 273 | ResponseResult updateResult = chatService.updateFriendRemark(userId, friendUserId, remark); 274 | if (updateResult.isSuccess()) { 275 | ResponseResult result = userFeignService.getFriendInfo(userId, friendUserId); 276 | if (result.isSuccess() && ackRequest.isAckRequested()) { 277 | ackRequest.sendAckData(result.getData()); 278 | } 279 | } 280 | } 281 | 282 | @OnEvent("addSession") 283 | public void onEventAddSession(SocketIOClient client, 284 | String userId, String friendUserId, 285 | AckRequest ackRequest) { 286 | log.info("用户:{} 添加会话...", userId); 287 | String sessionTime = LocalDateTime.now() 288 | .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); 289 | ResponseResult addResult = chatService.addFriendSession(userId, friendUserId, sessionTime); 290 | if (addResult.isSuccess()) { 291 | if (addResult.getData() != null && ackRequest.isAckRequested()) { 292 | ackRequest.sendAckData(addResult.getData()); 293 | return; 294 | } 295 | ResponseResult result = chatService.queryChatInfo(userId, friendUserId); 296 | if (result.isSuccess() && ackRequest.isAckRequested()) { 297 | ackRequest.sendAckData(result.getData()); 298 | } 299 | } 300 | } 301 | 302 | @OnEvent("removeSession") 303 | public void onEventRemoveSession(SocketIOClient client, 304 | String userId, String friendUserId, 305 | AckRequest ackRequest) { 306 | log.info("用户:{} 删除会话...", userId); 307 | ResponseResult result = chatService.removeFriendSession(userId, friendUserId); 308 | if (result.isSuccess() && ackRequest.isAckRequested()) { 309 | ackRequest.sendAckData("ok"); 310 | } 311 | } 312 | 313 | // @OnEvent("joinRoom") 314 | // public void onEventJoinRoom(SocketIOClient client, String sessionId) { 315 | // log.info("客户端:{} 加入房间 {}", client.getSessionId(), sessionId); 316 | // client.joinRoom(sessionId); 317 | // log.info("房间:{} 的成员数量:{}", sessionId, 318 | // socketIOServer.getRoomOperations(sessionId).getClients().size()); 319 | // } 320 | 321 | @OnEvent("sendMsg") 322 | public void onEventSendMsg(SocketIOClient client, ChatHistory message, AckRequest ackRequest) { 323 | log.info("用户:{} 发送消息:{}", message.getSenderId(), message); 324 | if (message.getType() == 0) { 325 | try { 326 | ResponseResult> result = chatService.createChatHistory(message, null); 327 | if (result.isSuccess()) { 328 | String receiverClientId = userOnlineService.getClientIdByUserId(message.getReceiverId()); 329 | if (StringUtils.isNotBlank(receiverClientId)) { 330 | if (ackRequest.isAckRequested()) { 331 | ackRequest.sendAckData(result.getData().get(0), "ok"); 332 | } 333 | SocketIOClient receiverClient = socketIOServer.getClient(UUID.fromString(receiverClientId)); 334 | if (receiverClient != null && receiverClient.isChannelOpen()) { 335 | receiverClient.sendEvent("receiveMsg", new VoidAckCallback() { 336 | @Override 337 | protected void onSuccess() { 338 | log.info("用户:{} 收到消息:{}", message.getReceiverId(), result.getData().get(0)); 339 | } 340 | }, result.getData().get(0)); 341 | } 342 | } else { 343 | if (ackRequest.isAckRequested()) { 344 | ackRequest.sendAckData(result.getData().get(0), "offline"); 345 | log.info("用户:{} 不在线...", message.getReceiverId()); 346 | } 347 | // 将该消息保存为离线消息 redis 348 | } 349 | } 350 | } catch (CustomException e) { 351 | ResultCode resultCode = e.getResultCode(); 352 | if (resultCode.code() == 20002) { 353 | if (ackRequest.isAckRequested()) { 354 | ackRequest.sendAckData(null, "notFriend"); 355 | } 356 | } 357 | } 358 | } 359 | if (message.getType() == 1 || message.getType() == 2) { 360 | String receiverClientId = userOnlineService.getClientIdByUserId(message.getReceiverId()); 361 | if (StringUtils.isNotBlank(receiverClientId)) { 362 | if (ackRequest.isAckRequested()) { 363 | ackRequest.sendAckData(message, "ok"); 364 | } 365 | SocketIOClient receiverClient = socketIOServer.getClient(UUID.fromString(receiverClientId)); 366 | if (receiverClient != null && receiverClient.isChannelOpen()) { 367 | receiverClient.sendEvent("receiveMsg", new VoidAckCallback() { 368 | @Override 369 | protected void onSuccess() { 370 | log.info("用户:{} 收到消息:{}", message.getReceiverId(), message); 371 | } 372 | }, message); 373 | } 374 | } else { 375 | if (ackRequest.isAckRequested()) { 376 | ackRequest.sendAckData(message, "offline"); 377 | log.info("用户:{} 不在线...", message.getReceiverId()); 378 | } 379 | // 将该消息保存为离线消息 redis 380 | } 381 | } 382 | } 383 | 384 | @OnEvent("readMessages") 385 | public void onEventReadMessages(SocketIOClient client, String sessionId, String userId) { 386 | log.info("用户:{} 打开会话:{}", userId, sessionId); 387 | ResponseResult result = chatService.readChatHistory(sessionId, userId); 388 | if (result.isSuccess()) { 389 | log.info("用户:{} 已读会话消息...", userId); 390 | } 391 | } 392 | } 393 | --------------------------------------------------------------------------------