├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── encodings.xml ├── misc.xml ├── vcs.xml └── workspace.xml ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── MobileFrontEnd └── weChat │ ├── .project │ ├── chatlist.html │ ├── chatting.html │ ├── contact.html │ ├── css │ ├── chat.css │ ├── header.css │ ├── mui.css │ ├── mui.indexedlist.css │ ├── mui.min.css │ └── registLogin │ │ ├── default.png │ │ ├── main.css │ │ └── util.css │ ├── discover.html │ ├── fonts │ └── mui.ttf │ ├── image │ ├── addfriends.png │ ├── bg.png │ ├── download.png │ ├── error.png │ ├── face-default-cat.png │ ├── friends.png │ ├── givememoney.png │ ├── good.png │ ├── qrcode.png │ ├── scanscan.png │ ├── success.png │ └── upload.png │ ├── index.html │ ├── js │ ├── app.js │ ├── mui.indexedlist.js │ ├── mui.js │ ├── mui.min.js │ └── nickname.js │ ├── login.html │ ├── manifest.json │ ├── me.html │ ├── mp3 │ ├── di_didi.mp3 │ ├── msn.mp3 │ └── send.mp3 │ ├── myface.html │ ├── mynickname.html │ ├── plugin │ ├── cropper │ │ ├── css │ │ │ ├── cropper.css │ │ │ └── main.css │ │ ├── images │ │ │ └── picture.jpg │ │ ├── index.html │ │ ├── js │ │ │ ├── cropper.js │ │ │ └── main.js │ │ └── uploader.html │ └── v3.1.6 │ │ ├── css │ │ ├── cropper.css │ │ └── main.css │ │ ├── images │ │ └── picture.jpg │ │ ├── index.html │ │ ├── js │ │ ├── cropper.js │ │ └── main.js │ │ └── myface-uploader.html │ ├── searchFriends.html │ ├── searchFriendsResult.html │ └── unpackage │ ├── .confirmed_dependencies │ └── .dependencies ├── README.md ├── im-distributed-client ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ycw │ │ │ └── im │ │ │ └── imdistributedclient │ │ │ └── ImDistributedClientApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── ycw │ └── im │ └── imdistributedclient │ └── ImDistributedClientApplicationTests.java ├── im-distributed-com ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── ycw │ │ └── im │ │ └── imdistributedcom │ │ ├── algorithm │ │ └── route │ │ │ ├── handle │ │ │ └── ConsistentHashHandle.java │ │ │ └── routeHandler.java │ │ ├── constant │ │ └── Constants.java │ │ ├── enums │ │ └── StatusEnum.java │ │ ├── pojo │ │ ├── ChatMsg.java │ │ └── UserInfo.java │ │ ├── protocol │ │ ├── RequestProtocol.java │ │ ├── ResponseProtocol.java │ │ └── chat.proto │ │ ├── util │ │ └── NettyAttrUtil.java │ │ └── vo │ │ ├── req │ │ └── BaseRequest.java │ │ └── resp │ │ └── BaseResponse.java │ └── resources │ └── application.properties ├── im-distributed-route ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ycw │ │ │ └── im │ │ │ └── imdistributedroute │ │ │ ├── ImDistributedRouteApplication.java │ │ │ ├── config │ │ │ ├── AppConfig.java │ │ │ ├── BeanConfig.java │ │ │ └── SwaggerConfig.java │ │ │ ├── controller │ │ │ └── RouteController.java │ │ │ ├── service │ │ │ ├── AccountSerice.java │ │ │ ├── UserLocalCacheService.java │ │ │ └── impl │ │ │ │ ├── AccountServiceImpl.java │ │ │ │ └── UserLocalCacheImpl.java │ │ │ ├── tool │ │ │ ├── ServerRouteCache.java │ │ │ ├── SpringBeanFactory.java │ │ │ ├── ZkListenServerList.java │ │ │ └── Zktool.java │ │ │ └── vo │ │ │ ├── req │ │ │ ├── LoginReq.java │ │ │ ├── OffLoginReq.java │ │ │ ├── P2pChatMsg.java │ │ │ └── RegisterReq.java │ │ │ └── resp │ │ │ ├── RegistorResp.java │ │ │ └── ServerInfoResp.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── ycw │ └── im │ └── imdistributedroute │ └── ImDistributedRouteApplicationTests.java ├── im-distributed-server ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ycw │ │ │ └── im │ │ │ └── imdistributedserver │ │ │ ├── ImDistributedServerApplication.java │ │ │ ├── config │ │ │ ├── AppConfiguration.java │ │ │ ├── BeanConfig.java │ │ │ └── SwaggerConfig.java │ │ │ ├── controller │ │ │ └── ChatController.java │ │ │ ├── dao │ │ │ └── ChatDao.java │ │ │ ├── handle │ │ │ └── ChatHandler.java │ │ │ ├── init │ │ │ └── ServerNettyInit.java │ │ │ ├── server │ │ │ └── Server.java │ │ │ ├── service │ │ │ └── ChatService.java │ │ │ ├── tool │ │ │ ├── RegistorZkTool.java │ │ │ └── ZKTool.java │ │ │ ├── util │ │ │ ├── SessionChannelHolder.java │ │ │ └── SpringFactory.java │ │ │ └── vo │ │ │ ├── request │ │ │ └── SendMsgReqVo.java │ │ │ └── response │ │ │ └── SendMsgResVo.java │ └── resources │ │ ├── application.properties │ │ └── mapper │ │ └── ChatMsgMapper.xml │ └── test │ └── java │ └── com │ └── ycw │ └── im │ └── imdistributedserver │ └── ImDistributedServerApplicationTests.java ├── im-distributed-zk ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ycw │ │ │ └── im │ │ │ └── imdistributedzk │ │ │ ├── ImDistributedZkApplication.java │ │ │ ├── cache │ │ │ └── ServerCache.java │ │ │ ├── config │ │ │ ├── AppConfig.java │ │ │ └── SwaggerConfig.java │ │ │ ├── controller │ │ │ └── IndexController.java │ │ │ ├── thread │ │ │ └── RegistryZK.java │ │ │ └── util │ │ │ ├── AppConfiguration.java │ │ │ ├── SpringBeanFactory.java │ │ │ └── ZKit.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── ycw │ └── im │ └── imdistributedzk │ └── ImDistributedZkApplicationTests.java ├── im-netty.iml ├── im-singel ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── ycw │ │ │ └── im │ │ │ └── imsingel │ │ │ ├── Mobilewechat │ │ │ ├── controller │ │ │ │ ├── ChatController.java │ │ │ │ ├── FriendController.java │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ ├── enums │ │ │ │ ├── AddFriendRequstEnum.java │ │ │ │ └── MsgStateEnum.java │ │ │ ├── mapper │ │ │ │ ├── ChatMsgMapper.java │ │ │ │ ├── FriendsRequestMapper.java │ │ │ │ ├── MyFriendsMapper.java │ │ │ │ └── UsersMapper.java │ │ │ ├── netty │ │ │ │ ├── ChatHandler.java │ │ │ │ ├── Initial.java │ │ │ │ ├── Server.java │ │ │ │ ├── UserChannels.java │ │ │ │ ├── pojo │ │ │ │ │ ├── ChatMsgVo.java │ │ │ │ │ └── DataContent.java │ │ │ │ └── strategy │ │ │ │ │ ├── Context.java │ │ │ │ │ ├── Strategy.java │ │ │ │ │ ├── StrategyFactory.java │ │ │ │ │ └── impl │ │ │ │ │ ├── ChatStrategy.java │ │ │ │ │ ├── CloseStrategy.java │ │ │ │ │ ├── ConnectStrategy.java │ │ │ │ │ ├── HeartCheckStrategy.java │ │ │ │ │ └── SignStrategy.java │ │ │ ├── plugin │ │ │ │ ├── FileConst.java │ │ │ │ ├── QiNiuApi.java │ │ │ │ └── QiniuUploadType.java │ │ │ ├── pojo │ │ │ │ ├── ChatMsg.java │ │ │ │ ├── DataResult.java │ │ │ │ ├── FriendsRequest.java │ │ │ │ ├── MyFriends.java │ │ │ │ ├── Users.java │ │ │ │ ├── bo │ │ │ │ │ ├── AddFriendRequst.java │ │ │ │ │ ├── HandleFriendRequest.java │ │ │ │ │ └── UserBo.java │ │ │ │ └── vo │ │ │ │ │ ├── QueryAddFriendRequestVo.java │ │ │ │ │ ├── QueryAllFriendVo.java │ │ │ │ │ └── UserVoResult.java │ │ │ ├── service │ │ │ │ ├── ChatService.java │ │ │ │ ├── FriendService.java │ │ │ │ ├── UserService.java │ │ │ │ └── impl │ │ │ │ │ ├── ChatServiceImpl.java │ │ │ │ │ ├── FriendServiceImpl.java │ │ │ │ │ └── UserServiceImpl.java │ │ │ └── utils │ │ │ │ ├── ImageUploadUtils.java │ │ │ │ ├── JsonUtils.java │ │ │ │ ├── MD5Utils.java │ │ │ │ ├── SpringUtil.java │ │ │ │ └── TrieTree.java │ │ │ ├── NettyBoots.java │ │ │ ├── WebApplication.java │ │ │ ├── Webwechat │ │ │ ├── dao │ │ │ │ ├── GroupInfoDao.java │ │ │ │ ├── UserInfoDao.java │ │ │ │ └── impl │ │ │ │ │ ├── GroupInfoDaoImpl.java │ │ │ │ │ └── UserInfoDaoImpl.java │ │ │ ├── model │ │ │ │ ├── po │ │ │ │ │ ├── GroupInfo.java │ │ │ │ │ └── UserInfo.java │ │ │ │ └── vo │ │ │ │ │ └── ResponseJson.java │ │ │ ├── service │ │ │ │ ├── ChatService.java │ │ │ │ ├── FileUploadService.java │ │ │ │ ├── SecurityService.java │ │ │ │ ├── UserInfoService.java │ │ │ │ └── impl │ │ │ │ │ ├── FileUploadServiceImpl.java │ │ │ │ │ ├── SecurityServiceImpl.java │ │ │ │ │ ├── UserInfoServiceImpl.java │ │ │ │ │ └── WebChatServiceImpl.java │ │ │ ├── util │ │ │ │ ├── ChatType.java │ │ │ │ ├── Constant.java │ │ │ │ ├── FileUtils.java │ │ │ │ └── JsonMsgHelper.java │ │ │ └── web │ │ │ │ ├── config │ │ │ │ └── WebConfig.java │ │ │ │ ├── controller │ │ │ │ ├── ChatroomController.java │ │ │ │ ├── FileUploadController.java │ │ │ │ ├── LoginController.java │ │ │ │ └── common │ │ │ │ │ └── GlobalExceptionHandler.java │ │ │ │ ├── interceptor │ │ │ │ └── UserAuthInteceptor.java │ │ │ │ └── websocket │ │ │ │ ├── HttpRequestHandler.java │ │ │ │ ├── WebSocketChildChannelHandler.java │ │ │ │ ├── WebSocketServer.java │ │ │ │ └── WebSocketServerHandler.java │ │ │ └── learnNettyExample │ │ │ ├── BrowserAndClient │ │ │ ├── Init.java │ │ │ ├── NettyServer.java │ │ │ └── ResponseHandler.java │ │ │ ├── ClientAndServer │ │ │ ├── client │ │ │ │ ├── NettyClient.java │ │ │ │ └── handler │ │ │ │ │ ├── LoginResponseHandler.java │ │ │ │ │ └── MessageResponseHandler.java │ │ │ ├── codec │ │ │ │ ├── Codec.java │ │ │ │ └── nettyCodec │ │ │ │ │ ├── PacketDecoder.java │ │ │ │ │ └── PacketEncoder.java │ │ │ ├── protocol │ │ │ │ ├── Packet.java │ │ │ │ ├── request │ │ │ │ │ ├── LoginRequest.java │ │ │ │ │ └── MessageRequest.java │ │ │ │ ├── response │ │ │ │ │ ├── LoginResponse.java │ │ │ │ │ └── MessageResponse.java │ │ │ │ └── serializer │ │ │ │ │ ├── JSONSerializer.java │ │ │ │ │ ├── Serializer.java │ │ │ │ │ └── SerializerAlogrithm.java │ │ │ ├── server │ │ │ │ ├── NettyServer.java │ │ │ │ └── handler │ │ │ │ │ ├── AuthHandler.java │ │ │ │ │ ├── LoginRuqestHandler.java │ │ │ │ │ └── MessageRequestHandler.java │ │ │ └── util │ │ │ │ ├── Command.java │ │ │ │ ├── LoginUtil.java │ │ │ │ └── State.java │ │ │ └── WebSocketAndNetty │ │ │ ├── ChatHandler.java │ │ │ ├── Init.java │ │ │ └── WsServer.java │ └── resources │ │ ├── application.properties │ │ ├── mapper │ │ ├── ChatMsgMapper.xml │ │ ├── FriendsRequestMapper.xml │ │ ├── MyFriendsMapper.xml │ │ └── UsersMapper.xml │ │ ├── public │ │ ├── chatroom.html │ │ └── login.html │ │ └── static │ │ ├── css │ │ ├── chatroom.css │ │ ├── common │ │ │ ├── bootstrap.min.css │ │ │ ├── fileinput.min.css │ │ │ ├── font-awesome.css │ │ │ └── layui.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── fontawesome-webfont.woff2 │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── img │ │ │ ├── loading-sm.gif │ │ │ └── loading.gif │ │ └── login.css │ │ ├── img │ │ ├── avatar │ │ │ ├── Group01.jpg │ │ │ ├── Member001.jpg │ │ │ ├── Member002.jpg │ │ │ ├── Member003.jpg │ │ │ ├── Member004.jpg │ │ │ ├── Member005.jpg │ │ │ ├── Member006.jpg │ │ │ ├── Member007.jpg │ │ │ ├── Member008.jpg │ │ │ └── Member009.jpg │ │ ├── box_head.jpg │ │ ├── chat.ico │ │ ├── chat_bg.jpg │ │ ├── emoji.jpg │ │ ├── emoji │ │ │ ├── emoji_01.png │ │ │ ├── emoji_02.png │ │ │ ├── emoji_03.png │ │ │ ├── emoji_04.png │ │ │ ├── emoji_05.png │ │ │ ├── emoji_06.png │ │ │ ├── emoji_07.png │ │ │ ├── emoji_08.png │ │ │ ├── emoji_09.png │ │ │ ├── emoji_10.png │ │ │ ├── emoji_11.png │ │ │ ├── emoji_12.png │ │ │ ├── emoji_13.png │ │ │ ├── emoji_14.png │ │ │ ├── emoji_15.png │ │ │ ├── emoji_16.png │ │ │ ├── emoji_17.png │ │ │ ├── emoji_18.png │ │ │ ├── emoji_19.png │ │ │ ├── emoji_20.png │ │ │ ├── emoji_21.png │ │ │ ├── emoji_22.png │ │ │ ├── emoji_23.png │ │ │ └── emoji_24.png │ │ ├── login_bg.jpg │ │ └── upload.jpg │ │ └── js │ │ ├── chatroom.js │ │ └── common │ │ ├── bootstrap.min.js │ │ ├── fileinput.min.js │ │ ├── jquery-1.9.1.min.js │ │ ├── jquery.actual.min.js │ │ └── zh.js │ └── test │ └── java │ └── com │ └── ycw │ └── im │ └── imsingel │ └── ImSingelApplicationTests.java ├── image ├── 1.png └── 2.png ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── ycw │ │ └── im │ │ ├── imdistributedcommon │ │ └── ImDistributedCommonApplication.java │ │ ├── imdistributedcommons │ │ └── ImDistributedCommonsApplication.java │ │ └── imdistributedroute │ │ └── ImDistributedRouteApplication.java └── resources │ └── application.properties └── test └── java └── com └── ycw └── im ├── imdistributedcommon └── ImDistributedCommonApplicationTests.java ├── imdistributedcommons └── ImDistributedCommonsApplicationTests.java └── imdistributedroute └── ImDistributedRouteApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | im-root -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | weChat 4 | Create By HBuilder 5 | 6 | 7 | 8 | 9 | com.pandora.projects.ui.MKeyBuilder 10 | 11 | 12 | 13 | 14 | com.aptana.ide.core.unifiedBuilder 15 | 16 | 17 | 18 | 19 | 20 | com.pandora.projects.ui.MKeyNature 21 | com.aptana.projects.webnature 22 | 23 | 24 | 25 | 1543927910469 26 | 27 | 10 28 | 29 | org.eclipse.ui.ide.orFilterMatcher 30 | 31 | 32 | org.eclipse.ui.ide.multiFilter 33 | 1.0-projectRelativePath-matches-false-false-bin 34 | 35 | 36 | org.eclipse.ui.ide.multiFilter 37 | 1.0-projectRelativePath-matches-false-false-setting 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/css/header.css: -------------------------------------------------------------------------------- 1 | .title { 2 | background-color: black; 3 | } 4 | 5 | .title-font { 6 | color: white; 7 | } 8 | -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/css/registLogin/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/css/registLogin/default.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/discover.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 25 | 26 |
27 | 28 | 46 | 47 |
48 | 49 | 50 | 51 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/fonts/mui.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/fonts/mui.ttf -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/addfriends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/addfriends.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/bg.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/download.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/error.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/face-default-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/face-default-cat.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/friends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/friends.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/givememoney.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/givememoney.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/good.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/good.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/qrcode.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/scanscan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/scanscan.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/success.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/image/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/image/upload.png -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/mp3/di_didi.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/mp3/di_didi.mp3 -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/mp3/msn.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/mp3/msn.mp3 -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/mp3/send.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/mp3/send.mp3 -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/plugin/cropper/images/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/plugin/cropper/images/picture.jpg -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/plugin/v3.1.6/images/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/MobileFrontEnd/weChat/plugin/v3.1.6/images/picture.jpg -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/plugin/v3.1.6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Cropper 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 | 26 |
27 | Picture 28 |
29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/plugin/v3.1.6/js/main.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | 3 | var $image = $('#image'); 4 | var options = { 5 | aspectRatio: 1 / 1, 6 | preview: '.img-preview', 7 | crop: function (e) { 8 | } 9 | }; 10 | 11 | // Cropper 12 | $image.cropper(options); 13 | 14 | // Methods 15 | $('.docs-buttons').on('click', '[data-method]', function () { 16 | var cropper = $image.data('cropper'); 17 | var result; 18 | 19 | result = $image.cropper("getCroppedCanvas"); 20 | 21 | if (result) { 22 | // Bootstrap's Modal 23 | $('#getCroppedCanvasModal').modal().find('.modal-body').html(result); 24 | var base64Url = result.toDataURL(); 25 | console.log(base64Url); 26 | } 27 | 28 | }); 29 | 30 | }); -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/unpackage/.confirmed_dependencies: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /MobileFrontEnd/weChat/unpackage/.dependencies: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /im-distributed-client/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /im-distributed-client/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-client/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /im-distributed-client/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /im-distributed-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.ycw.im 7 | im-root 8 | 1.0-SNAPSHOT 9 | 10 | 11 | im-distributed-client 12 | 0.0.1-SNAPSHOT 13 | im-distributed-client 14 | 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-test 29 | test 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-maven-plugin 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /im-distributed-client/src/main/java/com/ycw/im/imdistributedclient/ImDistributedClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedclient; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImDistributedClientApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImDistributedClientApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /im-distributed-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /im-distributed-client/src/test/java/com/ycw/im/imdistributedclient/ImDistributedClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedclient; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedClientApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /im-distributed-com/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /im-distributed-com/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-com/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /im-distributed-com/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /im-distributed-com/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.ycw.im 7 | im-root 8 | 1.0-SNAPSHOT 9 | 10 | 11 | im-distributed-com 12 | 0.0.1-SNAPSHOT 13 | im-distributed-com 14 | 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | com.google.protobuf 23 | protobuf-java 24 | 25 | 26 | 27 | com.squareup.okhttp3 28 | okhttp 29 | 30 | 31 | 32 | io.springfox 33 | springfox-swagger2 34 | compile 35 | 36 | 37 | io.springfox 38 | springfox-swagger-ui 39 | 40 | 41 | 42 | com.github.sgroschupf 43 | zkclient 44 | 45 | 46 | 47 | io.netty 48 | netty-all 49 | 50 | 51 | 52 | org.projectlombok 53 | lombok 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/algorithm/route/routeHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.algorithm.route; 2 | 3 | import java.util.List; 4 | 5 | public interface routeHandler { 6 | 7 | String getRoute(Listips ,String key); 8 | } 9 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.constant; 2 | 3 | /** 4 | * @author ycw 5 | */ 6 | public class Constants { 7 | 8 | 9 | /** 10 | * 服务端手动 push 次数 11 | */ 12 | public static final String COUNTER_SERVER_PUSH_COUNT = "counter.server.push.count"; 13 | 14 | 15 | /** 16 | * 客户端手动 push 次数 17 | */ 18 | public static final String COUNTER_CLIENT_PUSH_COUNT = "counter.client.push.count"; 19 | 20 | 21 | /** 22 | * 自定义报文类型 23 | */ 24 | public static class CommandType { 25 | /** 26 | * 登录 27 | */ 28 | public static final int LOGIN = 1; 29 | /** 30 | * 业务消息 31 | */ 32 | public static final int MSG = 2; 33 | 34 | /** 35 | * ping 36 | */ 37 | public static final int PING = 3; 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/enums/StatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.enums; 2 | 3 | /** 4 | * @Author yuchunwei 5 | */ 6 | public enum StatusEnum { 7 | 8 | 9 | SUCCESS(200, "成功"), 10 | FAIL(-1, "失败"), 11 | 12 | //消息相关 13 | SEND_SUCCESS(201,"发送消息成功"), 14 | SEND_FAIL(202,"发送消息失败"), 15 | 16 | 17 | //登陆相关400起始 18 | LOGIN_SUCCESS(400,"登陆成功"), 19 | REPEAT_LOGIN(401, "重复登陆"), 20 | OFF_LINE(402, "用户下线"), 21 | 22 | //注册相关500起始 23 | REGISTOR_SUCCESS(500,"注册成功"), 24 | REPEAT_USERNAME(501,"注册失败,username重复"), 25 | REPEAT_USERID(502,"注册失败,userid重复"), 26 | NOTREGISTOR(503,"没有注册"); 27 | 28 | private int code; 29 | private String description; 30 | 31 | StatusEnum(int code, String description) { 32 | this.code = code; 33 | this.description = description; 34 | } 35 | 36 | public int getCode() { 37 | return code; 38 | } 39 | 40 | public String getDescription() { 41 | return description; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/pojo/ChatMsg.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.pojo; 2 | 3 | 4 | import lombok.Data; 5 | 6 | import java.util.Date; 7 | 8 | @Data 9 | public class ChatMsg { 10 | public ChatMsg(String sendUserId,String acceptUserId,String msg){ 11 | this.sendUserId = sendUserId; 12 | this.acceptUserId = acceptUserId; 13 | this.msg = msg; 14 | this.createTime = new Date(); 15 | this.signFlag = 1; 16 | } 17 | 18 | private String id; 19 | 20 | private String sendUserId; 21 | 22 | private String acceptUserId; 23 | 24 | private String msg; 25 | 26 | private Integer signFlag; 27 | 28 | private Date createTime; 29 | 30 | } -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/pojo/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.pojo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class UserInfo { 10 | private Long userId; 11 | private String userName; 12 | 13 | public UserInfo(Long userId, String userName) { 14 | this.userId = userId; 15 | this.userName = userName; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "UserInfo{" + 21 | "userId=" + userId + 22 | ", userName='" + userName + '\'' + 23 | '}'; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/protocol/chat.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package protocol ; 3 | 4 | option java_package = "com.ycw.im.imdistributedcom.protocol"; 5 | option java_outer_classname = "RequestProtocol"; 6 | 7 | message ReqProtocol{ 8 | required int64 requestId = 2 ; 9 | required string reqMsg = 1 ; 10 | required int32 type = 3; 11 | 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/util/NettyAttrUtil.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.util; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.util.Attribute; 5 | import io.netty.util.AttributeKey; 6 | 7 | /** 8 | * @Author yuchunwei 9 | */ 10 | public class NettyAttrUtil { 11 | 12 | private static final AttributeKey ATTR_KEY_READER_TIME = AttributeKey.valueOf("readerTime"); 13 | 14 | 15 | public static void updateReaderTime(Channel channel, Long time) { 16 | channel.attr(ATTR_KEY_READER_TIME).set(time.toString()); 17 | } 18 | 19 | public static Long getReaderTime(Channel channel) { 20 | String value = getAttribute(channel, ATTR_KEY_READER_TIME); 21 | 22 | if (value != null) { 23 | return Long.valueOf(value); 24 | } 25 | return null; 26 | } 27 | 28 | 29 | private static String getAttribute(Channel channel, AttributeKey key) { 30 | Attribute attr = channel.attr(key); 31 | return attr.get(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/vo/req/BaseRequest.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.vo.req; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Data 10 | public class BaseRequest { 11 | 12 | @ApiModelProperty(required = false, value = "唯一请求号", example = "1234567890") 13 | private String reqNo; 14 | 15 | @ApiModelProperty(required = false, value = "当前请求的时间戳", example = "0") 16 | private int timeStamp; 17 | 18 | public BaseRequest() { 19 | this.setTimeStamp((int) System.currentTimeMillis() / 1000); 20 | } 21 | 22 | private void setTimeStamp(int timeStamp) { 23 | this.timeStamp = timeStamp; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/java/com/ycw/im/imdistributedcom/vo/resp/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcom.vo.resp; 2 | 3 | import com.ycw.im.imdistributedcom.enums.StatusEnum; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | 12 | @Data 13 | public class BaseResponse implements Serializable { 14 | private int status; 15 | private String message; 16 | private String reqNo; 17 | private T dataBody; 18 | 19 | public BaseResponse(){ 20 | 21 | } 22 | 23 | public BaseResponse(T dataBody, String message, int status) { 24 | this.dataBody = dataBody; 25 | this.message = message; 26 | this.status = status; 27 | } 28 | 29 | public BaseResponse(T dataBody, String message, int status, String reqNo) { 30 | this.dataBody = dataBody; 31 | this.message = message; 32 | this.status = status; 33 | this.reqNo = reqNo; 34 | } 35 | public static BaseResponse ok(T data, String message,int code) { 36 | return new BaseResponse<>(data, message, code); 37 | } 38 | 39 | public static BaseResponse ok(T data, String message) { 40 | return new BaseResponse<>(data, message, StatusEnum.SUCCESS.getCode()); 41 | } 42 | public static BaseResponse error(T data,String message,int status){ 43 | return new BaseResponse<>(data,message,status); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /im-distributed-com/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /im-distributed-route/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /im-distributed-route/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-route/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /im-distributed-route/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/ImDistributedRouteApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImDistributedRouteApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImDistributedRouteApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Component; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Component 10 | public class AppConfig { 11 | @Value("${app.zk.root}") 12 | private String zkRoot; 13 | 14 | @Value("${app.zk.addr}") 15 | private String zkAddr; 16 | 17 | 18 | @Value("${server.port}") 19 | private int port; 20 | 21 | @Value("${app.zk.connect.timeout}") 22 | private int zkConnectTimeout; 23 | 24 | public int getZkConnectTimeout() { 25 | return zkConnectTimeout; 26 | } 27 | 28 | public int getPort() { 29 | return port; 30 | } 31 | 32 | public void setPort(int port) { 33 | this.port = port; 34 | } 35 | 36 | public String getZkRoot() { 37 | return zkRoot; 38 | } 39 | 40 | public void setZkRoot(String zkRoot) { 41 | this.zkRoot = zkRoot; 42 | } 43 | 44 | public String getZkAddr() { 45 | return zkAddr; 46 | } 47 | 48 | public void setZkAddr(String zkAddr) { 49 | this.zkAddr = zkAddr; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/config/BeanConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.config; 2 | 3 | import com.google.common.cache.CacheBuilder; 4 | import com.google.common.cache.CacheLoader; 5 | import com.google.common.cache.LoadingCache; 6 | import okhttp3.OkHttpClient; 7 | import org.I0Itec.zkclient.ZkClient; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.data.redis.connection.RedisConnectionFactory; 12 | import org.springframework.data.redis.core.RedisTemplate; 13 | import org.springframework.data.redis.core.StringRedisTemplate; 14 | import org.springframework.data.redis.serializer.StringRedisSerializer; 15 | 16 | import java.util.concurrent.TimeUnit; 17 | 18 | /** 19 | * @Author yuchunwei 20 | */ 21 | @Configuration 22 | public class BeanConfig { 23 | @Autowired 24 | private AppConfig config ; 25 | 26 | @Bean 27 | public ZkClient buildZKClient(){ 28 | return new ZkClient(config.getZkAddr(), config.getZkConnectTimeout()); 29 | } 30 | 31 | 32 | @Bean 33 | public LoadingCache buildCache(){ 34 | return CacheBuilder.newBuilder() 35 | .build(new CacheLoader() { 36 | @Override 37 | public String load(String s) throws Exception { 38 | return null; 39 | } 40 | }); 41 | } 42 | @Bean 43 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) { 44 | StringRedisTemplate redisTemplate = new StringRedisTemplate(factory); 45 | redisTemplate.setKeySerializer(new StringRedisSerializer()); 46 | redisTemplate.setValueSerializer(new StringRedisSerializer()); 47 | redisTemplate.afterPropertiesSet(); 48 | return redisTemplate; 49 | } 50 | 51 | @Bean 52 | public OkHttpClient okHttpClient() { 53 | OkHttpClient.Builder builder = new OkHttpClient.Builder(); 54 | builder.connectTimeout(30, TimeUnit.SECONDS) 55 | .readTimeout(10, TimeUnit.SECONDS) 56 | .writeTimeout(10,TimeUnit.SECONDS) 57 | .retryOnConnectionFailure(true); 58 | return builder.build(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.config; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | /** 15 | * @Author yuchunwei 16 | */ 17 | 18 | @Configuration 19 | @EnableSwagger2 20 | /** 是否打开swagger **/ 21 | @ConditionalOnExpression("'${swagger.enable}' == 'true'") 22 | public class SwaggerConfig { 23 | 24 | 25 | @Bean 26 | public Docket createRestApi() { 27 | return new Docket(DocumentationType.SWAGGER_2) 28 | .apiInfo(apiInfo()) 29 | .select() 30 | .apis(RequestHandlerSelectors.basePackage("com.ycw.im.imdistributedroute.controller")) 31 | .paths(PathSelectors.any()) 32 | .build(); 33 | } 34 | 35 | private ApiInfo apiInfo() { 36 | return new ApiInfoBuilder() 37 | .title("im-route") 38 | .description("im-route api") 39 | .termsOfServiceUrl("") 40 | .contact("ycw") 41 | .version("1.0.0") 42 | .build(); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/service/AccountSerice.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.service; 2 | 3 | import com.ycw.im.imdistributedcom.vo.resp.BaseResponse; 4 | import com.ycw.im.imdistributedroute.vo.req.LoginReq; 5 | import com.ycw.im.imdistributedroute.vo.req.OffLoginReq; 6 | import com.ycw.im.imdistributedroute.vo.req.P2pChatMsg; 7 | import com.ycw.im.imdistributedroute.vo.req.RegisterReq; 8 | import com.ycw.im.imdistributedroute.vo.resp.ServerInfoResp; 9 | 10 | public interface AccountSerice { 11 | //登陆成功即返回服务器信息 12 | BaseResponse login(LoginReq loginReq); 13 | 14 | //注册用户,由接口调用方(client)提供Id和userName,这里只作去重校验 15 | BaseResponse registor(RegisterReq registerReq); 16 | 17 | BaseResponse p2pChat(P2pChatMsg msg) throws Exception; 18 | 19 | BaseResponse offLogin(OffLoginReq req); 20 | } 21 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/service/UserLocalCacheService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.service; 2 | 3 | import com.ycw.im.imdistributedcom.pojo.UserInfo; 4 | import com.ycw.im.imdistributedroute.vo.req.OffLoginReq; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | public interface UserLocalCacheService { 10 | 11 | boolean isAlreadLogin(Long userId); 12 | 13 | boolean cacheLogin(UserInfo userInfo); 14 | 15 | boolean cacheOffLogin(OffLoginReq req); 16 | 17 | UserInfo getUserInfoById(Long userId); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/service/impl/UserLocalCacheImpl.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.service.impl; 2 | 3 | import com.ycw.im.imdistributedcom.pojo.UserInfo; 4 | import com.ycw.im.imdistributedroute.service.UserLocalCacheService; 5 | import com.ycw.im.imdistributedroute.vo.req.OffLoginReq; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | @Service 15 | public class UserLocalCacheImpl implements UserLocalCacheService { 16 | //本地缓存用户在线用户表 17 | private final Map USER_INFO_MAP = new ConcurrentHashMap(128); 18 | 19 | @Override 20 | public boolean cacheLogin(UserInfo userInfo) { 21 | USER_INFO_MAP.put(userInfo.getUserId(),userInfo); 22 | return true ; 23 | } 24 | 25 | @Override 26 | public boolean isAlreadLogin(Long userId) { 27 | if(USER_INFO_MAP.containsKey(userId)){ 28 | return true ; 29 | } 30 | else return false; 31 | } 32 | 33 | @Override 34 | public boolean cacheOffLogin(OffLoginReq req) { 35 | if (USER_INFO_MAP.containsKey(req.getUserId())){ 36 | USER_INFO_MAP.remove(req.getUserId()); 37 | } 38 | return true; 39 | } 40 | 41 | @Override 42 | public UserInfo getUserInfoById(Long userId) { 43 | return USER_INFO_MAP.get(userId); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/tool/ServerRouteCache.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.tool; 2 | 3 | import com.google.common.cache.LoadingCache; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | //本地缓存存放可用路由信息 15 | @Component 16 | public class ServerRouteCache { 17 | @Autowired 18 | private LoadingCache cache; 19 | 20 | @Autowired 21 | private Zktool zktool; 22 | 23 | private AtomicInteger index = new AtomicInteger(0); 24 | 25 | public void updateCache(List strings){ 26 | //删除所有 27 | cache.invalidateAll(); 28 | 29 | for(String str : strings){ 30 | add(str.split("-")[1]); 31 | } 32 | } 33 | 34 | private void add(String str){ 35 | cache.put(str,str); 36 | } 37 | 38 | //如果cache中没有任何服务器,则添加节点至cache中 39 | public List getAll(){ 40 | List list = new ArrayList<>(3); 41 | List nodes = zktool.getAllNode(); 42 | if(cache.size() == 0){ 43 | for(String str : nodes){ 44 | String key = str.split("-")[1]; 45 | add(key); 46 | } 47 | } 48 | for(String str : nodes){ 49 | list.add(str.split("-")[1]); 50 | } 51 | return list; 52 | } 53 | 54 | public String select(){ 55 | List allIp = getAll(); 56 | if(allIp.size() == 0){ 57 | throw new RuntimeException("后台服务器全部没有启动!!"); 58 | } 59 | int size = allIp.size(); 60 | 61 | //负载均衡算法,有时间可以改成负载均衡随机算法 62 | return allIp.get(index.incrementAndGet() % size); 63 | } 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/tool/SpringBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.tool; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | 12 | 13 | @Component 14 | public final class SpringBeanFactory implements ApplicationContextAware { 15 | private static ApplicationContext context; 16 | 17 | public static T getBean(Class c){ 18 | return context.getBean(c); 19 | } 20 | 21 | 22 | public static T getBean(String name,Class clazz){ 23 | return context.getBean(name,clazz); 24 | } 25 | 26 | @Override 27 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 28 | context = applicationContext; 29 | } 30 | 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/tool/ZkListenServerList.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.tool; 2 | 3 | import com.ycw.im.imdistributedroute.config.AppConfig; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | public class ZkListenServerList implements Runnable { 10 | 11 | private Zktool zktool ; 12 | private AppConfig config; 13 | 14 | public ZkListenServerList() { 15 | zktool = SpringBeanFactory.getBean(Zktool.class) ; 16 | config = SpringBeanFactory.getBean(AppConfig.class) ; 17 | } 18 | 19 | @Override 20 | public void run() { 21 | zktool.subscribeEvent(config.getZkRoot()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/tool/Zktool.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.tool; 2 | 3 | import com.ycw.im.imdistributedroute.config.AppConfig; 4 | import org.I0Itec.zkclient.IZkChildListener; 5 | import org.I0Itec.zkclient.ZkClient; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @Author yuchunwei 16 | */ 17 | @Component 18 | public class Zktool { 19 | private static Logger logger = LoggerFactory.getLogger(Zktool.class); 20 | 21 | @Autowired 22 | private AppConfig config; 23 | 24 | @Autowired 25 | private ZkClient buildZKClient; 26 | 27 | @Autowired 28 | private ServerRouteCache cache; 29 | 30 | public void subscribeEvent(String path){ 31 | buildZKClient.subscribeChildChanges(path, new IZkChildListener() { 32 | @Override 33 | public void handleChildChange(String s, List list) throws Exception { 34 | //一旦zookeeper列表发生变化,就要更新本地路由缓存 35 | cache.updateCache(list); 36 | logger.info("【{}】路径下可用服务器列表更新为【{}】",path,list.toString()); 37 | } 38 | }); 39 | } 40 | 41 | public List getAllNode(){ 42 | List list = buildZKClient.getChildren(config.getZkRoot()); 43 | logger.info("查询可用服务器节点【{}】",list); 44 | return list ; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/vo/req/LoginReq.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.vo.req; 2 | 3 | import com.ycw.im.imdistributedcom.vo.req.BaseRequest; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Data 10 | public class LoginReq extends BaseRequest { 11 | private long userId; 12 | private String userName; 13 | } 14 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/vo/req/OffLoginReq.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.vo.req; 2 | 3 | import com.ycw.im.imdistributedcom.vo.req.BaseRequest; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Data 10 | public class OffLoginReq extends BaseRequest { 11 | private long userId; 12 | } 13 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/vo/req/P2pChatMsg.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.vo.req; 2 | 3 | import com.ycw.im.imdistributedcom.vo.req.BaseRequest; 4 | import lombok.Data; 5 | 6 | import javax.annotation.security.DenyAll; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | @Data 12 | public class P2pChatMsg extends BaseRequest { 13 | private long sendUserId; 14 | private long receiveUserId; 15 | private String msg; 16 | private String userName; 17 | } 18 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/vo/req/RegisterReq.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.vo.req; 2 | 3 | import com.ycw.im.imdistributedcom.vo.req.BaseRequest; 4 | import lombok.Data; 5 | 6 | 7 | /** 8 | * @Author yuchunwei 9 | */ 10 | @Data 11 | public class RegisterReq extends BaseRequest { 12 | private long userId; 13 | private String userName; 14 | } 15 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/vo/resp/RegistorResp.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.vo.resp; 2 | 3 | 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | @Data 12 | public class RegistorResp implements Serializable { 13 | private long userId; 14 | private String userName; 15 | } 16 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/java/com/ycw/im/imdistributedroute/vo/resp/ServerInfoResp.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute.vo.resp; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | @Data 12 | public class ServerInfoResp implements Serializable { 13 | private String ip; 14 | private int httpPort; 15 | private int nettyPort; 16 | public ServerInfoResp(String ip,int httpPort,int nettyPort){ 17 | this.ip = ip; 18 | this.httpPort = httpPort; 19 | this.nettyPort = nettyPort; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /im-distributed-route/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-route/src/main/resources/application.properties -------------------------------------------------------------------------------- /im-distributed-route/src/test/java/com/ycw/im/imdistributedroute/ImDistributedRouteApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedRouteApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /im-distributed-server/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /im-distributed-server/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-server/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /im-distributed-server/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/ImDistributedServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver; 2 | 3 | import com.ycw.im.imdistributedserver.config.AppConfiguration; 4 | import com.ycw.im.imdistributedserver.tool.RegistorZkTool; 5 | import org.mybatis.spring.annotation.MapperScan; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.boot.CommandLineRunner; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | 14 | import java.net.InetAddress; 15 | 16 | @SpringBootApplication 17 | @MapperScan(basePackages = "com.ycw.im.imdistributedserver.dao") 18 | public class ImDistributedServerApplication implements CommandLineRunner { 19 | 20 | private final static Logger LOGGER = LoggerFactory.getLogger(ImDistributedServerApplication.class); 21 | 22 | @Autowired 23 | private AppConfiguration appConfiguration; 24 | 25 | @Value("${server.port}") 26 | private int httpPort; 27 | 28 | public static void main(String[] args) { 29 | SpringApplication.run(ImDistributedServerApplication.class, args); 30 | LOGGER.info("服务端开始启动"); 31 | } 32 | 33 | 34 | @Override 35 | public void run(String... args) throws Exception { 36 | String localAdree = InetAddress.getLocalHost().getHostAddress(); 37 | Thread thread = new Thread(new RegistorZkTool(localAdree, appConfiguration.getImServerPort(), httpPort)); 38 | thread.setName("registry-zk"); 39 | thread.start(); 40 | ; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/config/AppConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.stereotype.Component; 6 | 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | @Component 12 | @Data 13 | public class AppConfiguration { 14 | 15 | @Value("${app.zk.root}") 16 | private String zkRoot; 17 | 18 | @Value("${app.zk.addr}") 19 | private String zkAddr; 20 | 21 | @Value("${app.zk.switch}") 22 | private boolean zkSwitch; 23 | 24 | @Value("${im.server.port}") 25 | private int imServerPort; 26 | 27 | @Value("${im.clear.route.request.url}") 28 | private String clearRouteUrl; 29 | 30 | @Value("${im.heartbeat.time}") 31 | private long heartBeatTime; 32 | 33 | @Value("${app.zk.connect.timeout}") 34 | private int zkConnectTimeout; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/config/BeanConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.config; 2 | 3 | import com.ycw.im.imdistributedcom.constant.Constants; 4 | import com.ycw.im.imdistributedcom.protocol.RequestProtocol; 5 | import org.I0Itec.zkclient.ZkClient; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * @Author yuchunwei 12 | */ 13 | @Configuration 14 | public class BeanConfig { 15 | 16 | @Autowired 17 | private AppConfiguration appConfiguration; 18 | 19 | @Bean 20 | public RequestProtocol.ReqProtocol heartbeat() { 21 | RequestProtocol.ReqProtocol heart = RequestProtocol.ReqProtocol.newBuilder() 22 | .setRequestId(0L) 23 | .setSendId(0L) 24 | .setReqMsg("服务端pong") 25 | .setType(Constants.CommandType.PING) 26 | .build(); 27 | return heart; 28 | } 29 | 30 | @Bean 31 | public ZkClient zkClient() { 32 | return new ZkClient(appConfiguration.getZkAddr(), appConfiguration.getZkConnectTimeout()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.config; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | /** 15 | * @Author yuchunwei 16 | */ 17 | 18 | @Configuration 19 | @EnableSwagger2 20 | /** 是否打开swagger **/ 21 | @ConditionalOnExpression("'${swagger.enable}' == 'true'") 22 | public class SwaggerConfig { 23 | 24 | 25 | @Bean 26 | public Docket createRestApi() { 27 | return new Docket(DocumentationType.SWAGGER_2) 28 | .apiInfo(apiInfo()) 29 | .select() 30 | .apis(RequestHandlerSelectors.basePackage("com.ycw.im.imdistributedserver.controller")) 31 | .paths(PathSelectors.any()) 32 | .build(); 33 | } 34 | 35 | private ApiInfo apiInfo() { 36 | return new ApiInfoBuilder() 37 | .title("Server api") 38 | .description("test server api") 39 | .termsOfServiceUrl("") 40 | .contact("ycw") 41 | .version("1.0.0") 42 | .build(); 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/controller/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.controller; 2 | 3 | import com.ycw.im.imdistributedcom.vo.resp.BaseResponse; 4 | import com.ycw.im.imdistributedserver.server.Server; 5 | import com.ycw.im.imdistributedserver.vo.request.SendMsgReqVo; 6 | import io.swagger.annotations.ApiOperation; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.ResponseBody; 13 | 14 | 15 | /** 16 | * @Author yuchunwei 17 | */ 18 | @Controller 19 | @RequestMapping("/") 20 | public class ChatController { 21 | @Autowired 22 | private Server server; 23 | 24 | @ApiOperation("服务端发送消息") 25 | @RequestMapping(value = "sendMsg",method = RequestMethod.POST) 26 | @ResponseBody 27 | public BaseResponse sendMsg(@RequestBody SendMsgReqVo sendMsgReqVO){ 28 | return server.sendMsg(sendMsgReqVO); 29 | } 30 | 31 | 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/dao/ChatDao.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.dao; 2 | 3 | import com.ycw.im.imdistributedcom.pojo.ChatMsg; 4 | import org.springframework.stereotype.Repository; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Repository 10 | public interface ChatDao { 11 | void insertMsg(ChatMsg msg); 12 | } 13 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/init/ServerNettyInit.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.init; 2 | 3 | import com.ycw.im.imdistributedcom.protocol.RequestProtocol; 4 | import com.ycw.im.imdistributedserver.handle.ChatHandler; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 8 | import io.netty.handler.codec.protobuf.ProtobufEncoder; 9 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 10 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 11 | import io.netty.handler.timeout.IdleStateHandler; 12 | 13 | /** 14 | * @Author yuchunwei 15 | */ 16 | public class ServerNettyInit extends ChannelInitializer { 17 | @Override 18 | protected void initChannel(Channel channel) throws Exception { 19 | 20 | channel.pipeline() 21 | .addLast(new IdleStateHandler(11, 0, 0)) 22 | // google Protobuf 编解码 23 | .addLast(new ProtobufVarint32FrameDecoder()) 24 | .addLast(new ProtobufDecoder(RequestProtocol.ReqProtocol.getDefaultInstance())) 25 | .addLast(new ProtobufVarint32LengthFieldPrepender()) 26 | .addLast(new ProtobufEncoder()) 27 | .addLast(new ChatHandler()); 28 | } 29 | 30 | public static void main(String[] args) { 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/service/ChatService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.service; 2 | 3 | import com.ycw.im.imdistributedcom.pojo.ChatMsg; 4 | import com.ycw.im.imdistributedcom.protocol.RequestProtocol; 5 | import com.ycw.im.imdistributedserver.dao.ChatDao; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | @Service 13 | public class ChatService { 14 | @Autowired 15 | private ChatDao chatDao; 16 | 17 | public void insertMsg(RequestProtocol.ReqProtocol protocol){ 18 | ChatMsg chatMsg = new ChatMsg(String.valueOf(protocol.getSendId()),String.valueOf(protocol.getRequestId()),protocol.getReqMsg()); 19 | chatDao.insertMsg(chatMsg); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/tool/RegistorZkTool.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.tool; 2 | 3 | import com.ycw.im.imdistributedserver.config.AppConfiguration; 4 | import com.ycw.im.imdistributedserver.util.SpringFactory; 5 | import javafx.application.Application; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Component; 9 | 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | public class RegistorZkTool implements Runnable { 15 | 16 | private static Logger logger = LoggerFactory.getLogger(RegistorZkTool.class); 17 | 18 | private String ip; 19 | private int nettyPort; 20 | private int httpPort; 21 | 22 | 23 | private AppConfiguration config; 24 | 25 | private ZKTool zkTool; 26 | 27 | public RegistorZkTool(String ip, int nettyPort, int httpPort) { 28 | this.ip = ip; 29 | this.httpPort = httpPort; 30 | this.nettyPort = nettyPort; 31 | config = SpringFactory.getBean(AppConfiguration.class); 32 | zkTool = SpringFactory.getBean(ZKTool.class); 33 | } 34 | 35 | 36 | @Override 37 | public void run() { 38 | zkTool.createRootNode(); 39 | if (config.isZkSwitch()) { 40 | String path = config.getZkRoot() + "/ip-" + ip + ":" + httpPort + ":" + nettyPort; 41 | zkTool.createNode(path); 42 | logger.info("服务端注册到zookeeper成功,节点信息为{}", path); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/tool/ZKTool.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.tool; 2 | 3 | import com.ycw.im.imdistributedserver.config.AppConfiguration; 4 | import javafx.application.Application; 5 | import org.I0Itec.zkclient.ZkClient; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | @Component 13 | public class ZKTool { 14 | 15 | @Autowired 16 | private ZkClient zkClient; 17 | 18 | @Autowired 19 | private AppConfiguration config; 20 | 21 | 22 | //写根节点 23 | public void createRootNode() { 24 | boolean exits = zkClient.exists(config.getZkRoot()); 25 | if (exits) { 26 | return; 27 | } 28 | zkClient.createPersistent(config.getZkRoot()); 29 | } 30 | 31 | //创建临时节点 32 | public void createNode(String path) { 33 | zkClient.createEphemeral(path); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/util/SessionChannelHolder.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.util; 2 | 3 | 4 | import com.ycw.im.imdistributedcom.pojo.UserInfo; 5 | import io.netty.channel.socket.nio.NioSocketChannel; 6 | 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | /** 11 | * @Author yuchunwei 12 | */ 13 | public class SessionChannelHolder { 14 | private final static Map channelMap = new ConcurrentHashMap<>(16); 15 | private final static Map SessionMap = new ConcurrentHashMap<>(16); 16 | 17 | 18 | static { 19 | channelMap.put(201903071130L,new NioSocketChannel()); 20 | SessionMap.put(201903071130L,"ycw"); 21 | } 22 | //保存用户及用户名 23 | public static void saveSession(Long userId, String userName) { 24 | SessionMap.put(userId, userName); 25 | } 26 | 27 | public static void removeSession(Long userId) { 28 | SessionMap.remove(userId); 29 | } 30 | 31 | //保存在线channel及删除 32 | public static void putChannel(Long userId, NioSocketChannel channel) { 33 | channelMap.put(userId, channel); 34 | } 35 | 36 | public static NioSocketChannel getChannel(Long userId) { 37 | return channelMap.get(userId); 38 | } 39 | 40 | public static void removeChannel(NioSocketChannel channel) { 41 | channelMap.entrySet().stream().filter(entry -> entry.getValue() == channel).forEach(entry -> channelMap.remove(entry.getKey())); 42 | } 43 | 44 | public static Map getChannelMap() { 45 | return channelMap; 46 | } 47 | 48 | //通过channel获取用户信息 49 | public static UserInfo getUserInfo(NioSocketChannel channel) { 50 | for (Map.Entry map : channelMap.entrySet()) { 51 | if (map.getValue() == channel) { 52 | Long userId = map.getKey(); 53 | String userName = SessionMap.get(userId); 54 | UserInfo userInfo = new UserInfo(userId, userName); 55 | return userInfo; 56 | } 57 | } 58 | return null; 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/util/SpringFactory.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.util; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @Author yuchunwei 10 | * 如果注册到spring容器中的类是实现了ApplicationContextAware接口的话,在 11 | * 加载spring配置文件时,会自动调用setApplicationContext方法,获得springcontent 12 | * 这样做的好处是,可以动态的通过spring容器获得spring容器中的bean 13 | */ 14 | @Component 15 | public class SpringFactory implements ApplicationContextAware { 16 | private static ApplicationContext context; 17 | 18 | public static T getBean(Class clazz) { 19 | return context.getBean(clazz); 20 | } 21 | 22 | public static T getBean(String name, Class clazz) { 23 | return context.getBean(name, clazz); 24 | } 25 | 26 | @Override 27 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 28 | context = applicationContext; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/vo/request/SendMsgReqVo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.vo.request; 2 | 3 | import com.ycw.im.imdistributedcom.vo.req.BaseRequest; 4 | import lombok.Data; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | @Data 12 | public class SendMsgReqVo extends BaseRequest { 13 | 14 | @ApiModelProperty(required = true, value = "msg", example = "hello") 15 | private String msg; 16 | 17 | @ApiModelProperty(required = true, value = "userId", example = "11") 18 | private Long userId; 19 | 20 | @ApiModelProperty(required = true, value = "sendId", example = "11") 21 | private Long sendId; 22 | 23 | @Override 24 | public String toString() { 25 | return "SendMsgReqVO{" + 26 | "msg='" + msg + '\'' + 27 | ", userId=" + userId + '\'' + 28 | ", sendId=" + sendId + 29 | "} " + super.toString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/java/com/ycw/im/imdistributedserver/vo/response/SendMsgResVo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver.vo.response; 2 | 3 | 4 | /** 5 | * @Author yuchunwei 6 | */ 7 | public class SendMsgResVo { 8 | private String msg; 9 | 10 | public String getMsg() { 11 | return msg; 12 | } 13 | 14 | public void setMsg(String msg) { 15 | this.msg = msg; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /im-distributed-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-server/src/main/resources/application.properties -------------------------------------------------------------------------------- /im-distributed-server/src/main/resources/mapper/ChatMsgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | INSERT INTO chat_msg(send_user_id,accept_user_id,msg,sign_flag,create_time) 16 | values(#{sendUserId},#{acceptUserId},#{msg},#{signFlag},#{createTime}) 17 | 18 | -------------------------------------------------------------------------------- /im-distributed-server/src/test/java/com/ycw/im/imdistributedserver/ImDistributedServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedserver; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedServerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /im-distributed-zk/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /im-distributed-zk/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-distributed-zk/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /im-distributed-zk/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/ImDistributedZkApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImDistributedZkApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImDistributedZkApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/cache/ServerCache.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.cache; 2 | 3 | import com.ycw.im.imdistributedzk.util.ZKit; 4 | import com.google.common.cache.LoadingCache; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | /** 14 | * Function: 服务器节点缓存 15 | * 16 | * @author ycw 17 | * : 18 | * @since JDK 1.8 19 | */ 20 | @Component 21 | public class ServerCache { 22 | 23 | 24 | @Autowired 25 | private LoadingCache cache; 26 | 27 | @Autowired 28 | private ZKit zkUtil; 29 | 30 | private AtomicLong index = new AtomicLong(); 31 | 32 | 33 | public void addCache(String key) { 34 | cache.put(key, key); 35 | } 36 | 37 | 38 | /** 39 | * 更新所有缓存/先删除 再新增 40 | * 41 | * @param currentChilds 42 | */ 43 | public void updateCache(List currentChilds) { 44 | cache.invalidateAll(); 45 | for (String currentChild : currentChilds) { 46 | String key = currentChild.split("-")[1]; 47 | addCache(key); 48 | } 49 | } 50 | 51 | 52 | /** 53 | * 获取所有的服务列表 54 | * 55 | * @return 56 | */ 57 | public List getAll() { 58 | 59 | List list = new ArrayList<>(); 60 | 61 | if (cache.size() == 0) { 62 | List allNode = zkUtil.getAllNode(); 63 | for (String node : allNode) { 64 | String key = node.split("-")[1]; 65 | addCache(key); 66 | } 67 | } 68 | for (Map.Entry entry : cache.asMap().entrySet()) { 69 | list.add(entry.getKey()); 70 | } 71 | return list; 72 | 73 | } 74 | 75 | /** 76 | * 选取服务器 77 | * 78 | * @return 79 | */ 80 | public String selectServer() { 81 | List all = getAll(); 82 | if (all.size() == 0) { 83 | throw new RuntimeException("路由列表为空"); 84 | } 85 | Long position = index.incrementAndGet() % all.size(); 86 | if (position < 0) { 87 | position = 0L; 88 | } 89 | 90 | return all.get(position.intValue()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.config; 2 | 3 | import com.ycw.im.imdistributedzk.util.AppConfiguration; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.google.common.cache.CacheLoader; 6 | import com.google.common.cache.LoadingCache; 7 | import org.I0Itec.zkclient.ZkClient; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * Function: 14 | * 15 | * @author ycw 16 | * @since JDK 1.8 17 | */ 18 | @Configuration 19 | public class AppConfig { 20 | 21 | @Autowired 22 | private AppConfiguration appConfiguration; 23 | 24 | @Bean 25 | public ZkClient buildZKClient() { 26 | return new ZkClient(appConfiguration.getZkAddr(), 5000); 27 | } 28 | 29 | 30 | @Bean 31 | public LoadingCache buildCache() { 32 | return CacheBuilder.newBuilder() 33 | .build(new CacheLoader() { 34 | @Override 35 | public String load(String s) throws Exception { 36 | return null; 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.config; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import springfox.documentation.builders.ApiInfoBuilder; 7 | import springfox.documentation.builders.PathSelectors; 8 | import springfox.documentation.builders.RequestHandlerSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | 15 | @Configuration 16 | @EnableSwagger2 17 | /** 是否打开swagger **/ 18 | @ConditionalOnExpression("'${swagger.enable}' == 'true'") 19 | public class SwaggerConfig { 20 | 21 | 22 | @Bean 23 | public Docket createRestApi() { 24 | return new Docket(DocumentationType.SWAGGER_2) 25 | .apiInfo(apiInfo()) 26 | .select() 27 | .apis(RequestHandlerSelectors.basePackage("com.crossoverjie.netty.action.zk.controller")) 28 | .paths(PathSelectors.any()) 29 | .build(); 30 | } 31 | 32 | private ApiInfo apiInfo() { 33 | return new ApiInfoBuilder() 34 | .title("netty-action-zk api") 35 | .description("netty-action-zk api") 36 | .termsOfServiceUrl("https://crossoverJie.top") 37 | .contact("crossoverJie") 38 | .version("1.0.0") 39 | .build(); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.controller; 2 | 3 | 4 | import com.ycw.im.imdistributedzk.cache.ServerCache; 5 | import io.swagger.annotations.ApiOperation; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestMethod; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Function: 16 | * 17 | * @author ycw 18 | * @since JDK 1.8 19 | */ 20 | @Controller 21 | @RequestMapping("/") 22 | public class IndexController { 23 | 24 | 25 | @Autowired 26 | private ServerCache serverCache; 27 | 28 | /** 29 | * 获取所有路由节点 30 | * 31 | * @return 32 | */ 33 | // @ApiOperation("获取所有路由节点") 34 | // @RequestMapping(value = "getAllRoute", method = RequestMethod.POST) 35 | // @ResponseBody() 36 | // public BaseResponse> getAllRoute() { 37 | // BaseResponse> res = new BaseResponse(); 38 | // List all = serverCache.getAll(); 39 | // res.setDataBody(all); 40 | // res.setCode(StatusEnum.SUCCESS.getCode()); 41 | // res.setMessage(StatusEnum.SUCCESS.getMessage()); 42 | // return res; 43 | // } 44 | 45 | /** 46 | * 获取所有路由节点 47 | * 48 | * @return 49 | */ 50 | // @ApiOperation("获取所有路由节点") 51 | // @RequestMapping(value = "getOneOfRoute", method = RequestMethod.POST) 52 | // @ResponseBody() 53 | // public BaseResponse getOneOfRoute() { 54 | // BaseResponse res = new BaseResponse(); 55 | // String server = serverCache.selectServer(); 56 | // res.setDataBody(server); 57 | // res.setCode(StatusEnum.SUCCESS.getCode()); 58 | // res.setMessage(StatusEnum.SUCCESS.getMessage()); 59 | // return res; 60 | // } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/thread/RegistryZK.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.thread; 2 | 3 | import com.ycw.im.imdistributedzk.util.AppConfiguration; 4 | import com.ycw.im.imdistributedzk.util.SpringBeanFactory; 5 | import com.ycw.im.imdistributedzk.util.ZKit; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * Function: 11 | * 12 | * @author ycw 13 | * @since JDK 1.8 14 | */ 15 | public class RegistryZK implements Runnable { 16 | 17 | private static Logger logger = LoggerFactory.getLogger(RegistryZK.class); 18 | 19 | private ZKit zkUtil; 20 | 21 | private AppConfiguration appConfiguration; 22 | 23 | private String ip; 24 | private int port; 25 | 26 | public RegistryZK(String ip, int port) { 27 | this.ip = ip; 28 | this.port = port; 29 | zkUtil = SpringBeanFactory.getBean(ZKit.class); 30 | appConfiguration = SpringBeanFactory.getBean(AppConfiguration.class); 31 | } 32 | 33 | @Override 34 | public void run() { 35 | 36 | //创建父节点 37 | zkUtil.createRootNode(); 38 | 39 | //是否要将自己注册到 ZK 40 | if (appConfiguration.isZkSwitch()) { 41 | String path = appConfiguration.getZkRoot() + "/ip-" + ip + ":" + port; 42 | zkUtil.createNode(path, path); 43 | logger.info("注册 zookeeper 成功,msg=[{}]", path); 44 | } 45 | 46 | //注册监听服务 47 | zkUtil.subscribeEvent(appConfiguration.getZkRoot()); 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/util/AppConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.util; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Component; 5 | 6 | /** 7 | * Function: 8 | * 9 | * @author ycw 10 | * @since JDK 1.8 11 | */ 12 | @Component 13 | public class AppConfiguration { 14 | 15 | @Value("${app.zk.root}") 16 | private String zkRoot; 17 | 18 | @Value("${app.zk.addr}") 19 | private String zkAddr; 20 | 21 | @Value("${app.zk.switch}") 22 | private boolean zkSwitch; 23 | 24 | @Value("${server.port}") 25 | private int port; 26 | 27 | public int getPort() { 28 | return port; 29 | } 30 | 31 | public void setPort(int port) { 32 | this.port = port; 33 | } 34 | 35 | public String getZkRoot() { 36 | return zkRoot; 37 | } 38 | 39 | public void setZkRoot(String zkRoot) { 40 | this.zkRoot = zkRoot; 41 | } 42 | 43 | public String getZkAddr() { 44 | return zkAddr; 45 | } 46 | 47 | public void setZkAddr(String zkAddr) { 48 | this.zkAddr = zkAddr; 49 | } 50 | 51 | public boolean isZkSwitch() { 52 | return zkSwitch; 53 | } 54 | 55 | public void setZkSwitch(boolean zkSwitch) { 56 | this.zkSwitch = zkSwitch; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/java/com/ycw/im/imdistributedzk/util/SpringBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk.util; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public final class SpringBeanFactory implements ApplicationContextAware { 10 | private static ApplicationContext context; 11 | 12 | public static T getBean(Class c) { 13 | return context.getBean(c); 14 | } 15 | 16 | 17 | public static T getBean(String name, Class clazz) { 18 | return context.getBean(name, clazz); 19 | } 20 | 21 | @Override 22 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 23 | context = applicationContext; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /im-distributed-zk/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /im-distributed-zk/src/test/java/com/ycw/im/imdistributedzk/ImDistributedZkApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedzk; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedZkApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /im-netty.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /im-singel/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /nbbuild/ 22 | /dist/ 23 | /nbdist/ 24 | /.nb-gradle/ 25 | /build/ 26 | -------------------------------------------------------------------------------- /im-singel/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /im-singel/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/controller/ChatController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.controller; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 4 | import com.ycw.im.imsingel.Mobilewechat.service.ChatService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | @RestController 13 | @RequestMapping("/c") 14 | public class ChatController { 15 | @Autowired 16 | private ChatService chatService; 17 | 18 | @RequestMapping("/getUnSignMsgs") 19 | public DataResult getUnSignMsgs(String acceptUserId) { 20 | return chatService.queryUnSignMsgs(acceptUserId); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/controller/FriendController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.controller; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.AddFriendRequst; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.HandleFriendRequest; 6 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.UserBo; 7 | import com.ycw.im.imsingel.Mobilewechat.service.FriendService; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | @RestController 15 | @RequestMapping("/f") 16 | public class FriendController { 17 | @Autowired 18 | private FriendService friendService; 19 | 20 | @PostMapping("/addFriendRequest") 21 | public DataResult addFriend(@RequestBody AddFriendRequst requst) { 22 | return friendService.addFriend(requst); 23 | } 24 | 25 | @RequestMapping("/queryFriendRequests") 26 | public DataResult queryRequest(UserBo userBo) { 27 | return friendService.queryFriendRequest(userBo.getUserId()); 28 | } 29 | 30 | //忽略是0 同意是1 31 | @RequestMapping("/operFriendRequest") 32 | public DataResult operFriendRequest(HandleFriendRequest request) { 33 | return friendService.operFriendRequest(request); 34 | } 35 | 36 | @RequestMapping("/myFriends") 37 | public DataResult getAllFriends(String userId) { 38 | return friendService.getAllFriend(userId); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @RestController 10 | public class TestController { 11 | 12 | @RequestMapping("/index") 13 | public String test() { 14 | return "hello netty"; 15 | } 16 | 17 | public static void main(String[] args) { 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.controller; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.Users; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.AddFriendRequst; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.UserBo; 6 | import com.ycw.im.imsingel.Mobilewechat.service.UserService; 7 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | @RestController 15 | @RequestMapping("/u") 16 | public class UserController { 17 | @Autowired 18 | private UserService userService; 19 | 20 | @PostMapping("/login") 21 | public DataResult login(@RequestBody Users users) { 22 | if (isVaild(users.getUsername(), users.getPassword())) { 23 | return DataResult.errorMsg("密码或者用户名不能为空"); 24 | } 25 | return userService.login(users); 26 | } 27 | 28 | @RequestMapping("/register") 29 | public DataResult register(Users users) { 30 | if (isVaild(users.getUsername(), users.getPassword())) { 31 | return DataResult.errorMsg("密码或者用户名不能为空"); 32 | } 33 | DataResult result = userService.queryUsername(users.getUsername()); 34 | if (result.getStatus() != 200) { 35 | return result; 36 | } 37 | return userService.registor(users.getUsername(), users.getPassword()); 38 | } 39 | 40 | @PostMapping("/uploadFace") 41 | public DataResult uploadImage(@RequestBody UserBo userBo) { 42 | return userService.upLoadImage(userBo); 43 | } 44 | 45 | @PostMapping("setNickname") 46 | public DataResult setNickname(@RequestBody UserBo userBo) { 47 | return userService.setNickName(userBo); 48 | } 49 | 50 | @PostMapping("search") 51 | public DataResult searchFriend(@RequestBody AddFriendRequst requst) { 52 | return userService.searchFriend(requst); 53 | } 54 | 55 | 56 | public static boolean isVaild(String username, String password) { 57 | if (username.equals("") || password.equals("")) { 58 | return true; 59 | } 60 | return false; 61 | } 62 | 63 | 64 | public static void main(String[] args) { 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/enums/AddFriendRequstEnum.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.enums; 2 | 3 | /** 4 | * @Author yuchunwei 5 | */ 6 | //无论添加好友的请求是成功还是忽略 都是已经处理的状态 7 | public enum AddFriendRequstEnum { 8 | HANDLED(1, "已经处理"), 9 | UNHANDLED(2, "还没有被处理"), 10 | ISYOURFRIEND(3, "已经是你的好友,无法添加"), 11 | ISYOURSELF(4, "无法添加自己"); 12 | 13 | private int code; 14 | private String message; 15 | 16 | AddFriendRequstEnum(int code, String message) { 17 | this.code = code; 18 | this.message = message; 19 | } 20 | 21 | public int getCode() { 22 | return code; 23 | } 24 | 25 | public String getMessage() { 26 | return message; 27 | } 28 | 29 | public void setCode(int code) { 30 | this.code = code; 31 | } 32 | 33 | public void setMessage(String message) { 34 | this.message = message; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/enums/MsgStateEnum.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.enums; 2 | 3 | public enum MsgStateEnum { 4 | CONNECT(1, " 第一次(或重连)初始化连接"), 5 | CHAT(2, "聊天消息"), 6 | SIGNED(3, "消息签收"), 7 | KEEPALIVE(4, "客户端保持心跳"), 8 | PULL_FRIEND(5, "重新拉取好友"), 9 | CLOSE(6, "close"); 10 | private Integer code; 11 | private String des; 12 | 13 | MsgStateEnum(Integer code, String des) { 14 | this.code = code; 15 | this.des = des; 16 | } 17 | 18 | public void setCode(Integer code) { 19 | this.code = code; 20 | } 21 | 22 | public Integer getCode() { 23 | return code; 24 | } 25 | 26 | public void setDes(String des) { 27 | this.des = des; 28 | } 29 | 30 | public String getDes() { 31 | return des; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/mapper/ChatMsgMapper.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.mapper; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.ChatMsg; 4 | import org.apache.ibatis.annotations.Param; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface ChatMsgMapper { 11 | int insertMsg(ChatMsg chatMsg); 12 | 13 | List queryUnSignMsgs(@Param("acceptUserId") String acceptUserId); 14 | 15 | void updateMsgToSign(List ids); 16 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/mapper/FriendsRequestMapper.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.mapper; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.AddFriendRequst; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.HandleFriendRequest; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.vo.QueryAddFriendRequestVo; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.stereotype.Repository; 8 | 9 | import java.util.List; 10 | 11 | @Repository 12 | public interface FriendsRequestMapper { 13 | 14 | void insertAddFriendRequst(AddFriendRequst requst); 15 | 16 | List queryFriendRequst(@Param("userId") String userId); 17 | 18 | void updateStatus(HandleFriendRequest request); 19 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/mapper/MyFriendsMapper.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.mapper; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.vo.QueryAllFriendVo; 4 | import org.apache.ibatis.annotations.Param; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface MyFriendsMapper { 11 | List selectFriendIds(@Param("userId") String userId); 12 | 13 | void insertFriend(@Param("acceptUserId") String acceptUserId, @Param("sendUserId") String sendUserId); 14 | 15 | List selectFriends(List ids); 16 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/mapper/UsersMapper.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.mapper; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.UserBo; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.vo.UserVoResult; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.Users; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface UsersMapper { 10 | Users queryUsername(String username); 11 | 12 | void registor(String username, String password); 13 | 14 | UserVoResult login(Users users); 15 | 16 | void updateImage(UserBo userBo); 17 | 18 | UserVoResult getUser(UserBo userBo); 19 | 20 | void updateNickName(UserBo userBo); 21 | 22 | UserVoResult selecUserByUserName(String userName); 23 | 24 | 25 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/ChatHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.Context; 5 | import com.ycw.im.imsingel.Mobilewechat.utils.JsonUtils; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | import io.netty.channel.group.ChannelGroup; 9 | import io.netty.channel.group.DefaultChannelGroup; 10 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 11 | import io.netty.util.concurrent.GlobalEventExecutor; 12 | 13 | /** 14 | * @Author yuchunwei 15 | */ 16 | public class ChatHandler extends SimpleChannelInboundHandler { 17 | private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 18 | 19 | @Override 20 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg) throws Exception { 21 | String content = msg.text(); 22 | System.out.println("收到的消息" + content); 23 | DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class); 24 | Context.handle(dataContent, channelHandlerContext.channel()); 25 | 26 | } 27 | 28 | @Override 29 | public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 30 | channels.add(ctx.channel()); 31 | } 32 | 33 | @Override 34 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 35 | System.out.println("有新的channel"); 36 | super.channelActive(ctx); 37 | } 38 | 39 | @Override 40 | public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 41 | System.out.println("有用户被移除"); 42 | super.handlerRemoved(ctx); 43 | } 44 | 45 | public static void main(String[] args) { 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/Initial.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.socket.SocketChannel; 5 | import io.netty.handler.codec.http.HttpObjectAggregator; 6 | import io.netty.handler.codec.http.HttpServerCodec; 7 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 8 | import io.netty.handler.stream.ChunkedWriteHandler; 9 | 10 | /** 11 | * @Author yuchunwei 12 | */ 13 | public class Initial extends ChannelInitializer { 14 | 15 | @Override 16 | protected void initChannel(SocketChannel channel) throws Exception { 17 | channel.pipeline().addLast(new HttpServerCodec()); 18 | channel.pipeline().addLast(new ChunkedWriteHandler()); 19 | channel.pipeline().addLast(new HttpObjectAggregator(1024 * 64)); 20 | 21 | channel.pipeline().addLast(new WebSocketServerProtocolHandler("/ws")); 22 | channel.pipeline().addLast(new ChatHandler()); 23 | } 24 | 25 | public static void main(String[] args) { 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/Server.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | public class Server { 13 | private final static Server INSTANCE = new Server(); 14 | 15 | private EventLoopGroup mainGroup; 16 | private EventLoopGroup subGroup; 17 | private ServerBootstrap server; 18 | private ChannelFuture future; 19 | 20 | private Server() { 21 | mainGroup = new NioEventLoopGroup(); 22 | subGroup = new NioEventLoopGroup(); 23 | server = new ServerBootstrap(); 24 | server.group(mainGroup, subGroup) 25 | .channel(NioServerSocketChannel.class) 26 | .childHandler(new Initial()); 27 | } 28 | 29 | public static Server getInstance() { 30 | return INSTANCE; 31 | } 32 | 33 | public void start(int port) { 34 | future = server.bind(port); 35 | System.err.println("netty server 启动,端口号为" + port); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/UserChannels.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * @Author yuchunwei 9 | */ 10 | 11 | 12 | public class UserChannels { 13 | 14 | private static HashMap manager = new HashMap<>(); 15 | 16 | public static void put(String senderId, Channel channel) { 17 | manager.put(senderId, channel); 18 | } 19 | 20 | public static Channel get(String senderId) { 21 | return manager.get(senderId); 22 | } 23 | 24 | public static void output() { 25 | for (HashMap.Entry entry : manager.entrySet()) { 26 | System.out.println("UserId: " + entry.getKey() 27 | + ", ChannelId: " + entry.getValue().id().asLongText()); 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/pojo/ChatMsgVo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.pojo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class ChatMsgVo { 10 | private static final long serialVersionUID = 3611169682695799175L; 11 | 12 | private String senderId; // 发送者的用户id 13 | private String receiverId; // 接受者的用户id 14 | private String msg; // 聊天内容 15 | private String msgId; // 用于消息的签收 16 | } 17 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/pojo/DataContent.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.pojo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Data 10 | public class DataContent { 11 | private static final long serialVersionUID = 8021381444738260454L; 12 | 13 | private Integer action; // 动作类型 14 | @JsonProperty(value = "ChatMsgVo") 15 | private ChatMsgVo chatMsgVo; // 用户的聊天内容entity 16 | private String extand; // 扩展字段 17 | } 18 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/Context.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 4 | import io.netty.channel.Channel; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | public class Context { 10 | private Strategy strategy; 11 | 12 | public static void handle(DataContent dataContent, Channel curChannel) { 13 | Strategy strategy = StrategyFactory.getInstance().create(dataContent.getAction()); 14 | strategy.handle(dataContent, curChannel); 15 | } 16 | 17 | public Strategy getStrategy() { 18 | return strategy; 19 | } 20 | 21 | public void setStrategy(Strategy strategy) { 22 | this.strategy = strategy; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/Strategy.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 4 | import io.netty.channel.Channel; 5 | 6 | public interface Strategy { 7 | 8 | public void handle(DataContent dataContent, Channel curChannel); 9 | } 10 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/StrategyFactory.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.enums.MsgStateEnum; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.impl.*; 5 | 6 | import java.util.HashMap; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | public class StrategyFactory { 12 | private static StrategyFactory factory = new StrategyFactory(); 13 | 14 | private StrategyFactory() { 15 | } 16 | 17 | private static HashMap map = new HashMap<>(); 18 | 19 | static { 20 | map.put(MsgStateEnum.CONNECT.getCode(), new ConnectStrategy()); 21 | map.put(MsgStateEnum.CHAT.getCode(), new ChatStrategy()); 22 | map.put(MsgStateEnum.CLOSE.getCode(), new CloseStrategy()); 23 | map.put(MsgStateEnum.KEEPALIVE.getCode(), new HeartCheckStrategy()); 24 | map.put(MsgStateEnum.SIGNED.getCode(), new SignStrategy()); 25 | } 26 | 27 | public Strategy create(Integer type) { 28 | return map.get(type); 29 | } 30 | 31 | public static StrategyFactory getInstance() { 32 | return factory; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/impl/ChatStrategy.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy.impl; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.UserChannels; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.ChatMsgVo; 5 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 6 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.Strategy; 7 | import com.ycw.im.imsingel.Mobilewechat.pojo.ChatMsg; 8 | import com.ycw.im.imsingel.Mobilewechat.service.ChatService; 9 | import com.ycw.im.imsingel.Mobilewechat.utils.JsonUtils; 10 | import com.ycw.im.imsingel.Mobilewechat.utils.SpringUtil; 11 | import io.netty.channel.Channel; 12 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 13 | 14 | import java.util.Date; 15 | 16 | /** 17 | * @Author yuchunwei 18 | */ 19 | public class ChatStrategy implements Strategy { 20 | @Override 21 | public void handle(DataContent dataContent, Channel curChannel) { 22 | ChatMsgVo chatMsgVo = dataContent.getChatMsgVo(); 23 | ChatMsg chatMsg = new ChatMsg(); 24 | String msgText = chatMsgVo.getMsg(); 25 | String receiverId = chatMsgVo.getReceiverId(); 26 | String senderId = chatMsgVo.getSenderId(); 27 | 28 | 29 | chatMsg.setAcceptUserId(receiverId); 30 | chatMsg.setSendUserId(senderId); 31 | chatMsg.setMsg(msgText); 32 | chatMsg.setCreateTime(new Date()); 33 | //签收flag 0 -> 未签收 1 -> 已签收 34 | chatMsg.setSignFlag(0); 35 | ChatService chatService = (ChatService) SpringUtil.getBean("chatServiceImpl"); 36 | int msgId = chatService.insertMsg(chatMsg); 37 | chatMsgVo.setMsgId(String.valueOf(msgId)); 38 | Channel receiveChannel = UserChannels.get(senderId); 39 | if (receiveChannel != null) { 40 | receiveChannel.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(chatMsgVo))); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/impl/CloseStrategy.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy.impl; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.UserChannels; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 5 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.Strategy; 6 | import io.netty.channel.Channel; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | public class CloseStrategy implements Strategy { 12 | 13 | @Override 14 | public void handle(DataContent dataContent, Channel curChannel) { 15 | UserChannels.put(dataContent.getExtand(), null); 16 | System.out.println("用户" + dataContent.getExtand() + "被移除"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/impl/ConnectStrategy.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy.impl; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.UserChannels; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.ChatMsgVo; 5 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 6 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.Strategy; 7 | import io.netty.channel.Channel; 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | public class ConnectStrategy implements Strategy { 13 | 14 | @Override 15 | public void handle(DataContent dataContent, Channel curChannel) { 16 | ChatMsgVo chatMsgVo = dataContent.getChatMsgVo(); 17 | UserChannels.put(dataContent.getChatMsgVo().getSenderId(), curChannel); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/impl/HeartCheckStrategy.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy.impl; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.Strategy; 5 | import io.netty.channel.Channel; 6 | 7 | /** 8 | * @Author yuchunwei 9 | */ 10 | public class HeartCheckStrategy implements Strategy { 11 | 12 | 13 | @Override 14 | public void handle(DataContent dataContent, Channel curChannel) { 15 | System.out.println("收到心跳检查"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/netty/strategy/impl/SignStrategy.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.netty.strategy.impl; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.pojo.DataContent; 4 | import com.ycw.im.imsingel.Mobilewechat.netty.strategy.Strategy; 5 | import com.ycw.im.imsingel.Mobilewechat.service.ChatService; 6 | import com.ycw.im.imsingel.Mobilewechat.utils.SpringUtil; 7 | import io.netty.channel.Channel; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | 12 | /** 13 | * @Author yuchunwei 14 | */ 15 | public class SignStrategy implements Strategy { 16 | 17 | 18 | @Override 19 | public void handle(DataContent dataContent, Channel curChannel) { 20 | String unSignedMsgIdStr = dataContent.getExtand(); 21 | List unSignedMsgIds = Arrays.asList(unSignedMsgIdStr.split(",")); 22 | //应该检测一下是否是数字的 23 | if (unSignedMsgIds.size() > 0) { 24 | ChatService chatService = (ChatService) SpringUtil.getBean("chatServiceImpl"); 25 | chatService.updateMsgToSign(unSignedMsgIds); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/plugin/FileConst.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.plugin; 2 | 3 | /** 4 | * @Author yuchunwei 5 | */ 6 | public class FileConst { 7 | /** 8 | * 默认图片的宽度:为一数组,如果为一个元素则必须等于该值才合格,如果为两个值,则为图片宽度应符合的区间值。元素个数最多只可为两个 9 | */ 10 | public static final int[] DEFAULT_IMG_WIDTH = {0, 1366}; 11 | 12 | /** 13 | * 默认图片的高度 14 | */ 15 | public static final int[] DEFAULT_IMG_HEIGHT = {0, 768}; 16 | 17 | /** 18 | * 默认图片的大小:单位B, 52428800B = 51200KB = 50M 19 | */ 20 | public static final int[] DEFAULT_IMG_SIZE = {1024, 52428800}; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/plugin/QiniuUploadType.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.plugin; 2 | 3 | public enum QiniuUploadType { 4 | FACEBIGIMAGE("faceBigImage/", FileConst.DEFAULT_IMG_WIDTH, FileConst.DEFAULT_IMG_HEIGHT, FileConst.DEFAULT_IMG_SIZE), 5 | FACEIMAGE("faceImage/", FileConst.DEFAULT_IMG_WIDTH, FileConst.DEFAULT_IMG_HEIGHT, FileConst.DEFAULT_IMG_SIZE), 6 | QRCODE("qrcode/", FileConst.DEFAULT_IMG_WIDTH, FileConst.DEFAULT_IMG_HEIGHT, FileConst.DEFAULT_IMG_SIZE); 7 | 8 | private String path; 9 | /** 10 | * 上传图片的宽度 11 | */ 12 | private int[] width; 13 | /** 14 | * 上传图片的高度 15 | */ 16 | private int[] height; 17 | /** 18 | * 上传图片的大小 19 | */ 20 | private int[] size; 21 | 22 | QiniuUploadType(String path, int[] width, int[] height, int[] size) { 23 | this.path = path; 24 | this.width = width; 25 | this.height = height; 26 | this.size = size; 27 | } 28 | 29 | public String getPath() { 30 | 31 | return path; 32 | } 33 | 34 | public int[] getWidth() { 35 | return width; 36 | } 37 | 38 | public int[] getHeight() { 39 | return height; 40 | } 41 | 42 | public int[] getSize() { 43 | return size; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/ChatMsg.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo; 2 | 3 | 4 | import javax.persistence.Column; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | import java.util.Date; 8 | 9 | @Table(name = "chat_msg") 10 | public class ChatMsg { 11 | @Id 12 | private String id; 13 | 14 | @Column(name = "send_user_id") 15 | private String sendUserId; 16 | 17 | @Column(name = "accept_user_id") 18 | private String acceptUserId; 19 | 20 | private String msg; 21 | 22 | @Column(name = "sign_flag") 23 | private Integer signFlag; 24 | 25 | @Column(name = "create_time") 26 | private Date createTime; 27 | 28 | /** 29 | * @return id 30 | */ 31 | public String getId() { 32 | return id; 33 | } 34 | 35 | /** 36 | * @param id 37 | */ 38 | public void setId(String id) { 39 | this.id = id; 40 | } 41 | 42 | /** 43 | * @return send_user_id 44 | */ 45 | public String getSendUserId() { 46 | return sendUserId; 47 | } 48 | 49 | /** 50 | * @param sendUserId 51 | */ 52 | public void setSendUserId(String sendUserId) { 53 | this.sendUserId = sendUserId; 54 | } 55 | 56 | /** 57 | * @return accept_user_id 58 | */ 59 | public String getAcceptUserId() { 60 | return acceptUserId; 61 | } 62 | 63 | /** 64 | * @param acceptUserId 65 | */ 66 | public void setAcceptUserId(String acceptUserId) { 67 | this.acceptUserId = acceptUserId; 68 | } 69 | 70 | /** 71 | * @return msg 72 | */ 73 | public String getMsg() { 74 | return msg; 75 | } 76 | 77 | /** 78 | * @param msg 79 | */ 80 | public void setMsg(String msg) { 81 | this.msg = msg; 82 | } 83 | 84 | /** 85 | * @return sign_flag 86 | */ 87 | public Integer getSignFlag() { 88 | return signFlag; 89 | } 90 | 91 | /** 92 | * @param signFlag 93 | */ 94 | public void setSignFlag(Integer signFlag) { 95 | this.signFlag = signFlag; 96 | } 97 | 98 | /** 99 | * @return create_time 100 | */ 101 | public Date getCreateTime() { 102 | return createTime; 103 | } 104 | 105 | /** 106 | * @param createTime 107 | */ 108 | public void setCreateTime(Date createTime) { 109 | this.createTime = createTime; 110 | } 111 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/FriendsRequest.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Id; 5 | import javax.persistence.Table; 6 | import java.util.Date; 7 | 8 | @Table(name = "friends_request") 9 | public class FriendsRequest { 10 | @Id 11 | private String id; 12 | 13 | @Column(name = "send_user_id") 14 | private String sendUserId; 15 | 16 | @Column(name = "accept_user_id") 17 | private String acceptUserId; 18 | 19 | @Column(name = "request_time") 20 | private Date requestTime; 21 | 22 | /** 23 | * @return id 24 | */ 25 | public String getId() { 26 | return id; 27 | } 28 | 29 | /** 30 | * @param id 31 | */ 32 | public void setId(String id) { 33 | this.id = id; 34 | } 35 | 36 | /** 37 | * @return send_user_id 38 | */ 39 | public String getSendUserId() { 40 | return sendUserId; 41 | } 42 | 43 | /** 44 | * @param sendUserId 45 | */ 46 | public void setSendUserId(String sendUserId) { 47 | this.sendUserId = sendUserId; 48 | } 49 | 50 | /** 51 | * @return accept_user_id 52 | */ 53 | public String getAcceptUserId() { 54 | return acceptUserId; 55 | } 56 | 57 | /** 58 | * @param acceptUserId 59 | */ 60 | public void setAcceptUserId(String acceptUserId) { 61 | this.acceptUserId = acceptUserId; 62 | } 63 | 64 | /** 65 | * @return request_time 66 | */ 67 | public Date getRequestTime() { 68 | return requestTime; 69 | } 70 | 71 | /** 72 | * @param requestTime 73 | */ 74 | public void setRequestTime(Date requestTime) { 75 | this.requestTime = requestTime; 76 | } 77 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/MyFriends.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Id; 5 | import javax.persistence.Table; 6 | 7 | @Table(name = "my_friends") 8 | public class MyFriends { 9 | @Id 10 | private String id; 11 | 12 | @Column(name = "my_user_id") 13 | private String myUserId; 14 | 15 | @Column(name = "my_friend_user_id") 16 | private String myFriendUserId; 17 | 18 | /** 19 | * @return id 20 | */ 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | /** 26 | * @param id 27 | */ 28 | public void setId(String id) { 29 | this.id = id; 30 | } 31 | 32 | /** 33 | * @return my_user_id 34 | */ 35 | public String getMyUserId() { 36 | return myUserId; 37 | } 38 | 39 | /** 40 | * @param myUserId 41 | */ 42 | public void setMyUserId(String myUserId) { 43 | this.myUserId = myUserId; 44 | } 45 | 46 | /** 47 | * @return my_friend_user_id 48 | */ 49 | public String getMyFriendUserId() { 50 | return myFriendUserId; 51 | } 52 | 53 | /** 54 | * @param myFriendUserId 55 | */ 56 | public void setMyFriendUserId(String myFriendUserId) { 57 | this.myFriendUserId = myFriendUserId; 58 | } 59 | } -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/bo/AddFriendRequst.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo.bo; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.enums.AddFriendRequstEnum; 4 | import lombok.Data; 5 | 6 | /** 7 | * @Author yuchunwei 8 | */ 9 | @Data 10 | public class AddFriendRequst { 11 | private String myUserId; 12 | private String friendUsername; 13 | private String friendId; 14 | private String date; 15 | private int status = AddFriendRequstEnum.UNHANDLED.getCode(); 16 | } 17 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/bo/HandleFriendRequest.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo.bo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class HandleFriendRequest { 10 | private String acceptUserId; 11 | private String sendUserId; 12 | private String operType; 13 | private int status; 14 | } 15 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/bo/UserBo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo.bo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class UserBo { 10 | private String userId; 11 | private String faceData; 12 | private String nickname; 13 | } 14 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/vo/QueryAddFriendRequestVo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class QueryAddFriendRequestVo { 10 | private String sendUserId; 11 | private String sendNickname; 12 | private String sendFaceImage; 13 | } 14 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/vo/QueryAllFriendVo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class QueryAllFriendVo { 10 | private String friendUserId; 11 | private String friendNickname; 12 | private String friendFaceImage; 13 | } 14 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/pojo/vo/UserVoResult.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.pojo.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @Author yuchunwei 7 | */ 8 | @Data 9 | public class UserVoResult { 10 | private String username; 11 | private String faceImage; 12 | private String faceImageBig; 13 | private String nickname; 14 | private String qrcode; 15 | private String userId; 16 | } 17 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/service/ChatService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.service; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.ChatMsg; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 5 | 6 | import java.util.List; 7 | 8 | public interface ChatService { 9 | int insertMsg(ChatMsg msg); 10 | 11 | DataResult queryUnSignMsgs(String accpetId); 12 | 13 | void updateMsgToSign(List ids); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/service/FriendService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.service; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.AddFriendRequst; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.HandleFriendRequest; 6 | 7 | /** 8 | * @Author yuchunwei 9 | */ 10 | public interface FriendService { 11 | DataResult addFriend(AddFriendRequst requst); 12 | 13 | DataResult queryFriendRequest(String userId); 14 | 15 | DataResult operFriendRequest(HandleFriendRequest request); 16 | 17 | DataResult getAllFriend(String userId); 18 | } 19 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.service; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.pojo.Users; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.AddFriendRequst; 6 | import com.ycw.im.imsingel.Mobilewechat.pojo.bo.UserBo; 7 | 8 | public interface UserService { 9 | DataResult queryUsername(String username); 10 | 11 | DataResult registor(String username, String password); 12 | 13 | DataResult login(Users users); 14 | 15 | DataResult upLoadImage(UserBo userBo); 16 | 17 | DataResult setNickName(UserBo userBo); 18 | 19 | DataResult searchFriend(AddFriendRequst requst); 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/service/impl/ChatServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.service.impl; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.mapper.ChatMsgMapper; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.ChatMsg; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 6 | import com.ycw.im.imsingel.Mobilewechat.service.ChatService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author yuchunwei 14 | */ 15 | @Service 16 | public class ChatServiceImpl implements ChatService { 17 | @Autowired 18 | private ChatMsgMapper msgMapper; 19 | 20 | @Override 21 | public DataResult queryUnSignMsgs(String acceptUserId) { 22 | List chatMsgs = msgMapper.queryUnSignMsgs(acceptUserId); 23 | return DataResult.ok(chatMsgs); 24 | } 25 | 26 | @Override 27 | public int insertMsg(ChatMsg msg) { 28 | return msgMapper.insertMsg(msg); 29 | } 30 | 31 | @Override 32 | public void updateMsgToSign(List ids) { 33 | msgMapper.updateMsgToSign(ids); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.utils; 2 | 3 | import java.util.List; 4 | 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import com.fasterxml.jackson.databind.JavaType; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | 9 | /** 10 | * @Description: 自定义响应结构, 转换类 11 | */ 12 | public class JsonUtils { 13 | 14 | // 定义jackson对象 15 | private static final ObjectMapper MAPPER = new ObjectMapper(); 16 | 17 | /** 18 | * 将对象转换成json字符串。 19 | *

Title: pojoToJson

20 | *

Description:

21 | * 22 | * @param data 23 | * @return 24 | */ 25 | public static String objectToJson(Object data) { 26 | try { 27 | String string = MAPPER.writeValueAsString(data); 28 | return string; 29 | } catch (JsonProcessingException e) { 30 | e.printStackTrace(); 31 | } 32 | return null; 33 | } 34 | 35 | /** 36 | * 将json结果集转化为对象 37 | * 38 | * @param jsonData json数据 39 | * @param clazz 对象中的object类型 40 | * @return 41 | */ 42 | public static T jsonToPojo(String jsonData, Class beanType) { 43 | try { 44 | T t = MAPPER.readValue(jsonData, beanType); 45 | return t; 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | return null; 50 | } 51 | 52 | /** 53 | * 将json数据转换成pojo对象list 54 | *

Title: jsonToList

55 | *

Description:

56 | * 57 | * @param jsonData 58 | * @param beanType 59 | * @return 60 | */ 61 | public static List jsonToList(String jsonData, Class beanType) { 62 | JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); 63 | try { 64 | List list = MAPPER.readValue(jsonData, javaType); 65 | return list; 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | 70 | return null; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/utils/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.utils; 2 | 3 | import org.apache.tomcat.util.codec.binary.Base64; 4 | 5 | import java.security.MessageDigest; 6 | 7 | 8 | public class MD5Utils { 9 | 10 | /** 11 | * @Description: 对字符串进行md5加密 12 | */ 13 | public static String getMD5Str(String strValue) throws Exception { 14 | MessageDigest md5 = MessageDigest.getInstance("MD5"); 15 | String newstr = Base64.encodeBase64String(md5.digest(strValue.getBytes())); 16 | return newstr; 17 | } 18 | 19 | public static void main(String[] args) { 20 | try { 21 | String md5 = getMD5Str("hello everything"); 22 | System.out.println(md5); 23 | } catch (Exception e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Mobilewechat/utils/SpringUtil.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Mobilewechat.utils; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * @Description: 提供手动获取被spring管理的bean对象 10 | */ 11 | @Component 12 | public class SpringUtil implements ApplicationContextAware { 13 | 14 | private static ApplicationContext applicationContext; 15 | 16 | @Override 17 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 18 | if (SpringUtil.applicationContext == null) { 19 | SpringUtil.applicationContext = applicationContext; 20 | } 21 | } 22 | 23 | // 获取applicationContext 24 | public static ApplicationContext getApplicationContext() { 25 | return applicationContext; 26 | } 27 | 28 | // 通过name获取 Bean. 29 | public static Object getBean(String name) { 30 | return getApplicationContext().getBean(name); 31 | } 32 | 33 | // 通过class获取Bean. 34 | public static T getBean(Class clazz) { 35 | return getApplicationContext().getBean(clazz); 36 | } 37 | 38 | // 通过name,以及Clazz返回指定的Bean 39 | public static T getBean(String name, Class clazz) { 40 | return getApplicationContext().getBean(name, clazz); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/NettyBoots.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.netty.Server; 4 | import com.ycw.im.imsingel.Webwechat.web.websocket.WebSocketServer; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.context.event.ContextRefreshedEvent; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author yuchunwei 14 | * 在springboot上下文启动期间,启动netty服务器 15 | */ 16 | @Component 17 | public class NettyBoots implements ApplicationListener { 18 | @Autowired 19 | private WebSocketServer webNettyServer; 20 | 21 | @Override 22 | public void onApplicationEvent(ContextRefreshedEvent event) { 23 | 24 | if (event.getApplicationContext().getParent() == null) { 25 | try { 26 | Server.getInstance().start(8088); 27 | // webNettyServer.build(3333); 28 | } catch (Exception e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/WebApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | @SpringBootApplication 13 | //@ComponentScan({"com.blog"}) 14 | //@ServletComponentScan 15 | @MapperScan(basePackages = "com.ycw.im.imsingel.Mobilewechat.mapper") 16 | @EnableAutoConfiguration 17 | public class WebApplication { 18 | public static void main(String[] args) { 19 | SpringApplication.run(WebApplication.class, args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/dao/GroupInfoDao.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.dao; 2 | 3 | 4 | import com.ycw.im.imsingel.Webwechat.model.po.GroupInfo; 5 | 6 | public interface GroupInfoDao { 7 | 8 | void loadGroupInfo(); 9 | 10 | GroupInfo getByGroupId(String groupId); 11 | } 12 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/dao/UserInfoDao.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.dao; 2 | 3 | import com.ycw.im.imsingel.Webwechat.model.po.UserInfo; 4 | 5 | public interface UserInfoDao { 6 | 7 | void loadUserInfo(); 8 | 9 | UserInfo getByUsername(String username); 10 | 11 | UserInfo getByUserId(String userId); 12 | } 13 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/dao/impl/GroupInfoDaoImpl.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.dao.impl; 2 | 3 | import org.springframework.stereotype.Repository; 4 | import com.ycw.im.imsingel.Webwechat.dao.GroupInfoDao; 5 | import com.ycw.im.imsingel.Webwechat.model.po.GroupInfo; 6 | import com.ycw.im.imsingel.Webwechat.model.po.UserInfo; 7 | import com.ycw.im.imsingel.Webwechat.util.Constant; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | @Repository 13 | public class GroupInfoDaoImpl implements GroupInfoDao { 14 | 15 | @Override 16 | public void loadGroupInfo() { 17 | UserInfo userInfo = new UserInfo("001", "Member001", "001", "static/img/avatar/Member001.jpg"); 18 | UserInfo userInfo2 = new UserInfo("002", "Member002", "002", "static/img/avatar/Member002.jpg"); 19 | UserInfo userInfo3 = new UserInfo("003", "Member003", "003", "static/img/avatar/Member003.jpg"); 20 | UserInfo userInfo4 = new UserInfo("004", "Member004", "004", "static/img/avatar/Member004.jpg"); 21 | UserInfo userInfo5 = new UserInfo("005", "Member005", "005", "static/img/avatar/Member005.jpg"); 22 | UserInfo userInfo6 = new UserInfo("006", "Member006", "006", "static/img/avatar/Member006.jpg"); 23 | UserInfo userInfo7 = new UserInfo("007", "Member007", "007", "static/img/avatar/Member007.jpg"); 24 | UserInfo userInfo8 = new UserInfo("008", "Member008", "008", "static/img/avatar/Member008.jpg"); 25 | UserInfo userInfo9 = new UserInfo("009", "Member009", "009", "static/img/avatar/Member009.jpg"); 26 | List members = new ArrayList(); 27 | members.add(userInfo); 28 | members.add(userInfo2); 29 | members.add(userInfo3); 30 | members.add(userInfo4); 31 | members.add(userInfo5); 32 | members.add(userInfo6); 33 | members.add(userInfo7); 34 | members.add(userInfo8); 35 | members.add(userInfo9); 36 | GroupInfo groupInfo = new GroupInfo("01", "Group01", "static/img/avatar/Group01.jpg", members); 37 | Constant.groupInfoMap.put(groupInfo.getGroupId(), groupInfo); 38 | } 39 | 40 | @Override 41 | public GroupInfo getByGroupId(String groupId) { 42 | return Constant.groupInfoMap.get(groupId); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/model/po/GroupInfo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.model.po; 2 | 3 | import java.util.List; 4 | 5 | public class GroupInfo { 6 | 7 | private String groupId; 8 | private String groupName; 9 | private String groupAvatarUrl; 10 | private List members; 11 | 12 | public GroupInfo(String groupId, String groupName, String groupAvatarUrl, List members) { 13 | super(); 14 | this.groupId = groupId; 15 | this.groupName = groupName; 16 | this.groupAvatarUrl = groupAvatarUrl; 17 | this.members = members; 18 | } 19 | 20 | public String getGroupId() { 21 | return groupId; 22 | } 23 | 24 | public void setGroupId(String groupId) { 25 | this.groupId = groupId; 26 | } 27 | 28 | public List getMembers() { 29 | return members; 30 | } 31 | 32 | public void setMembers(List members) { 33 | this.members = members; 34 | } 35 | 36 | public String getGroupName() { 37 | return groupName; 38 | } 39 | 40 | public void setGroupName(String groupName) { 41 | this.groupName = groupName; 42 | } 43 | 44 | public String getGroupAvatarUrl() { 45 | return groupAvatarUrl; 46 | } 47 | 48 | public void setGroupAvatarUrl(String groupAvatarUrl) { 49 | this.groupAvatarUrl = groupAvatarUrl; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/model/po/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.model.po; 2 | 3 | import java.util.List; 4 | 5 | public class UserInfo { 6 | 7 | private String userId; 8 | private String username; 9 | private String password; 10 | private String avatarUrl; 11 | private List friendList; 12 | private List groupList; 13 | 14 | public UserInfo() { 15 | super(); 16 | } 17 | 18 | public UserInfo(String userId, String username, String password, String avatarUrl) { 19 | super(); 20 | this.userId = userId; 21 | this.username = username; 22 | this.password = password; 23 | this.avatarUrl = avatarUrl; 24 | } 25 | 26 | public String getUserId() { 27 | return userId; 28 | } 29 | 30 | public void setUserId(String userId) { 31 | this.userId = userId; 32 | } 33 | 34 | public String getUsername() { 35 | return username; 36 | } 37 | 38 | public void setUsername(String username) { 39 | this.username = username; 40 | } 41 | 42 | public String getPassword() { 43 | return password; 44 | } 45 | 46 | public void setPassword(String password) { 47 | this.password = password; 48 | } 49 | 50 | public String getAvatarUrl() { 51 | return avatarUrl; 52 | } 53 | 54 | public void setAvatarUrl(String avatarUrl) { 55 | this.avatarUrl = avatarUrl; 56 | } 57 | 58 | public List getFriendList() { 59 | return friendList; 60 | } 61 | 62 | public void setFriendList(List friendList) { 63 | this.friendList = friendList; 64 | } 65 | 66 | public List getGroupList() { 67 | return groupList; 68 | } 69 | 70 | public void setGroupList(List groupList) { 71 | this.groupList = groupList; 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/model/vo/ResponseJson.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.model.vo; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import org.springframework.http.HttpStatus; 5 | 6 | import java.util.HashMap; 7 | 8 | public class ResponseJson extends HashMap { 9 | private static final long serialVersionUID = 1L; 10 | 11 | private static final Integer SUCCESS_STATUS = 200; 12 | private static final Integer ERROR_STATUS = -1; 13 | private static final String SUCCESS_MSG = "一切正常"; 14 | 15 | public ResponseJson() { 16 | super(); 17 | } 18 | 19 | public ResponseJson(int code) { 20 | super(); 21 | setStatus(code); 22 | } 23 | 24 | public ResponseJson(HttpStatus status) { 25 | super(); 26 | setStatus(status.value()); 27 | setMsg(status.getReasonPhrase()); 28 | } 29 | 30 | public ResponseJson success() { 31 | put("msg", SUCCESS_MSG); 32 | put("status", SUCCESS_STATUS); 33 | return this; 34 | } 35 | 36 | public ResponseJson success(String msg) { 37 | put("msg", msg); 38 | put("status", SUCCESS_STATUS); 39 | return this; 40 | } 41 | 42 | public ResponseJson error(String msg) { 43 | put("msg", msg); 44 | put("status", ERROR_STATUS); 45 | return this; 46 | } 47 | 48 | public ResponseJson setData(String key, Object obj) { 49 | @SuppressWarnings("unchecked") 50 | HashMap data = (HashMap) get("data"); 51 | if (data == null) { 52 | data = new HashMap(); 53 | put("data", data); 54 | } 55 | data.put(key, obj); 56 | return this; 57 | } 58 | 59 | public ResponseJson setStatus(int status) { 60 | put("status", status); 61 | return this; 62 | } 63 | 64 | public ResponseJson setMsg(String msg) { 65 | put("msg", msg); 66 | return this; 67 | } 68 | 69 | public ResponseJson setValue(String key, Object val) { 70 | put(key, val); 71 | return this; 72 | } 73 | 74 | /** 75 | * 返回JSON字符串 76 | */ 77 | @Override 78 | public String toString() { 79 | return JSONObject.toJSONString(this); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/ChatService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | public interface ChatService { 7 | 8 | public void register(JSONObject param, ChannelHandlerContext ctx); 9 | 10 | public void singleSend(JSONObject param, ChannelHandlerContext ctx); 11 | 12 | public void groupSend(JSONObject param, ChannelHandlerContext ctx); 13 | 14 | public void FileMsgSingleSend(JSONObject param, ChannelHandlerContext ctx); 15 | 16 | public void FileMsgGroupSend(JSONObject param, ChannelHandlerContext ctx); 17 | 18 | public void remove(ChannelHandlerContext ctx); 19 | 20 | public void typeError(ChannelHandlerContext ctx); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/FileUploadService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service; 2 | 3 | import org.springframework.web.multipart.MultipartFile; 4 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | 8 | public interface FileUploadService { 9 | 10 | ResponseJson upload(MultipartFile file, HttpServletRequest request); 11 | } 12 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/SecurityService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service; 2 | 3 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 4 | 5 | import javax.servlet.http.HttpSession; 6 | 7 | public interface SecurityService { 8 | 9 | ResponseJson login(String username, String password, HttpSession session); 10 | 11 | ResponseJson logout(HttpSession session); 12 | } 13 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/UserInfoService.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service; 2 | 3 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 4 | 5 | public interface UserInfoService { 6 | 7 | ResponseJson getByUserId(String userId); 8 | } 9 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/impl/FileUploadServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | import org.springframework.web.multipart.MultipartFile; 5 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 6 | import com.ycw.im.imsingel.Webwechat.service.FileUploadService; 7 | import com.ycw.im.imsingel.Webwechat.util.FileUtils; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.io.IOException; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | import java.nio.file.Paths; 14 | import java.util.UUID; 15 | 16 | @Service 17 | public class FileUploadServiceImpl implements FileUploadService { 18 | 19 | private final static String SERVER_URL_PREFIX = "http://localhost:8080/WebSocket/"; 20 | private final static String FILE_STORE_PATH = "UploadFile"; 21 | 22 | @Override 23 | public ResponseJson upload(MultipartFile file, HttpServletRequest request) { 24 | // 重命名文件,防止重名 25 | String filename = getRandomUUID(); 26 | String suffix = ""; 27 | String originalFilename = file.getOriginalFilename(); 28 | String fileSize = FileUtils.getFormatSize(file.getSize()); 29 | // 截取文件的后缀名 30 | if (originalFilename.contains(".")) { 31 | suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); 32 | } 33 | filename = filename + suffix; 34 | String prefix = request.getSession().getServletContext().getRealPath("/") + FILE_STORE_PATH; 35 | System.out.println("存储路径为:" + prefix + "\\" + filename); 36 | Path filePath = Paths.get(prefix, filename); 37 | try { 38 | Files.copy(file.getInputStream(), filePath); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | return new ResponseJson().error("文件上传发生错误!"); 42 | } 43 | return new ResponseJson().success() 44 | .setData("originalFilename", originalFilename) 45 | .setData("fileSize", fileSize) 46 | .setData("fileUrl", SERVER_URL_PREFIX + FILE_STORE_PATH + "\\" + filename); 47 | } 48 | 49 | private String getRandomUUID() { 50 | return UUID.randomUUID().toString().replace("-", ""); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/impl/SecurityServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service.impl; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import com.ycw.im.imsingel.Webwechat.dao.UserInfoDao; 8 | import com.ycw.im.imsingel.Webwechat.model.po.UserInfo; 9 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 10 | import com.ycw.im.imsingel.Webwechat.service.SecurityService; 11 | import com.ycw.im.imsingel.Webwechat.util.Constant; 12 | 13 | import javax.servlet.http.HttpSession; 14 | import java.text.MessageFormat; 15 | 16 | @Service 17 | public class SecurityServiceImpl implements SecurityService { 18 | 19 | @Autowired 20 | private UserInfoDao userInfoDao; 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(SecurityServiceImpl.class); 23 | 24 | 25 | @Override 26 | public ResponseJson login(String username, String password, HttpSession session) { 27 | UserInfo userInfo = userInfoDao.getByUsername(username); 28 | if (userInfo == null) { 29 | return new ResponseJson().error("不存在该用户名"); 30 | } 31 | if (!userInfo.getPassword().equals(password)) { 32 | return new ResponseJson().error("密码不正确"); 33 | } 34 | session.setAttribute(Constant.USER_TOKEN, userInfo.getUserId()); 35 | return new ResponseJson().success(); 36 | } 37 | 38 | @Override 39 | public ResponseJson logout(HttpSession session) { 40 | Object userId = session.getAttribute(Constant.USER_TOKEN); 41 | if (userId == null) { 42 | return new ResponseJson().error("请先登录!"); 43 | } 44 | session.removeAttribute(Constant.USER_TOKEN); 45 | LOGGER.info(MessageFormat.format("userId为 {0} 的用户已注销登录!", userId)); 46 | return new ResponseJson().success(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/service/impl/UserInfoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.service.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | import com.ycw.im.imsingel.Webwechat.dao.UserInfoDao; 6 | import com.ycw.im.imsingel.Webwechat.model.po.UserInfo; 7 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 8 | import com.ycw.im.imsingel.Webwechat.service.UserInfoService; 9 | 10 | @Service 11 | public class UserInfoServiceImpl implements UserInfoService { 12 | 13 | @Autowired 14 | private UserInfoDao userInfoDao; 15 | 16 | @Override 17 | public ResponseJson getByUserId(String userId) { 18 | UserInfo userInfo = userInfoDao.getByUserId(userId); 19 | return new ResponseJson().success() 20 | .setData("userInfo", userInfo); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/util/ChatType.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.util; 2 | 3 | public enum ChatType { 4 | 5 | REGISTER, SINGLE_SENDING, GROUP_SENDING, FILE_MSG_SINGLE_SENDING, FILE_MSG_GROUP_SENDING; 6 | 7 | public static void main(String[] args) { 8 | System.out.println(ChatType.REGISTER); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/util/Constant.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.util; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; 5 | import com.ycw.im.imsingel.Webwechat.model.po.GroupInfo; 6 | import com.ycw.im.imsingel.Webwechat.model.po.UserInfo; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * 描述: 全局常量 14 | * 1. USER_TOKEN 用户认证的键,用来匹配http session中的对应userId; 15 | * 2. webSocketServerHandshaker表,用channelId为键,存放握手实例。用来响应CloseWebSocketFrame的请求; 16 | * 3. onlineUser表,用userId为键,存放在线的客户端连接上下文; 17 | * 4. groupInfo表,用groupId为键,存放群信息; 18 | * 5. userInfo表,用username为键,存放用户信息。 19 | * 20 | * @author Kanarien 21 | * @version 1.0 22 | * @date 2018年5月18日 下午9:17:35 23 | */ 24 | public class Constant { 25 | 26 | public static final String USER_TOKEN = "userId"; 27 | 28 | public static Map webSocketHandshakerMap = 29 | new ConcurrentHashMap(); 30 | 31 | public static Map onlineUserMap = 32 | new ConcurrentHashMap(); 33 | 34 | public static Map groupInfoMap = 35 | new ConcurrentHashMap(); 36 | 37 | public static Map userInfoMap = 38 | new HashMap(); 39 | } 40 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/util/JsonMsgHelper.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.util; 2 | 3 | import com.fasterxml.jackson.core.JsonGenerationException; 4 | import com.fasterxml.jackson.databind.JsonMappingException; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.http.HttpStatus; 7 | 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.io.IOException; 10 | import java.io.Writer; 11 | 12 | public class JsonMsgHelper { 13 | 14 | private static final ObjectMapper JSONMAPPER = new ObjectMapper(); 15 | 16 | public static void writeJson(HttpServletResponse response, Object pojo, HttpStatus status) 17 | throws JsonGenerationException, JsonMappingException, IOException { 18 | response.setContentType("application/json;charset=UTF-8"); 19 | response.setStatus(status.value()); 20 | writeJson(response.getWriter(), pojo); 21 | } 22 | 23 | public static void writeJson(Writer writer, Object pojo) 24 | throws JsonGenerationException, JsonMappingException, IOException { 25 | JSONMAPPER.writeValue(writer, pojo); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/web/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.web.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | @Configuration 12 | public abstract class WebConfig implements WebMvcConfigurer { 13 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 14 | registry.addResourceHandler("/public/**").addResourceLocations("classpath:/public/"); 15 | registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/web/controller/ChatroomController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.web.controller; 2 | 3 | 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 10 | import com.ycw.im.imsingel.Webwechat.service.UserInfoService; 11 | import com.ycw.im.imsingel.Webwechat.util.Constant; 12 | import org.springframework.web.servlet.ModelAndView; 13 | 14 | import javax.servlet.http.HttpSession; 15 | 16 | @Controller 17 | public class ChatroomController { 18 | 19 | @Autowired 20 | UserInfoService userInfoService; 21 | 22 | /** 23 | * 描述:登录成功后,调用此接口进行页面跳转 24 | * 25 | * @return 26 | */ 27 | @RequestMapping(value = "/chatroom") 28 | public ModelAndView toChatroom(HttpSession session) { 29 | Object userId = session.getAttribute(Constant.USER_TOKEN); 30 | if (userId == null) return new ModelAndView("login.html"); 31 | return new ModelAndView("chatroom.html"); 32 | } 33 | 34 | /** 35 | * 描述:登录成功跳转页面后,调用此接口获取用户信息 36 | * 37 | * @return 38 | */ 39 | @RequestMapping(value = "/chatroom/get_userinfo", method = RequestMethod.POST) 40 | @ResponseBody 41 | public ResponseJson getUserInfo(HttpSession session) { 42 | Object userId = session.getAttribute(Constant.USER_TOKEN); 43 | return userInfoService.getByUserId((String) userId); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/web/controller/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.web.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | import org.springframework.web.multipart.MultipartFile; 9 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 10 | import com.ycw.im.imsingel.Webwechat.service.FileUploadService; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | import static org.springframework.web.bind.annotation.RequestMethod.POST; 15 | 16 | @Controller 17 | @RequestMapping("/chatroom") 18 | public class FileUploadController { 19 | 20 | @Autowired 21 | private FileUploadService fileUploadService; 22 | 23 | @RequestMapping(value = "/upload", method = POST) 24 | @ResponseBody 25 | public ResponseJson upload( 26 | @RequestParam(value = "file", required = true) MultipartFile file, HttpServletRequest request) { 27 | return fileUploadService.upload(file, request); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/web/controller/LoginController.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.web.controller; 2 | 3 | import com.ycw.im.imsingel.Mobilewechat.controller.UserController; 4 | import com.ycw.im.imsingel.Mobilewechat.pojo.DataResult; 5 | import com.ycw.im.imsingel.Mobilewechat.pojo.Users; 6 | import com.ycw.im.imsingel.Mobilewechat.service.UserService; 7 | import com.ycw.im.imsingel.Webwechat.service.impl.SecurityServiceImpl; 8 | import com.ycw.im.imsingel.Webwechat.util.Constant; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Controller; 13 | import org.springframework.ui.Model; 14 | import org.springframework.web.bind.annotation.*; 15 | import com.ycw.im.imsingel.Webwechat.model.vo.ResponseJson; 16 | import com.ycw.im.imsingel.Webwechat.service.SecurityService; 17 | import org.springframework.web.servlet.ModelAndView; 18 | 19 | import javax.servlet.http.HttpSession; 20 | import java.text.MessageFormat; 21 | 22 | @Controller 23 | @RestController 24 | public class LoginController { 25 | 26 | private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class); 27 | 28 | @Autowired 29 | private UserService userService; 30 | 31 | @RequestMapping(value = {"login", "/"}, method = RequestMethod.GET) 32 | public ModelAndView toLogin() { 33 | return new ModelAndView("login.html"); 34 | } 35 | 36 | @PostMapping("/login") 37 | @ResponseBody 38 | public DataResult login(HttpSession session, Users users) { 39 | if (UserController.isVaild(users.getUsername(), users.getPassword())) { 40 | return DataResult.errorMsg("密码或者用户名不能为空"); 41 | } 42 | DataResult result = userService.login(users); 43 | if (result.getStatus() == 200) { 44 | session.setAttribute(Constant.USER_TOKEN, users.getId()); 45 | } 46 | return result; 47 | } 48 | 49 | @PostMapping("/logout") 50 | @ResponseBody 51 | public DataResult logout(HttpSession session) { 52 | Object userId = session.getAttribute(Constant.USER_TOKEN); 53 | if (userId == null) { 54 | return DataResult.errorMsg("请先登陆"); 55 | } 56 | session.removeAttribute(Constant.USER_TOKEN); 57 | LOGGER.info(MessageFormat.format("userId为 {0} 的用户已注销登录!", userId)); 58 | return DataResult.ok(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/web/interceptor/UserAuthInteceptor.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.web.interceptor; 2 | 3 | import org.springframework.web.servlet.HandlerInterceptor; 4 | import org.springframework.web.servlet.ModelAndView; 5 | import com.ycw.im.imsingel.Webwechat.util.Constant; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import javax.servlet.http.HttpSession; 10 | 11 | public class UserAuthInteceptor implements HandlerInterceptor { 12 | 13 | @Override 14 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 15 | throws Exception { 16 | HttpSession session = request.getSession(); 17 | Object userToken = session.getAttribute(Constant.USER_TOKEN); 18 | if (userToken == null) { 19 | /*JsonMsgHelper.writeJson(response, new ResponseJson(HttpStatus.FORBIDDEN).setMsg("请登录"), 20 | HttpStatus.FORBIDDEN);*/ 21 | response.sendRedirect("login"); 22 | return false; 23 | } 24 | return true; 25 | } 26 | 27 | @Override 28 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 29 | ModelAndView modelAndView) throws Exception { 30 | response.setHeader("Access-Control-Allow-Origin", "*"); 31 | response.setHeader("Access-Control-Allow-Credentials", "true"); 32 | } 33 | 34 | @Override 35 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 36 | throws Exception { 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/Webwechat/web/websocket/WebSocketChildChannelHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.Webwechat.web.websocket; 2 | 3 | import io.netty.channel.ChannelHandler; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.http.HttpServerCodec; 8 | import io.netty.handler.stream.ChunkedWriteHandler; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.annotation.Resource; 12 | 13 | @Component 14 | public class WebSocketChildChannelHandler extends ChannelInitializer { 15 | 16 | @Resource(name = "webSocketServerHandler") 17 | private ChannelHandler webSocketServerHandler; 18 | 19 | @Resource(name = "httpRequestHandler") 20 | private ChannelHandler httpRequestHandler; 21 | 22 | @Override 23 | protected void initChannel(SocketChannel ch) throws Exception { 24 | ch.pipeline().addLast("http-codec", new HttpServerCodec()); // HTTP编码解码器 25 | ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536)); // 把HTTP头、HTTP体拼成完整的HTTP请求 26 | ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); // 方便大文件传输,不过实质上都是短的文本数据 27 | ch.pipeline().addLast("http-handler", new HttpRequestHandler()); 28 | ch.pipeline().addLast("websocket-handler", new WebSocketServerHandler()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/BrowserAndClient/Init.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.BrowserAndClient; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.socket.SocketChannel; 5 | import io.netty.handler.codec.http.HttpObjectAggregator; 6 | import io.netty.handler.codec.http.HttpServerCodec; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | public class Init extends ChannelInitializer { 12 | 13 | @Override 14 | protected void initChannel(SocketChannel channel) throws Exception { 15 | channel.pipeline().addLast(new HttpServerCodec()); 16 | channel.pipeline().addLast(new HttpObjectAggregator(512 * 1024)); 17 | channel.pipeline().addLast(new ResponseHandler()); 18 | } 19 | 20 | public static void main(String[] args) { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/BrowserAndClient/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.BrowserAndClient; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.nio.NioEventLoopGroup; 6 | import io.netty.channel.socket.nio.NioServerSocketChannel; 7 | 8 | /** 9 | * @Author yuchunwei 10 | */ 11 | public class NettyServer { 12 | 13 | public static void init() { 14 | NioEventLoopGroup bossGroup = new NioEventLoopGroup(); 15 | NioEventLoopGroup workGroup = new NioEventLoopGroup(); 16 | ServerBootstrap server = new ServerBootstrap(); 17 | try { 18 | server 19 | .group(bossGroup, workGroup) 20 | .channel(NioServerSocketChannel.class) 21 | .childHandler(new Init()); 22 | 23 | ChannelFuture future = server.bind("127.0.0.1", 8088).sync(); 24 | future.channel().closeFuture().sync(); 25 | } catch (Exception e) { 26 | e.printStackTrace(); 27 | } finally { 28 | bossGroup.shutdownGracefully(); 29 | workGroup.shutdownGracefully(); 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | init(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/BrowserAndClient/ResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.BrowserAndClient; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | import io.netty.handler.codec.http.*; 8 | 9 | import java.nio.charset.Charset; 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | public class ResponseHandler extends SimpleChannelInboundHandler { 15 | 16 | @Override 17 | protected void channelRead0(ChannelHandlerContext ctx, HttpObject httpObject) throws Exception { 18 | Channel channel = ctx.channel(); 19 | ByteBuf byteBuf = ctx.alloc().buffer(); 20 | byteBuf.writeBytes("Hello Netty ".getBytes(Charset.forName("UTF-8"))); 21 | // ByteBuf content = Unpooled.copiedBuffer("Hello netty~", CharsetUtil.UTF_8); 22 | System.out.println("ip :" + channel.remoteAddress()); 23 | FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 24 | HttpResponseStatus.OK, byteBuf); 25 | response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); 26 | response.headers().set(HttpHeaderNames.CONTENT_LENGTH, byteBuf.readableBytes()); 27 | 28 | ctx.writeAndFlush(response); 29 | } 30 | 31 | public static void main(String[] args) { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/client/handler/LoginResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.client.handler; 2 | 3 | 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response.LoginResponse; 5 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.LoginUtil; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | 9 | 10 | public class LoginResponseHandler extends SimpleChannelInboundHandler { 11 | @Override 12 | public void channelRead0(ChannelHandlerContext ctx, LoginResponse response) { 13 | System.out.println(response.getMessage()); 14 | if (response.isSuccess()) { 15 | LoginUtil.set(ctx.channel()); 16 | LoginUtil.setUserName(ctx.channel(), response.getUserName()); 17 | ; 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/client/handler/MessageResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.client.handler; 2 | 3 | 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response.MessageResponse; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | 8 | public class MessageResponseHandler extends SimpleChannelInboundHandler { 9 | @Override 10 | public void channelRead0(ChannelHandlerContext ctx, MessageResponse messageResponse) { 11 | if (messageResponse.isUp()) { 12 | System.out.println("收到[" + messageResponse.getFromUserName() + "]消息:"); 13 | } 14 | System.out.println(messageResponse.getMessage()); 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/codec/Codec.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.codec; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.Packet; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.request.LoginRequest; 5 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.request.MessageRequest; 6 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response.LoginResponse; 7 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response.MessageResponse; 8 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.serializer.JSONSerializer; 9 | import io.netty.buffer.ByteBuf; 10 | 11 | import java.util.HashMap; 12 | 13 | public class Codec { 14 | private final int MAGIC_NUMBER = 0x12345678; 15 | public static final Codec INSTANCE = new Codec(); 16 | private JSONSerializer serializer = new JSONSerializer(); 17 | private final HashMap> map = new HashMap<>(); 18 | 19 | public Codec() { 20 | map.put(1, LoginRequest.class); 21 | map.put(2, LoginResponse.class); 22 | map.put(3, MessageRequest.class); 23 | map.put(4, MessageResponse.class); 24 | } 25 | 26 | public void encode(ByteBuf byteBuf, Packet packet) { 27 | byte[] bytes = serializer.serialize(packet); 28 | 29 | byteBuf.writeInt(MAGIC_NUMBER); 30 | byteBuf.writeInt((Integer) packet.getCommand()); 31 | byteBuf.writeInt(bytes.length); 32 | byteBuf.writeBytes(bytes); 33 | } 34 | 35 | public Packet decode(ByteBuf byteBuf) { 36 | if (byteBuf.readInt() == 0x12345678) { 37 | int command = byteBuf.readInt(); 38 | int length = byteBuf.readInt(); 39 | byte[] bytes = new byte[length]; 40 | byteBuf.readBytes(bytes); 41 | if (map.keySet().contains(command)) { 42 | return serializer.deserialize(map.get(command), bytes); 43 | } 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/codec/nettyCodec/PacketDecoder.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.codec.nettyCodec; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.codec.Codec; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.handler.codec.ByteToMessageDecoder; 7 | 8 | import java.util.List; 9 | 10 | public class PacketDecoder extends ByteToMessageDecoder { 11 | @Override 12 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { 13 | out.add(Codec.INSTANCE.decode(in)); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/codec/nettyCodec/PacketEncoder.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.codec.nettyCodec; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.codec.Codec; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.Packet; 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.MessageToByteEncoder; 8 | 9 | 10 | public class PacketEncoder extends MessageToByteEncoder { 11 | @Override 12 | protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) { 13 | Codec.INSTANCE.encode(out, packet); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/Packet.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.Command; 4 | 5 | public abstract class Packet { 6 | private Command command; 7 | 8 | public abstract Object getCommand(); 9 | } 10 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/request/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.request; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.Packet; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.Command; 5 | import lombok.Data; 6 | 7 | @Data 8 | public class LoginRequest extends Packet { 9 | private String username; 10 | private String password; 11 | 12 | public Integer getCommand() { 13 | return Command.LoginRequest.getCode(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/request/MessageRequest.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.request; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.Packet; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.Command; 5 | import lombok.Data; 6 | 7 | @Data 8 | public class MessageRequest extends Packet { 9 | private String message; 10 | private String toUserName; 11 | private String fromUsername; 12 | 13 | public MessageRequest() { 14 | 15 | } 16 | 17 | public MessageRequest(String message, String toUserName, String fromUsername) { 18 | this.message = message; 19 | this.toUserName = toUserName; 20 | this.fromUsername = fromUsername; 21 | } 22 | 23 | public Integer getCommand() { 24 | return Command.MessageRequest.getCode(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/response/LoginResponse.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.Packet; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.Command; 5 | import lombok.Data; 6 | 7 | @Data 8 | public class LoginResponse extends Packet { 9 | private boolean isSuccess; 10 | private String message; 11 | private String userName; 12 | 13 | public Integer getCommand() { 14 | return Command.LoginRespose.getCode(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/response/MessageResponse.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.Packet; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.Command; 5 | import lombok.Data; 6 | 7 | @Data 8 | public class MessageResponse extends Packet { 9 | private String message; 10 | private String toUserName; 11 | private String fromUserName; 12 | private boolean isUp; 13 | 14 | public Integer getCommand() { 15 | return Command.MessageResponse.getCode(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/serializer/JSONSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.serializer; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | public class JSONSerializer implements Serializer { 6 | 7 | @Override 8 | public byte getSerializerAlogrithm() { 9 | return SerializerAlogrithm.JSON; 10 | } 11 | 12 | @Override 13 | public byte[] serialize(Object object) { 14 | 15 | return JSON.toJSONBytes(object); 16 | } 17 | 18 | @Override 19 | public T deserialize(Class clazz, byte[] bytes) { 20 | 21 | return JSON.parseObject(bytes, clazz); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/serializer/Serializer.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.serializer; 2 | 3 | public interface Serializer { 4 | 5 | Serializer DEFAULT = new JSONSerializer(); 6 | 7 | /** 8 | * 序列化算法 9 | * 10 | * @return 11 | */ 12 | byte getSerializerAlogrithm(); 13 | 14 | /** 15 | * java 对象转换成二进制 16 | */ 17 | byte[] serialize(Object object); 18 | 19 | /** 20 | * 二进制转换成 java 对象 21 | */ 22 | T deserialize(Class clazz, byte[] bytes); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/protocol/serializer/SerializerAlogrithm.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.serializer; 2 | 3 | public interface SerializerAlogrithm { 4 | /** 5 | * json 序列化 6 | */ 7 | byte JSON = 1; 8 | } 9 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/server/handler/AuthHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.server.handler; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util.LoginUtil; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | 7 | /** 8 | * @Author yuchunwei 9 | */ 10 | public class AuthHandler extends ChannelInboundHandlerAdapter { 11 | 12 | @Override 13 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 14 | if (LoginUtil.isLogin(ctx.channel())) { 15 | ctx.pipeline().remove(this); 16 | super.channelRead(ctx, msg); 17 | } else { 18 | ctx.channel().close(); 19 | } 20 | 21 | } 22 | 23 | @Override 24 | public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 25 | if (LoginUtil.isLogin(ctx.channel())) { 26 | System.out.println("当前连接登录验证完毕,无需再次验证, AuthHandler 被移除"); 27 | } else { 28 | System.out.println("无登录验证,强制关闭连接!"); 29 | } 30 | } 31 | 32 | public static void main(String[] args) { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/server/handler/MessageRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.server.handler; 2 | 3 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.request.MessageRequest; 4 | import com.ycw.im.imsingel.learnNettyExample.ClientAndServer.protocol.response.MessageResponse; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | 9 | public class MessageRequestHandler extends SimpleChannelInboundHandler { 10 | @Override 11 | public void channelRead0(ChannelHandlerContext ctx, MessageRequest request) { 12 | Channel channel; 13 | MessageResponse messageResponse = new MessageResponse(); 14 | System.out.println(request.getFromUsername() + "正在发送消息"); 15 | if ((channel = LoginRuqestHandler.chatList.get(request.getToUserName())) != null) { 16 | messageResponse.setMessage(request.getMessage()); 17 | messageResponse.setToUserName(request.getToUserName()); 18 | messageResponse.setFromUserName(request.getFromUsername()); 19 | messageResponse.setUp(true); 20 | channel.writeAndFlush(messageResponse); 21 | } else { 22 | messageResponse.setUp(false); 23 | messageResponse.setMessage("对方没有上线"); 24 | ctx.channel().writeAndFlush(messageResponse); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/util/Command.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util; 2 | 3 | public enum Command { 4 | //指令代码 5 | LoginRequest(0x001), 6 | LoginRespose(0x002), 7 | MessageRequest(0x003), 8 | MessageResponse(0x004); 9 | 10 | private int code; 11 | 12 | private Command(int code) { 13 | this.code = code; 14 | } 15 | 16 | public int getCode() { 17 | return code; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/util/LoginUtil.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | public class LoginUtil { 6 | public static void set(Channel channel) { 7 | channel.attr(State.LOGIN).set(true); 8 | } 9 | 10 | public static boolean isLogin(Channel channel) { 11 | return channel.hasAttr(State.LOGIN); 12 | } 13 | 14 | public static String getUserName(Channel channel) { 15 | return channel.attr(State.USERNAME).get(); 16 | } 17 | 18 | public static void setUserName(Channel channel, String id) { 19 | channel.attr(State.USERNAME).set(id); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/ClientAndServer/util/State.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.ClientAndServer.util; 2 | 3 | import io.netty.util.AttributeKey; 4 | 5 | //接口中声明变量默认的是static final 6 | public interface State { 7 | AttributeKey LOGIN = AttributeKey.newInstance("login"); 8 | AttributeKey USERNAME = AttributeKey.newInstance("username"); 9 | } 10 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/WebSocketAndNetty/ChatHandler.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.WebSocketAndNetty; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | import io.netty.channel.group.ChannelGroup; 7 | import io.netty.channel.group.DefaultChannelGroup; 8 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 9 | import io.netty.util.concurrent.GlobalEventExecutor; 10 | 11 | /** 12 | * @Author yuchunwei 13 | */ 14 | public class ChatHandler extends SimpleChannelInboundHandler { 15 | private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 16 | 17 | @Override 18 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg) throws Exception { 19 | String content = msg.text(); 20 | System.out.println("收到的消息" + msg); 21 | //对所有在线的用户广播 22 | for (Channel channel : channels) { 23 | channel.writeAndFlush(new TextWebSocketFrame("广播 :某用户发送了消息" + content)); 24 | } 25 | 26 | } 27 | 28 | @Override 29 | public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 30 | channels.add(ctx.channel()); 31 | } 32 | 33 | public static void main(String[] args) { 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/WebSocketAndNetty/Init.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.WebSocketAndNetty; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.socket.SocketChannel; 5 | import io.netty.handler.codec.http.HttpObjectAggregator; 6 | import io.netty.handler.codec.http.HttpServerCodec; 7 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 8 | import io.netty.handler.stream.ChunkedWriteHandler; 9 | 10 | /** 11 | * @Author yuchunwei 12 | */ 13 | public class Init extends ChannelInitializer { 14 | 15 | public static void main(String[] args) { 16 | 17 | } 18 | 19 | @Override 20 | protected void initChannel(SocketChannel socketChannel) throws Exception { 21 | socketChannel.pipeline().addLast(new HttpServerCodec()); 22 | socketChannel.pipeline().addLast(new ChunkedWriteHandler()); 23 | socketChannel.pipeline().addLast(new HttpObjectAggregator(1024 * 64)); 24 | 25 | socketChannel.pipeline().addLast(new WebSocketServerProtocolHandler("/ws")); 26 | socketChannel.pipeline().addLast(null); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /im-singel/src/main/java/com/ycw/im/imsingel/learnNettyExample/WebSocketAndNetty/WsServer.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel.learnNettyExample.WebSocketAndNetty; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * @Author yuchunwei 11 | */ 12 | public class WsServer { 13 | 14 | private static void init() { 15 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 16 | EventLoopGroup workGroup = new NioEventLoopGroup(); 17 | try { 18 | ServerBootstrap bootstrap = new ServerBootstrap(); 19 | bootstrap 20 | .group(bossGroup, workGroup) 21 | .channel(NioServerSocketChannel.class) 22 | .childHandler(new Init()); 23 | ChannelFuture future = bootstrap.bind(8088).sync(); 24 | future.channel().closeFuture().sync(); 25 | } catch (Exception e) { 26 | e.printStackTrace(); 27 | } finally { 28 | bossGroup.shutdownGracefully(); 29 | workGroup.shutdownGracefully(); 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /im-singel/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/application.properties -------------------------------------------------------------------------------- /im-singel/src/main/resources/mapper/ChatMsgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | INSERT INTO chat_msg(send_user_id,accept_user_id,msg,sign_flag,create_time) 16 | values(#{sendUserId},#{acceptUserId},#{msg},#{signFlag},#{createTime}) 17 | 18 | 19 | 22 | 23 | 24 | UPDATE chat_msg SET sign_flag = 1 WHERE id 25 | IN 26 | 27 | #{id} 28 | 29 | 30 | -------------------------------------------------------------------------------- /im-singel/src/main/resources/mapper/FriendsRequestMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | insert into friends_request(send_user_id,accept_user_id,request_time,status) 14 | values(#{myUserId},#{friendId},#{date},#{status}) 15 | 16 | 17 | 23 | 24 | UPDATE friends_request SET status = #{status} WHERE accept_user_id = #{acceptUserId} AND send_user_id = 25 | #{sendUserId} 26 | 27 | -------------------------------------------------------------------------------- /im-singel/src/main/resources/mapper/MyFriendsMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | INSERT INTO my_friends(my_user_id,my_friend_user_id) values(#{acceptUserId},#{sendUserId}) 16 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/img/loading-sm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/img/loading-sm.gif -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/css/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/css/img/loading.gif -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Group01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Group01.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member001.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member002.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member003.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member004.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member005.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member006.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member007.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member008.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/avatar/Member009.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/avatar/Member009.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/box_head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/box_head.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/chat.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/chat.ico -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/chat_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/chat_bg.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_01.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_02.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_03.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_04.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_05.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_06.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_07.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_08.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_09.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_10.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_11.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_12.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_13.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_14.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_15.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_16.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_17.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_18.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_19.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_20.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_21.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_22.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_23.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/emoji/emoji_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/emoji/emoji_24.png -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/login_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/login_bg.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/img/upload.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/im-singel/src/main/resources/static/img/upload.jpg -------------------------------------------------------------------------------- /im-singel/src/main/resources/static/js/common/jquery.actual.min.js: -------------------------------------------------------------------------------- 1 | /*! Copyright 2012, Ben Lin (http://dreamerslab.com/) 2 | * Licensed under the MIT License (LICENSE.txt). 3 | * 4 | * Version: 1.0.19 5 | * 6 | * Requires: jQuery >= 1.2.3 7 | */ 8 | (function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a); 9 | }else{a(jQuery);}}(function(a){a.fn.addBack=a.fn.addBack||a.fn.andSelf;a.fn.extend({actual:function(b,l){if(!this[b]){throw'$.actual => The jQuery method "'+b+'" you called does not exist'; 10 | }var f={absolute:false,clone:false,includeMargin:false,display:"block"};var i=a.extend(f,l);var e=this.eq(0);var h,j;if(i.clone===true){h=function(){var m="position: absolute !important; top: -1000 !important; "; 11 | e=e.clone().attr("style",m).appendTo("body");};j=function(){e.remove();};}else{var g=[];var d="";var c;h=function(){c=e.parents().addBack().filter(":hidden"); 12 | d+="visibility: hidden !important; display: "+i.display+" !important; ";if(i.absolute===true){d+="position: absolute !important; ";}c.each(function(){var m=a(this); 13 | var n=m.attr("style");g.push(n);m.attr("style",n?n+";"+d:d);});};j=function(){c.each(function(m){var o=a(this);var n=g[m];if(n===undefined){o.removeAttr("style"); 14 | }else{o.attr("style",n);}});};}h();var k=/(outer)/.test(b)?e[b](i.includeMargin):e[b]();j();return k;}});})); 15 | -------------------------------------------------------------------------------- /im-singel/src/test/java/com/ycw/im/imsingel/ImSingelApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imsingel; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImSingelApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /image/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/image/1.png -------------------------------------------------------------------------------- /image/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiujiujiujiujiuaia/IM-netty/8fc2225f44ba52d4da9e02ef050b8d45962999be/image/2.png -------------------------------------------------------------------------------- /src/main/java/com/ycw/im/imdistributedcommon/ImDistributedCommonApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcommon; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImDistributedCommonApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImDistributedCommonApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/ycw/im/imdistributedcommons/ImDistributedCommonsApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcommons; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImDistributedCommonsApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImDistributedCommonsApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/ycw/im/imdistributedroute/ImDistributedRouteApplication.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ImDistributedRouteApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ImDistributedRouteApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/test/java/com/ycw/im/imdistributedcommon/ImDistributedCommonApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcommon; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedCommonApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/ycw/im/imdistributedcommons/ImDistributedCommonsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedcommons; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedCommonsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/ycw/im/imdistributedroute/ImDistributedRouteApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.ycw.im.imdistributedroute; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImDistributedRouteApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------