Repository: lining90567/leo-im-server
Branch: master
Commit: 35759b9caf08
Files: 357
Total size: 517.4 KB
Directory structure:
gitextract_5xra_4nj/
├── .classpath
├── .gitignore
├── .project
├── .settings/
│ ├── org.eclipse.core.resources.prefs
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.m2e.core.prefs
├── LICENSE
├── README.md
├── assemble/
│ ├── bin/
│ │ ├── run.bat
│ │ └── run.sh
│ └── package.xml
├── leo-im-api/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── api/
│ │ │ ├── annotation/
│ │ │ │ ├── Cacheable.java
│ │ │ │ └── Transactional.java
│ │ │ ├── dto/
│ │ │ │ ├── ChannelDTO.java
│ │ │ │ ├── ChannelListDTO.java
│ │ │ │ ├── ChannelMemberDTO.java
│ │ │ │ ├── FileDTO.java
│ │ │ │ ├── MessageDTO.java
│ │ │ │ ├── UserChannelDTO.java
│ │ │ │ └── UserDTO.java
│ │ │ ├── exception/
│ │ │ │ └── ServiceException.java
│ │ │ └── service/
│ │ │ ├── ChannelService.java
│ │ │ ├── MessageService.java
│ │ │ ├── UnreadMessageCountService.java
│ │ │ ├── UserChannelService.java
│ │ │ └── UserService.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── api/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-api/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.api.AppTest.xml
│ └── org.leo.im.api.AppTest.txt
├── leo-im-api-provider/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── api/
│ │ │ └── provider/
│ │ │ └── ServiceFactory.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── api/
│ │ └── provider/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-api-provider/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.api.provider.AppTest.xml
│ └── org.leo.im.api.provider.AppTest.txt
├── leo-im-common/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── common/
│ │ │ └── data/
│ │ │ └── Page.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── common/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-common/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.common.AppTest.xml
│ └── org.leo.im.common.AppTest.txt
├── leo-im-http/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── http/
│ │ │ ├── HttpServer.java
│ │ │ ├── cache/
│ │ │ │ ├── Cache.java
│ │ │ │ ├── CacheManager.java
│ │ │ │ ├── CacheManagerFactory.java
│ │ │ │ └── MapCacheManager.java
│ │ │ ├── constant/
│ │ │ │ └── CacheKeys.java
│ │ │ ├── controller/
│ │ │ │ ├── AuthController.java
│ │ │ │ ├── BaseController.java
│ │ │ │ ├── ChannelController.java
│ │ │ │ ├── ExceptionController.java
│ │ │ │ ├── MessageController.java
│ │ │ │ ├── UserChannelController.java
│ │ │ │ └── UserController.java
│ │ │ ├── exception/
│ │ │ │ └── NoSuchSettingException.java
│ │ │ ├── file/
│ │ │ │ ├── AbstractLocalFileStorage.java
│ │ │ │ ├── AvatarStorage.java
│ │ │ │ ├── AvatarStorageFactory.java
│ │ │ │ ├── FileStorage.java
│ │ │ │ ├── FileStorageFactory.java
│ │ │ │ ├── LocalAvatarStorage.java
│ │ │ │ └── LocalFileStorage.java
│ │ │ ├── interceptor/
│ │ │ │ ├── AuthenticationInterceptor.java
│ │ │ │ └── CorsInterceptor.java
│ │ │ ├── util/
│ │ │ │ └── JwtUtils.java
│ │ │ └── vo/
│ │ │ ├── ChannelListVO.java
│ │ │ ├── ChannelVO.java
│ │ │ ├── MessageVO.java
│ │ │ └── UserChannelVO.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── http/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-http/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.http.AppTest.xml
│ └── org.leo.im.http.AppTest.txt
├── leo-im-migration/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── org/
│ │ │ │ └── leo/
│ │ │ │ └── im/
│ │ │ │ └── migration/
│ │ │ │ └── FlywayMigration.java
│ │ │ └── resources/
│ │ │ └── db/
│ │ │ └── migration/
│ │ │ └── V20180615___Init.sql
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── migration/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ ├── META-INF/
│ │ │ ├── MANIFEST.MF
│ │ │ └── maven/
│ │ │ └── org.leo.im/
│ │ │ └── leo-im-migration/
│ │ │ ├── pom.properties
│ │ │ └── pom.xml
│ │ └── db/
│ │ └── migration/
│ │ └── V20180615___Init.sql
│ ├── maven-archiver/
│ │ └── pom.properties
│ └── maven-status/
│ └── maven-compiler-plugin/
│ └── compile/
│ └── default-compile/
│ ├── createdFiles.lst
│ └── inputFiles.lst
├── leo-im-model/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── model/
│ │ │ ├── Channel.java
│ │ │ ├── ChannelMember.java
│ │ │ ├── File.java
│ │ │ ├── Message.java
│ │ │ ├── User.java
│ │ │ └── UserChannel.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── model/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-model/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.model.AppTest.xml
│ └── org.leo.im.model.AppTest.txt
├── leo-im-notification/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── notification/
│ │ │ ├── ActionNames.java
│ │ │ ├── PublishKeys.java
│ │ │ ├── Publisher.java
│ │ │ ├── PublisherFactory.java
│ │ │ ├── QueuePublisher.java
│ │ │ ├── Subscriber.java
│ │ │ ├── ThreadPoolHolder.java
│ │ │ └── event/
│ │ │ ├── AvatarChangedEvent.java
│ │ │ ├── ChannelCreatedEvent.java
│ │ │ ├── ChannelNameChangedEvent.java
│ │ │ ├── ChannelRemovedEvent.java
│ │ │ ├── JoinChannelEvent.java
│ │ │ ├── LeaveChannelEvent.java
│ │ │ ├── MembersCountChangedEvent.java
│ │ │ ├── MessageRemovedEvent.java
│ │ │ ├── NewMessageEvent.java
│ │ │ ├── NicknameChangedEvent.java
│ │ │ ├── NotificationEvent.java
│ │ │ ├── OnlineStatusChangedEvent.java
│ │ │ ├── ReadMessageEvent.java
│ │ │ └── RemoveFromChannelEvent.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── notification/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-notification/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.notification.AppTest.xml
│ └── org.leo.im.notification.AppTest.txt
├── leo-im-service/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── service/
│ │ │ ├── ChannelServiceImpl.java
│ │ │ ├── MessageServiceImpl.java
│ │ │ ├── UnreadMessageCountServiceImpl.java
│ │ │ ├── UserChannelServiceImpl.java
│ │ │ ├── UserServiceImpl.java
│ │ │ ├── support/
│ │ │ │ ├── CacheableHolder.java
│ │ │ │ └── ServiceProxy.java
│ │ │ └── util/
│ │ │ └── PasswordUtils.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── service/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-service/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.service.AppTest.xml
│ └── org.leo.im.service.AppTest.txt
├── leo-im-socket/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── socket/
│ │ │ ├── ChannelIdSet.java
│ │ │ ├── ChannelsHolder.java
│ │ │ ├── SocketChannel.java
│ │ │ ├── WebSocketChannelInitializer.java
│ │ │ ├── WebSocketServer.java
│ │ │ ├── exception/
│ │ │ │ └── MessageHandleException.java
│ │ │ ├── handler/
│ │ │ │ └── TextWebSocketFrameHandler.java
│ │ │ └── subscription/
│ │ │ ├── QueueSubscriber.java
│ │ │ ├── SubscriberFactory.java
│ │ │ └── handler/
│ │ │ ├── AbstractMessageHandler.java
│ │ │ ├── AvatarChangedHandler.java
│ │ │ ├── ChannelCreatedHandler.java
│ │ │ ├── ChannelNameChangedHandler.java
│ │ │ ├── ChannelRemovedHandler.java
│ │ │ ├── JoinChannelHandler.java
│ │ │ ├── LeaveChannelHandler.java
│ │ │ ├── MembersCountChangedHandler.java
│ │ │ ├── MessageHandler.java
│ │ │ ├── MessageHandlerFactory.java
│ │ │ ├── NewMessageHandler.java
│ │ │ ├── NicknameChangedHandler.java
│ │ │ ├── OnlineStatusChangedHandler.java
│ │ │ ├── ReadMessageHandler.java
│ │ │ ├── RemoveFromChannelHandler.java
│ │ │ └── RemoveMessageHandler.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── socket/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-socket/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.socket.AppTest.xml
│ └── org.leo.im.socket.AppTest.txt
├── leo-im-starter/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ ├── conf/
│ │ │ │ └── app.conf
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── starter/
│ │ │ └── App.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── starter/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-starter/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── leo-im-starter-1.0/
│ │ ├── bin/
│ │ │ ├── run.bat
│ │ │ └── run.sh
│ │ └── conf/
│ │ └── app.conf
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.starter.AppTest.xml
│ └── org.leo.im.starter.AppTest.txt
├── leo-im-store/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── store/
│ │ │ ├── connection/
│ │ │ │ ├── ConnectionFactory.java
│ │ │ │ ├── ConnectionProvider.java
│ │ │ │ └── impl/
│ │ │ │ └── PoolConnectionFactory.java
│ │ │ ├── dao/
│ │ │ │ ├── BaseDAO.java
│ │ │ │ ├── ChannelDAO.java
│ │ │ │ ├── ChannelMemberDAO.java
│ │ │ │ ├── FileDAO.java
│ │ │ │ ├── HideChannelDAO.java
│ │ │ │ ├── MessageDAO.java
│ │ │ │ ├── UnreadMessageCountDAO.java
│ │ │ │ ├── UserChannelDAO.java
│ │ │ │ ├── UserDAO.java
│ │ │ │ └── impl/
│ │ │ │ ├── JdbcChannelDAOImpl.java
│ │ │ │ ├── JdbcChannelMemberDAOImpl.java
│ │ │ │ ├── JdbcFileDAOImpl.java
│ │ │ │ ├── JdbcHideChannelDAOImpl.java
│ │ │ │ ├── JdbcMessageDAOImpl.java
│ │ │ │ ├── JdbcUnreadMessageCountDAOImpl.java
│ │ │ │ ├── JdbcUserChannelDAOImpl.java
│ │ │ │ └── JdbcUserDAOImpl.java
│ │ │ ├── datasource/
│ │ │ │ ├── ConnectionPool.java
│ │ │ │ └── impl/
│ │ │ │ └── DruidConnectionPool.java
│ │ │ ├── exception/
│ │ │ │ └── DAOException.java
│ │ │ ├── factory/
│ │ │ │ └── DAOFactory.java
│ │ │ ├── support/
│ │ │ │ ├── BatchSqlBuildResult.java
│ │ │ │ ├── Parameter.java
│ │ │ │ ├── ParameterDataTypeEnum.java
│ │ │ │ └── SqlBuildResult.java
│ │ │ └── util/
│ │ │ ├── DbUtils.java
│ │ │ └── FirstLetterUtil.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── store/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-store/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.store.AppTest.xml
│ └── org.leo.im.store.AppTest.txt
├── leo-im-util/
│ ├── .classpath
│ ├── .project
│ ├── .settings/
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ ├── pom.xml
│ ├── src/
│ │ ├── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── leo/
│ │ │ └── im/
│ │ │ └── util/
│ │ │ ├── BeanUtils.java
│ │ │ └── JwtUtils.java
│ │ └── test/
│ │ └── java/
│ │ └── org/
│ │ └── leo/
│ │ └── im/
│ │ └── util/
│ │ └── AppTest.java
│ └── target/
│ ├── classes/
│ │ └── META-INF/
│ │ ├── MANIFEST.MF
│ │ └── maven/
│ │ └── org.leo.im/
│ │ └── leo-im-util/
│ │ ├── pom.properties
│ │ └── pom.xml
│ ├── maven-archiver/
│ │ └── pom.properties
│ ├── maven-status/
│ │ └── maven-compiler-plugin/
│ │ ├── compile/
│ │ │ └── default-compile/
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile/
│ │ └── default-testCompile/
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── surefire-reports/
│ ├── TEST-org.leo.im.util.AppTest.xml
│ └── org.leo.im.util.AppTest.txt
└── pom.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .classpath
================================================
================================================
FILE: .gitignore
================================================
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
================================================
FILE: .project
================================================
leo-im
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: .settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding/=UTF-8
================================================
FILE: .settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: .settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# 
Leo-IM,开源好用的IM。
Leo-IM是基于Java语言、Netty框架、Vue+Element-UI开发的轻量级IM,服务端可独立运行(无需部署到web容器),HTTP服务和Socket服务可分开部署,使用基于Netty扩展的[netty-rest-server](https://github.com/lining90567/netty-rest-server)RESTful框架提供Web服务,简单易用,方便扩展。
## 在线演示
演示地址:http://43.138.44.47:8000
建议使用Chrome浏览器
- 演示用户1:用户名 test1,口令 123456
- 演示用户2:用户名 test2,口令 123456
- 演示用户3:用户名 test3,口令 123456
## 运行环境要求
- 服务端:Java8、MySQL5.5+
- 客户端:Chrome、IE10+
## 主要功能
- 私聊
- 群聊
- 文字、表情、图片、文件
## 构建与部署
- 安装netty-rest-server到本地仓库
mvn install:install-file -Dfile=netty-rest-server-1.0.jar -DgroupId=org.leo -DartifactId=netty-rest-server -Dversion=1.0 -Dpackaging=jar
- 创建数据库,并设置字符集(my.cnf或my.ini)
[client]
default-character-set=utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect=’SET NAMES utf8mb4'
[mysql]
default-character-set=utf8mb4
- 构建
mvn package
- 部署
解压leo-im-1.0.zip,修改conf/app.conf的相关配置
- 启动
nohup bin/run.sh >/dev/null 2>&1 &
- Web端代码
https://github.com/lining90567/leo-im-web
## 联系方式
- **邮箱** - lining90567@sina.com
- **QQ** - 328616209
================================================
FILE: assemble/bin/run.bat
================================================
@REM app launcher script
@REM
@REM Environment:
@REM JAVA_HOME - location of a JDK home dir (optional if java on path)
@setlocal enabledelayedexpansion
@echo off
cd %~dp0
cd ../
if "%JAVA_OPS%" == "" set JAVA_OPS=-Dfile.encoding=utf-8 -Dio.netty.noUnsafe=true -server -Xmx128m -Xms128m -Xss256k
java %JAVA_OPS% -Dconf.home=%cd%\conf\ -jar %cd%\lib\leo-im-starter-1.0.jar
================================================
FILE: assemble/bin/run.sh
================================================
#!/bin/sh
### ------------------------------- ###
### leo-im-server launcher script ###
### ------------------------------- ###
cd `dirname $0`
cd ../
if [ -z "$JAVA_OPS" ]; then
JAVA_OPS="-Dfile.encoding=utf-8 -Dio.netty.noUnsafe=true -Xms128M -Xmx128M -Xss256K"
fi
java $JAVA_OPS -Dconf.home=$(pwd)/conf/ -jar $(pwd)/lib/leo-im-starter-1.0.jar
================================================
FILE: assemble/package.xml
================================================
package
zip
true
../assemble/bin
/bin
src/main/conf
/conf
lib
runtime
================================================
FILE: leo-im-api/.classpath
================================================
================================================
FILE: leo-im-api/.project
================================================
leo-im-api
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-api/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-api/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-api/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-api/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-api
leo-im-api
http://maven.apache.org
org.leo.im
leo-im-common
${parent.version}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/annotation/Cacheable.java
================================================
package org.leo.im.api.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 缓存注解
*
* @author Leo
* @date 2018/3/19
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@Inherited
public @interface Cacheable {
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/annotation/Transactional.java
================================================
package org.leo.im.api.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
/**
* 事务注解,该注解需要在服务接口上使用,在实现类上使用无效。
*
* @author Leo
* @date 2018/3/19
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@Inherited
public @interface Transactional {
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/ChannelDTO.java
================================================
package org.leo.im.api.dto;
import java.util.ArrayList;
import java.util.List;
/**
* 频道dto类
*
* @author Leo
* @date 2018/4/11
*/
public final class ChannelDTO {
private String id;
private String name;
private String type;
private int memberCount;
private long createAt;
private String creatorId;
private String fromUserId;
private String fromUsername;
private String fromUserNickname;
private String toUserId;
private String toUsername;
private String toUserNickname;
private String toUserOnlineStatus;
private String purpose;
private List members = new ArrayList<>(128);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public long getCreateAt() {
return createAt;
}
public void setCreateAt(long createAt) {
this.createAt = createAt;
}
public String getCreatorId() {
return creatorId;
}
public void setCreatorId(String creatorId) {
this.creatorId = creatorId;
}
public String getFromUserId() {
return fromUserId;
}
public void setFromUserId(String fromUserId) {
this.fromUserId = fromUserId;
}
public String getFromUsername() {
return fromUsername;
}
public void setFromUsername(String fromUsername) {
this.fromUsername = fromUsername;
}
public String getFromUserNickname() {
return fromUserNickname;
}
public void setFromUserNickname(String fromUserNickname) {
this.fromUserNickname = fromUserNickname;
}
public String getToUserId() {
return toUserId;
}
public void setToUserId(String toUserId) {
this.toUserId = toUserId;
}
public String getToUsername() {
return toUsername;
}
public void setToUsername(String toUsername) {
this.toUsername = toUsername;
}
public String getToUserNickname() {
return toUserNickname;
}
public void setToUserNickname(String toUserNickname) {
this.toUserNickname = toUserNickname;
}
public String getToUserOnlineStatus() {
return toUserOnlineStatus;
}
public void setToUserOnlineStatus(String toUserOnlineStatus) {
this.toUserOnlineStatus = toUserOnlineStatus;
}
public List getMembers() {
return members;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
@Override
public String toString() {
return "ChannelDTO [id=" + id + ", name=" + name + ", type=" + type + ", memberCount=" + memberCount
+ ", createAt=" + createAt + ", creatorId=" + creatorId + ", fromUserId=" + fromUserId
+ ", fromUsername=" + fromUsername + ", fromUserNickname=" + fromUserNickname + ", toUserId=" + toUserId
+ ", toUsername=" + toUsername + ", toUserNickname=" + toUserNickname + ", toUserOnlineStatus="
+ toUserOnlineStatus + ", purpose=" + purpose + ", members=" + members + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/ChannelListDTO.java
================================================
package org.leo.im.api.dto;
/**
* Channel列表DTO
*
* @author Leo
* @date 2018/3/30
*/
public class ChannelListDTO {
private String id;
private String name;
private String displayName;
private String otherSideOnlineStatus;
private String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getOtherSideOnlineStatus() {
return otherSideOnlineStatus;
}
public void setOtherSideOnlineStatus(String otherSideOnlineStatus) {
this.otherSideOnlineStatus = otherSideOnlineStatus;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "ChannelListDTO [id=" + id + ", name=" + name + ", displayName=" + displayName
+ ", otherSideOnlineStatus=" + otherSideOnlineStatus + ", type=" + type + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/ChannelMemberDTO.java
================================================
package org.leo.im.api.dto;
/**
* 频道成员dto类
*
* @author Leo
* @date 2018/4/11
*/
public class ChannelMemberDTO {
private String id;
private String nickname;
private boolean admin;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public boolean getAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
@Override
public String toString() {
return "ChannelMemberDTO [id=" + id + ", nickname=" + nickname + ", admin=" + admin + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/FileDTO.java
================================================
package org.leo.im.api.dto;
/**
* 文件dto类
*
* @author Leo
* @date 2018/6/13
*/
public class FileDTO {
private String id;
private String name;
private String extension;
private int size;
private String mimeType;
private int width;
private int height;
private short thumbWidth;
private short thumbHeight;
private String path;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public short getThumbWidth() {
return thumbWidth;
}
public void setThumbWidth(short thumbWidth) {
this.thumbWidth = thumbWidth;
}
public short getThumbHeight() {
return thumbHeight;
}
public void setThumbHeight(short thumbHeight) {
this.thumbHeight = thumbHeight;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String toString() {
return "FileDTO [id=" + id + ", name=" + name + ", extension=" + extension + ", size=" + size + ", mimeType="
+ mimeType + ", width=" + width + ", height=" + height + ", thumbWidth=" + thumbWidth + ", thumbHeight="
+ thumbHeight + ", path=" + path + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/MessageDTO.java
================================================
package org.leo.im.api.dto;
/**
* 消息dto类
*
* @author Leo
* @date 2018/5/15
*/
public class MessageDTO {
private long id;
private String channelId;
private String channelType;
private long createAt;
private String type;
private String senderId;
private String senderName;
private String senderNickname;
private String senderOnlineStatus;
private String senderAvatarUrl;
private String senderFirstLetterOfName;
private String content;
private String fileId;
private String fileName;
private String fileExtension;
private int fileSize;
private String fileMimeType;
private int imageWidth;
private int imageHeight;
private short imageThumbWidth;
private short imageThumbHeight;
private String filePath;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getChannelType() {
return channelType;
}
public void setChannelType(String channelType) {
this.channelType = channelType;
}
public long getCreateAt() {
return createAt;
}
public void setCreateAt(long createAt) {
this.createAt = createAt;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSenderId() {
return senderId;
}
public void setSenderId(String senderId) {
this.senderId = senderId;
}
public String getSenderName() {
return senderName;
}
public void setSenderName(String senderName) {
this.senderName = senderName;
}
public String getSenderNickname() {
return senderNickname;
}
public void setSenderNickname(String senderNickname) {
this.senderNickname = senderNickname;
}
public String getSenderOnlineStatus() {
return senderOnlineStatus;
}
public void setSenderOnlineStatus(String senderOnlineStatus) {
this.senderOnlineStatus = senderOnlineStatus;
}
public String getSenderAvatarUrl() {
return senderAvatarUrl;
}
public void setSenderAvatarUrl(String senderAvatarUrl) {
this.senderAvatarUrl = senderAvatarUrl;
}
public String getSenderFirstLetterOfName() {
return senderFirstLetterOfName;
}
public void setSenderFirstLetterOfName(String senderFirstLetterOfName) {
this.senderFirstLetterOfName = senderFirstLetterOfName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getFileMimeType() {
return fileMimeType;
}
public void setFileMimeType(String fileMimeType) {
this.fileMimeType = fileMimeType;
}
public int getImageWidth() {
return imageWidth;
}
public void setImageWidth(int imageWidth) {
this.imageWidth = imageWidth;
}
public int getImageHeight() {
return imageHeight;
}
public void setImageHeight(int imageHeight) {
this.imageHeight = imageHeight;
}
public short getImageThumbWidth() {
return imageThumbWidth;
}
public void setImageThumbWidth(short imageThumbWidth) {
this.imageThumbWidth = imageThumbWidth;
}
public short getImageThumbHeight() {
return imageThumbHeight;
}
public void setImageThumbHeight(short imageThumbHeight) {
this.imageThumbHeight = imageThumbHeight;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileExtension() {
return fileExtension;
}
public void setFileExtension(String fileExtension) {
this.fileExtension = fileExtension;
}
public int getFileSize() {
return fileSize;
}
public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getSenderRealAvatarUrl() {
if("http://".equalsIgnoreCase(this.senderAvatarUrl) || "https://".equalsIgnoreCase(this.senderAvatarUrl)) {
return this.senderAvatarUrl;
}
if(this.senderAvatarUrl != null && !this.senderAvatarUrl.trim().isEmpty()) {
return this.senderAvatarUrl;
}
return null;
}
@Override
public String toString() {
return "MessageDTO [id=" + id + ", channelId=" + channelId + ", channelType=" + channelType + ", createAt="
+ createAt + ", type=" + type + ", senderId=" + senderId + ", senderName=" + senderName
+ ", senderNickname=" + senderNickname + ", senderOnlineStatus=" + senderOnlineStatus
+ ", senderAvatarUrl=" + senderAvatarUrl + ", senderFirstLetterOfName=" + senderFirstLetterOfName
+ ", content=" + content + ", fileId=" + fileId + ", fileName=" + fileName + ", fileExtension="
+ fileExtension + ", fileSize=" + fileSize + ", fileMimeType=" + fileMimeType + ", imageWidth="
+ imageWidth + ", imageHeight=" + imageHeight + ", imageThumbWidth=" + imageThumbWidth
+ ", imageThumbHeight=" + imageThumbHeight + ", filePath=" + filePath + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/UserChannelDTO.java
================================================
package org.leo.im.api.dto;
/**
* 用户频道dto类
*
* @author Leo
* @date 2018/4/20
*/
public class UserChannelDTO {
private String channelId;
private String channelName;
private String channelType;
private String channelDisplayName;
private String channelDescription;
private String toUserId;
private String toUserOnlineStatus;
private short unreadMessageCount;
private int memberCount;
private String creatorId;
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public String getChannelType() {
return channelType;
}
public void setChannelType(String channelType) {
this.channelType = channelType;
}
public String getChannelDisplayName() {
return channelDisplayName;
}
public void setChannelDisplayName(String channelDisplayName) {
this.channelDisplayName = channelDisplayName;
}
public String getChannelDescription() {
return channelDescription;
}
public void setChannelDescription(String channelDescription) {
this.channelDescription = channelDescription;
}
public String getToUserId() {
return toUserId;
}
public void setToUserId(String toUserId) {
this.toUserId = toUserId;
}
public String getToUserOnlineStatus() {
return toUserOnlineStatus;
}
public void setToUserOnlineStatus(String toUserOnlineStatus) {
this.toUserOnlineStatus = toUserOnlineStatus;
}
public short getUnreadMessageCount() {
return unreadMessageCount;
}
public void setUnreadMessageCount(short unreadMessageCount) {
this.unreadMessageCount = unreadMessageCount;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public String getCreatorId() {
return creatorId;
}
public void setCreatorId(String creatorId) {
this.creatorId = creatorId;
}
@Override
public String toString() {
return "UserChannelDTO [channelId=" + channelId + ", channelName=" + channelName + ", channelType="
+ channelType + ", channelDisplayName=" + channelDisplayName + ", channelDescription="
+ channelDescription + ", toUserId=" + toUserId + ", toUserOnlineStatus=" + toUserOnlineStatus
+ ", unreadMessageCount=" + unreadMessageCount + ", memberCount=" + memberCount + ", creatorId="
+ creatorId + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/dto/UserDTO.java
================================================
package org.leo.im.api.dto;
/**
* 用户dto类
*
* @author Leo
* @date 2018/3/30
*/
public class UserDTO {
private String id;
private String name;
private String firstLetterOfName;
private String nickname;
private String password;
private String avatarUrl;
private Boolean locked;
private Long lastPostAt;
private String onlineStatus;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFirstLetterOfName() {
return firstLetterOfName;
}
public void setFirstLetterOfName(String firstLetterOfName) {
this.firstLetterOfName = firstLetterOfName;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAvatarUrl() {
return avatarUrl;
}
public void setAvatarUrl(String avatarUrl) {
this.avatarUrl = avatarUrl;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public Long getLastPostAt() {
return lastPostAt;
}
public void setLastPostAt(Long lastPostAt) {
this.lastPostAt = lastPostAt;
}
public String getOnlineStatus() {
return onlineStatus;
}
public void setOnlineStatus(String onlineStatus) {
this.onlineStatus = onlineStatus;
}
@Override
public String toString() {
return "UserDTO [id=" + id + ", name=" + name + ", firstLetterOfName=" + firstLetterOfName + ", nickname="
+ nickname + ", password=" + password + ", avatarUrl=" + avatarUrl + ", locked=" + locked
+ ", lastPostAt=" + lastPostAt + ", onlineStatus=" + onlineStatus + "]";
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/exception/ServiceException.java
================================================
package org.leo.im.api.exception;
/**
* 服务异常类
*
* @author Leo
* @date 2018/3/20
*/
public final class ServiceException extends RuntimeException {
private static final long serialVersionUID = 2447167264295739984L;
public ServiceException() {
}
public ServiceException(String message) {
super(message);
}
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
public ServiceException(Throwable cause) {
super(cause);
}
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/service/ChannelService.java
================================================
package org.leo.im.api.service;
import java.util.List;
import java.util.Map;
import org.leo.im.api.annotation.Transactional;
import org.leo.im.api.dto.ChannelDTO;
import org.leo.im.api.dto.ChannelListDTO;
import org.leo.im.api.dto.ChannelMemberDTO;
import org.leo.im.common.data.Page;
/**
* 频道管理服务接口
*
* @author Leo
* @date 2018/4/11
*/
public interface ChannelService {
/**
* 得到频道列表
* @param parameters
* @param limit
* @return
*/
List listChannel(Map parameters, int limit);
/**
* 得到群组频道列表
* @param parameters
* @param limit
* @return
*/
List listGroupChannel(Map parameters, int limit);
/**
* 添加频道
* @param dto
* @param creatorNickname
* @return
*/
@Transactional
ChannelDTO saveChannel(ChannelDTO dto, String creatorNickname);
/**
* 根据id得到频道信息
* @param id
* @return
*/
ChannelDTO getById(String id);
/**
* 得到用户是否为频道的管理员
* @param userId
* @param channelId
* @return
*/
boolean isAdmin(String userId, String channelId);
/**
* 更新频道名称
* @param channelId
* @param name
* @return
*/
@Transactional
int updateName(String channelId, String name);
/**
* 更新频道用途
* @param channelId
* @param purpose
* @return
*/
@Transactional
int updatePurpose(String channelId, String purpose);
/**
* 添加频道成员
* @param channelId
* @param userIds
* @param userNicknames
* @param admin
* @return
*/
@Transactional
int addMember(String channelId, String[] userIds, String[] userNicknames, String admin);
/**
* 移除组成员
* @param channelId
* @param memberId
* @param memberNickname
* @param admin
* @return
*/
@Transactional
int removeMember(String channelId, String memberId, String memberNickname, String admin);
/**
* 得到成员列表
* @param channelId
* @param username
* @param limit
* @param offset
* @return
*/
Page listMember(String channelId, String username, int limit, int offset);
/**
* 变更频道管理员
* @param channelId
* @param memberId
* @param isAdmin
* @return
*/
@Transactional
int changeAdmin(String channelId, String memberId, boolean isAdmin);
/**
* 离开频道
* @param channelId
* @param memberId
* @param memberNickname
* @return
*/
@Transactional
int leaveChannel(String channelId, String memberId, String memberNickname);
/**
* 删除频道
* @param channelId
* @param adminId
* @return
*/
@Transactional
int removeChannel(String channelId, String adminId);
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/service/MessageService.java
================================================
package org.leo.im.api.service;
import java.util.List;
import org.leo.im.api.annotation.Transactional;
import org.leo.im.api.dto.FileDTO;
import org.leo.im.api.dto.MessageDTO;
/**
* 消息服务接口
*
* @author Leo
* @date 2018/5/16
*/
public interface MessageService {
/**
* 得到消息列表
* @param channelId
* @param maxCreateAt
* @param limit
* @return
*/
List listMessage(String channelId, long maxCreateAt, int limit);
/**
* 根据id得到消息
* @param id
* @return
*/
MessageDTO getById(long id);
/**
* 添加消息
* @param dto
* @return
*/
@Transactional
MessageDTO saveMessage(MessageDTO dto);
/**
* 批量添加消息
* @param dtos
* @return
*/
@Transactional
int saveMessage(List dtos);
/**
* 读取消息
* @param channelId
* @param userId
* @param total
* @return
*/
@Transactional
int readMessage(String channelId, String userId, short total);
/**
* 删除消息
* @param messageId
* @param senderId
* @param channelId
* @param toUserId
* @return
*/
@Transactional
int removeMessage(long messageId, String senderId, String channelId, String toUserId);
/**
* 添加文件
* @param dto
* @return
*/
@Transactional
String saveFile(FileDTO dto);
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/service/UnreadMessageCountService.java
================================================
package org.leo.im.api.service;
import org.leo.im.api.annotation.Transactional;
/**
* 未读消息数量服务接口
* @author Administrator
*
*/
public interface UnreadMessageCountService {
/**
* 批量添加未读消息数量
* @param userIds
* @param channelId
* @param total
* @return
*/
@Transactional
int batchSaveUnreadMessageCount(String[] userIds, String channelId, short total);
/**
* 更新未读消息数量
* @param userId
* @param channelId
* @param total
* @return
*/
@Transactional
int updateUnreadMessageCount(String userId, String channelId, short total);
/**
* 批量更新未读消息数量
* @param userIds
* @param channelId
* @param total
* @return
*/
int batchUpdateUnreadMessageCount(String[] userIds, String channelId, short total);
/**
* 批量增加未读消息数量
* @param userIds
* @param channelId
* @param quantity
* @return
*/
@Transactional
int batchIncreaseUnreadMessageCount(String[] userIds, String channelId, short quantity);
/**
* 增加未读消息数量
* @param userId
* @param channelId
* @param quantity
* @return
*/
@Transactional
int increaseUnreadMessageCount(String userId, String channelId, short quantity);
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/service/UserChannelService.java
================================================
package org.leo.im.api.service;
import java.util.List;
import org.leo.im.api.annotation.Transactional;
import org.leo.im.api.dto.UserChannelDTO;
/**
* 用户频道服务接口
*
* @author Leo
* @date 2018/4/20
*/
public interface UserChannelService {
/**
* 得到用户频道列表
* @param userId
* @param type
* @param limit
* @return
*/
List listUserChannel(String userId, String type, int limit);
/**
* 得到用户频道
* @param userId
* @param channelId
* @return
*/
UserChannelDTO get(String userId, String channelId);
/**
* 更新用户频道
* @param channelId
* @param userId
* @param displayName
* @return
*/
@Transactional
int updateDisplayName(String channelId, String userId, String displayName);
/**
* 隐藏频道
* @param userId
* @param channelId
* @return
*/
@Transactional
int hideChannel(String userId, String channelId);
/**
* 根据名称得到用户频道列表
* @param userId
* @param name
* @param type
* @return
*/
List listByName(String userId, String name, String type);
}
================================================
FILE: leo-im-api/src/main/java/org/leo/im/api/service/UserService.java
================================================
package org.leo.im.api.service;
import java.util.Set;
import org.leo.im.api.annotation.Transactional;
import org.leo.im.api.dto.UserDTO;
import org.leo.im.common.data.Page;
/**
* 用户服务接口
*
* @author Leo
* @date 2018/4/9
*/
public interface UserService {
/**
* 验证用户登录
*
* @param loginName
* @param password
* @return
*/
UserDTO verifyLogin(String loginName, String password);
/**
* 根据id得到用户
*
* @param id
* @return
*/
UserDTO getById(String id);
/**
* 添加用户
*
* @param dto
* @return
*/
@Transactional
String saveUser(UserDTO dto);
/**
* 根据名称或昵称分页查询用户
*
* @param name
* @param limit
* @param offset
* @return
*/
Page listByNameOrNickname(String name, int limit, int offset);
/**
* 更新用户
* @param dto
* @param updateNullValueField
* @return
*/
@Transactional
UserDTO updateUser(UserDTO dto, boolean updateNullValueField);
/**
*
* @param channelId
* @param username
* @param limit
* @param offset
* @return
*/
Page listNonMembers(String channelId, String username, int limit, int offset);
/**
* 批量下线用户
* @param userIds
* @return
*/
@Transactional
int batchOffline(Set userIds);
/**
* 修改用户口令
* @param userId
* @param username
* @param oldPassword
* @param newPassword
* @return
*/
@Transactional
int updatePassword(String userId, String username, String oldPassword, String newPassword);
}
================================================
FILE: leo-im-api/src/test/java/org/leo/im/api/AppTest.java
================================================
package org.leo.im.api;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-api/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: leo-im-common-1.0.jar slf4j-api-1.7.25.jar logback-classic
-1.2.3.jar logback-core-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-api/target/classes/META-INF/maven/org.leo.im/leo-im-api/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:09 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-api
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-api
artifactId=leo-im-api
================================================
FILE: leo-im-api/target/classes/META-INF/maven/org.leo.im/leo-im-api/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-api
leo-im-api
http://maven.apache.org
org.leo.im
leo-im-common
${parent.version}
================================================
FILE: leo-im-api/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:09 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-api
================================================
FILE: leo-im-api/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-api/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\service\UserChannelService.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\annotation\Cacheable.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\service\UnreadMessageCountService.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\service\UserService.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\FileDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\UserDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\annotation\Transactional.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\exception\ServiceException.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\service\MessageService.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\ChannelDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\ChannelListDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\ChannelMemberDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\MessageDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\dto\UserChannelDTO.java
F:\Develop\open-source\leo-im-server\leo-im-api\src\main\java\org\leo\im\api\service\ChannelService.java
================================================
FILE: leo-im-api/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-api/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-api\src\test\java\org\leo\im\api\AppTest.java
================================================
FILE: leo-im-api/target/surefire-reports/TEST-org.leo.im.api.AppTest.xml
================================================
================================================
FILE: leo-im-api/target/surefire-reports/org.leo.im.api.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.api.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.097 sec
================================================
FILE: leo-im-api-provider/.classpath
================================================
================================================
FILE: leo-im-api-provider/.project
================================================
leo-im-api-provider
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-api-provider/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-api-provider/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-api-provider/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-api-provider/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-api-provider
leo-im-api-provider
http://maven.apache.org
UTF-8
org.leo.im
leo-im-api
${project.version}
org.leo.im
leo-im-service
${project.version}
================================================
FILE: leo-im-api-provider/src/main/java/org/leo/im/api/provider/ServiceFactory.java
================================================
package org.leo.im.api.provider;
import org.leo.im.api.service.ChannelService;
import org.leo.im.api.service.MessageService;
import org.leo.im.api.service.UserChannelService;
import org.leo.im.api.service.UserService;
import org.leo.im.service.ChannelServiceImpl;
import org.leo.im.service.MessageServiceImpl;
import org.leo.im.service.UserChannelServiceImpl;
import org.leo.im.service.UserServiceImpl;
/**
* 服务工厂类
*
* @author Leo
* @date 2018/3/30
*/
public final class ServiceFactory {
/**
* 创建用户服务的实例
*
* @return
*/
public static UserService createUserService() {
return new UserServiceImpl();
}
/**
* 创建频道服务的实例
* @return
*/
public static ChannelService createChannelService() {
return new ChannelServiceImpl();
}
/**
* 创建用户频道服务类的实例
* @return
*/
public static UserChannelService createUserChannelService() {
return new UserChannelServiceImpl();
}
/**
* 创建消息服务的实例
* @return
*/
public static MessageService createMessageService() {
return new MessageServiceImpl();
}
}
================================================
FILE: leo-im-api-provider/src/test/java/org/leo/im/api/provider/AppTest.java
================================================
package org.leo.im.api.provider;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-api-provider/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: leo-im-api-1.0.jar leo-im-common-1.0.jar leo-im-service-1.
0.jar leo-im-store-1.0.jar mysql-connector-java-8.0.11.jar protobuf-j
ava-2.6.0.jar druid-1.1.9.jar leo-im-model-1.0.jar leo-im-util-1.0.ja
r cglib-3.2.6.jar asm-6.0.jar ant-1.9.6.jar ant-launcher-1.9.6.jar jj
wt-0.9.0.jar jackson-databind-2.8.9.jar jackson-annotations-2.8.0.jar
jackson-core-2.8.9.jar leo-im-notification-1.0.jar jedis-2.9.0.jar c
ommons-pool2-2.4.2.jar fastjson-1.2.47.jar slf4j-api-1.7.25.jar logba
ck-classic-1.2.3.jar logback-core-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-api-provider/target/classes/META-INF/maven/org.leo.im/leo-im-api-provider/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:17 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-api-provider
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-api-provider
artifactId=leo-im-api-provider
================================================
FILE: leo-im-api-provider/target/classes/META-INF/maven/org.leo.im/leo-im-api-provider/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-api-provider
leo-im-api-provider
http://maven.apache.org
UTF-8
org.leo.im
leo-im-api
${project.version}
org.leo.im
leo-im-service
${project.version}
================================================
FILE: leo-im-api-provider/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:18 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-api-provider
================================================
FILE: leo-im-api-provider/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-api-provider/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-api-provider\src\main\java\org\leo\im\api\provider\ServiceFactory.java
================================================
FILE: leo-im-api-provider/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-api-provider/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-api-provider\src\test\java\org\leo\im\api\provider\AppTest.java
================================================
FILE: leo-im-api-provider/target/surefire-reports/TEST-org.leo.im.api.provider.AppTest.xml
================================================
================================================
FILE: leo-im-api-provider/target/surefire-reports/org.leo.im.api.provider.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.api.provider.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.087 sec
================================================
FILE: leo-im-common/.classpath
================================================
================================================
FILE: leo-im-common/.project
================================================
leo-im-common
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-common/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-common/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-common/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-common/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-common
leo-im-common
http://maven.apache.org
UTF-8
================================================
FILE: leo-im-common/src/main/java/org/leo/im/common/data/Page.java
================================================
package org.leo.im.common.data;
import java.util.List;
/**
* 分页查询结果类
*
* @author Leo
* @date 2018/4/8
* @param
*/
public final class Page implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private long total;
private List rows;
public Page(long total, List rows) {
this.total = total;
this.rows = rows;
}
public long getTotal() {
return this.total;
}
public List getRows() {
return this.rows;
}
}
================================================
FILE: leo-im-common/src/test/java/org/leo/im/common/AppTest.java
================================================
package org.leo.im.common;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-common/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: slf4j-api-1.7.25.jar logback-classic-1.2.3.jar logback-cor
e-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-common/target/classes/META-INF/maven/org.leo.im/leo-im-common/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:08 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-common
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-common
artifactId=leo-im-common
================================================
FILE: leo-im-common/target/classes/META-INF/maven/org.leo.im/leo-im-common/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-common
leo-im-common
http://maven.apache.org
UTF-8
================================================
FILE: leo-im-common/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:08 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-common
================================================
FILE: leo-im-common/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-common/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-common\src\main\java\org\leo\im\common\data\Page.java
================================================
FILE: leo-im-common/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-common/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-common\src\test\java\org\leo\im\common\AppTest.java
================================================
FILE: leo-im-common/target/surefire-reports/TEST-org.leo.im.common.AppTest.xml
================================================
================================================
FILE: leo-im-common/target/surefire-reports/org.leo.im.common.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.common.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.084 sec
================================================
FILE: leo-im-http/.classpath
================================================
================================================
FILE: leo-im-http/.project
================================================
leo-im-http
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-http/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-http/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-http/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-http/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-http
leo-im-http
http://maven.apache.org
UTF-8
org.ow2.asm
asm
6.1
net.coobird
thumbnailator
0.4.8
io.netty
netty-all
${netty.version}
com.alibaba
fastjson
${fastjson.version}
org.leo
netty-rest-server
1.0
org.leo.im
leo-im-api
${parent.version}
org.leo.im
leo-im-api-provider
${project.version}
org.leo.im
leo-im-util
${project.version}
org.leo.im
leo-im-notification
${project.version}
org.leo.im
leo-im-common
${project.version}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/HttpServer.java
================================================
package org.leo.im.http;
import org.leo.im.http.controller.ExceptionController;
import org.leo.im.http.interceptor.AuthenticationInterceptor;
import org.leo.im.http.interceptor.CorsInterceptor;
import org.leo.web.core.WebServer;
/**
* Leo IM REST API Server
*
* @author Leo
* @date 2018/4/2
*/
public final class HttpServer {
/**
* 启动api server
* @throws InterruptedException
*/
public void start() throws InterruptedException {
// 忽略指定url
WebServer.getIgnoreUrls().add("/favicon.ico");
// 全局异常处理
WebServer.setExceptionHandler(new ExceptionController());
// 设置监听端口号
WebServer server = new WebServer(Integer.getInteger("http.port"));
// 设置boss与worker线程数
server.setBossThreads(Integer.getInteger("http.boss.threads"));
server.setWorkerThreads(Integer.getInteger("http.worker.threads"));
// 设置Http最大内容长度(默认 为10M)
server.setMaxContentLength(1024 * 1024 * Integer.getInteger("http.max.content.length"));
// 设置Controller所在包
server.setControllerBasePackage("org.leo.im.http.controller");
// 添加拦截器,按照添加的顺序执行。
// 跨域拦截器
server.addInterceptor(new CorsInterceptor());
// 身份认证拦截器,设置例外url
server.addInterceptor(new AuthenticationInterceptor(), "/auth/login", "/auth/verificationCode",
"/users", "/messages/files");
server.start();
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/cache/Cache.java
================================================
package org.leo.im.http.cache;
/**
* 缓存
*
* @author Leo
* @date 2018/4/1
*/
final class Cache {
private Object value;
/**
* 缓存的生存时间,单位:秒
*/
private int timeout;
private long expireAt;
public Cache(Object value) {
this.value = value;
}
public Cache(Object value, int timeout) {
this.value = value;
this.timeout = timeout;
this.expireAt = System.currentTimeMillis() + this.timeout * 1000;
}
public Object getValue() {
return this.value;
}
public void setValue(Object value) {
this.value = value;
}
public int getTimeout() {
return this.timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
this.expireAt = System.currentTimeMillis() + this.timeout * 1000;
}
public long getExpireAt() {
return this.expireAt;
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/cache/CacheManager.java
================================================
package org.leo.im.http.cache;
/**
* 缓存管理接口
*
* @author Leo
* @date 2018/3/27
*/
public interface CacheManager {
/**
* 得到缓存
* @param key
* @return
*/
Object get(String key);
/**
* 设置缓存
* @param key
* @param value
*/
void put(String key, Object value);
/**
* 设置缓存
* @param key
* @param value
* @param timeout 生存时间,单位为秒。
*/
void put(String key, Object value, int timeout);
/**
* 删除缓存
* @param key
*/
void remove(String key);
/**
* 清除缓存
*/
void clear();
/**
* 清理超时缓存
*/
void clearExpired();
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/cache/CacheManagerFactory.java
================================================
package org.leo.im.http.cache;
/**
* 缓存管理器工厂类
*
* @author Leo
* @date 2018/3/27
*/
public final class CacheManagerFactory {
/**
* 得到缓存管理器的实例
*
* @return
*/
public static CacheManager getCacheManager() {
String cacheType = System.getProperty("cache.type") == null ? "map"
: System.getProperty("cache.type").toLowerCase();
switch (cacheType) {
case "map":
return MapCacheManager.getInstance();
default:
return MapCacheManager.getInstance();
}
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/cache/MapCacheManager.java
================================================
package org.leo.im.http.cache;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
/**
* 基于Java Map的缓存管理器
*
* @author Leo
* @date 2018/3/27
*/
final class MapCacheManager implements CacheManager {
private final static int CLEAR_INTERVAL = 10;
private Map caches = new ConcurrentHashMap<>(64);
private MapCacheManager() {
}
public static class InstanceHolder {
private static MapCacheManager instance = new MapCacheManager();
static {
instance.clearExpired();
}
}
public static MapCacheManager getInstance() {
return InstanceHolder.instance;
}
/**
* 得到缓存
* @param key
* @return
*/
@Override
public Object get(String key) {
Cache cache = caches.get(key);
return cache == null ? null : cache.getValue();
}
/**
* 添加缓存
*
* @param key
* @param value
*/
@Override
public void put(String key, Object value) {
Cache cache = new Cache(value);
caches.put(key, cache);
}
/**
* 添加缓存
*
* @param key
* @param value
* @param timeout
* 生存时间,单位为秒。
*/
@Override
public void put(String key, Object value, int timeout) {
Cache cache = new Cache(value, timeout);
caches.put(key, cache);
}
/**
* 删除缓存
*
* @param key
*/
@Override
public void remove(String key) {
this.caches.remove(key);
}
/**
* 清除缓存
*/
@Override
public void clear() {
this.caches.clear();
}
/**
* 清理超时缓存
*/
@Override
public void clearExpired() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
Set> entrySet = caches.entrySet();
long currentTime = System.currentTimeMillis();
for (Entry entry : entrySet) {
if (entry.getValue().getExpireAt() > 0 && currentTime >= entry.getValue().getExpireAt()) {
caches.remove(entry.getKey());
}
}
}
}, 1 * 1000, CLEAR_INTERVAL * 1000);
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/constant/CacheKeys.java
================================================
package org.leo.im.http.constant;
/**
* 缓存key常量类
*
* @author Leo
* @date 2018/4/1
*/
public final class CacheKeys {
/**
* JSession key前缀
*/
public static final String JSESSIONID = "JSESSIONID";
/**
* 验证码缓存key前缀
*/
public static final String VERIFICATION_CODE_PREFIX = "v-code-";
/**
* 登录失败次数缓存前缀
*/
public static final String LOGIN_FAILURE_COUNT = "login-failure-count_";
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/AuthController.java
================================================
package org.leo.im.http.controller;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.leo.im.api.service.UserService;
import org.leo.im.api.dto.UserDTO;
import org.leo.im.api.provider.ServiceFactory;
import org.leo.im.http.cache.CacheManagerFactory;
import org.leo.im.http.constant.CacheKeys;
import org.leo.im.http.util.JwtUtils;
import org.leo.im.service.support.ServiceProxy;
import org.leo.web.annotation.GetMapping;
import org.leo.web.annotation.PostMapping;
import org.leo.web.annotation.RequestMapping;
import org.leo.web.annotation.RestController;
import org.leo.web.annotation.UrlEncodedForm;
import org.leo.web.rest.HttpResponse;
import org.leo.web.rest.HttpStatus;
import org.leo.web.rest.ResponseEntity;
import com.alibaba.fastjson.JSONObject;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.cookie.Cookie;
/**
* 认证控制器
*
* @author Leo
* @date 2018/4/4
*/
@RestController
@RequestMapping("/auth")
public final class AuthController extends BaseController {
/**
* Session超时时间,单位:秒。
*/
private static final int SESSION_TIMEOUT = 5 * 60;
/**
* 验证码超时时间,默认为120秒。
*/
private static final int VERIFICATION_CODE_TIMEOUT = 2 * 60;
/**
* 登录重试次数
*/
private static final int LOGIN_RETRY_COUNT = 5;
/**
* 登录失败次数缓存超时时间,单位:秒
*/
private static final int LOGIN_FAILURE_COUNT_TIMEOUT = 5 * 60;
@PostMapping("/login")
public ResponseEntity> login(FullHttpRequest request, HttpResponse response, @UrlEncodedForm Map form) {
String sessionId = getJSessionId(request);
if(sessionId == null) {
// Session不存在
sessionId = UUID.randomUUID().toString().replaceAll("-", "");
response.getCookies().put(CacheKeys.JSESSIONID, sessionId);
}
CacheManagerFactory.getCacheManager().put(sessionId, (byte)0, SESSION_TIMEOUT);
// 检查登录失败次数
Object loginFailureCount = CacheManagerFactory.getCacheManager().get(CacheKeys.LOGIN_FAILURE_COUNT + sessionId);
if(loginFailureCount != null) {
if((int)loginFailureCount >= LOGIN_RETRY_COUNT) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build("登录失败次数过多,请稍后重试");
}
}
// 检查验证码
/*String verificationCode = form.get("verificationCode");
if(verificationCode == null || verificationCode.trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("验证码为空");
}
if(sessionId == null || sessionId.trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("无效的请求");
}
Object verificationCodeInCache = CacheManagerFactory.getCacheManager().get(CacheKeys.VERIFICATION_CODE_PREFIX + sessionId);
if(verificationCodeInCache == null || verificationCodeInCache.toString().trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("无效的验证码");
}
if(!verificationCode.equals(verificationCodeInCache)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("无效的验证码");
}*/
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
UserDTO dto = serviceProxy.verifyLogin(form.get("username"), form.get("password"));
if (dto == null) {
int userLoginFailureCount = (loginFailureCount == null ? 0 : (int)loginFailureCount);
CacheManagerFactory.getCacheManager().put(CacheKeys.LOGIN_FAILURE_COUNT + sessionId, ++userLoginFailureCount, LOGIN_FAILURE_COUNT_TIMEOUT);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
JSONObject json = new JSONObject();
json.put("userId", dto.getId());
String jwt = JwtUtils.createJWT(json.toJSONString(), System.getProperty("jwt.secret"), Long.getLong("jwt.ttl.millis"));
Map result = new HashMap<>();
result.put("userId", dto.getId());
result.put("username", dto.getName());
result.put("nickname", dto.getNickname());
result.put("firstLetterOfName", dto.getFirstLetterOfName());
result.put("avatarUrl", dto.getAvatarUrl());
result.put("token", jwt);
// 删除缓存中的验证码
// CacheManagerFactory.getCacheManager().remove(CacheKeys.VERIFICATION_CODE_PREFIX + sessionId);
// 删除登录失败次数缓存
CacheManagerFactory.getCacheManager().remove(CacheKeys.LOGIN_FAILURE_COUNT + sessionId);
return ResponseEntity.ok(result);
}
@GetMapping("/verificationCode")
public ResponseEntity getVerificationCode(FullHttpRequest request, HttpResponse response) {
String verificationCode = UUID.randomUUID().toString().substring(0, 4);
String sessionId = null;
if((sessionId = getJSessionId(request)) == null) {
// Session不存在
sessionId = UUID.randomUUID().toString().replaceAll("-", "");
response.getCookies().put(CacheKeys.JSESSIONID, sessionId);
}
CacheManagerFactory.getCacheManager().put(sessionId, (byte)0, SESSION_TIMEOUT);
CacheManagerFactory.getCacheManager().put(CacheKeys.VERIFICATION_CODE_PREFIX + sessionId, verificationCode, VERIFICATION_CODE_TIMEOUT);
return ResponseEntity.ok(verificationCode);
}
/**
* 从cookie中得到Session Id
* @param request
* @return
*/
private String getJSessionId(FullHttpRequest request) {
try {
String cookieStr = request.headers().get("Cookie");
if(cookieStr == null || cookieStr.trim().isEmpty()) {
return null;
}
Set cookies = ServerCookieDecoder.STRICT.decode(cookieStr);
Iterator it = cookies.iterator();
while (it.hasNext()) {
Cookie cookie = it.next();
if (cookie.name().equals(CacheKeys.JSESSIONID)) {
if (CacheManagerFactory.getCacheManager().get(cookie.value()) != null) {
return cookie.value();
}
}
}
} catch (Exception e1) {
return null;
}
return null;
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/BaseController.java
================================================
package org.leo.im.http.controller;
import org.leo.im.http.util.JwtUtils;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
/**
* 控制器基类
*
* @author Leo
* @date 2018/3/26
*/
public class BaseController {
/**
* 从jwt中获取subject信息
* @param jwtUtils
* @param jwt
* @param key
* @return
*/
protected String getSubjectFromJwt(String jwt, String key) {
Claims claims = JwtUtils.parseJWT(jwt, System.getProperty("jwt.secret"));
String subject = claims.getSubject();
if(key != null && !key.trim().equals("")) {
JSONObject json = JSONObject.parseObject(subject);
return json.getString(key);
} else {
return subject;
}
}
/**
* 验证jwt
* @param jwt
* @return
*/
protected boolean verifyJwt(String jwt) {
try {
JwtUtils.parseJWT(jwt, System.getProperty("jwt.secret"));
return true;
} catch(Exception e) {
return false;
}
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/ChannelController.java
================================================
package org.leo.im.http.controller;
import org.leo.im.api.dto.ChannelDTO;
import org.leo.im.api.dto.ChannelMemberDTO;
import org.leo.im.api.provider.ServiceFactory;
import org.leo.im.api.service.ChannelService;
import org.leo.im.common.data.Page;
import org.leo.im.http.vo.ChannelVO;
import org.leo.im.http.vo.UserChannelVO;
import org.leo.im.service.support.ServiceProxy;
import org.leo.im.util.BeanUtils;
import org.leo.web.annotation.DeleteMapping;
import org.leo.web.annotation.GetMapping;
import org.leo.web.annotation.PatchMapping;
import org.leo.web.annotation.PathVariable;
import org.leo.web.annotation.PostMapping;
import org.leo.web.annotation.PutMapping;
import org.leo.web.annotation.RequestBody;
import org.leo.web.annotation.RequestHeader;
import org.leo.web.annotation.RequestMapping;
import org.leo.web.annotation.RequestParam;
import org.leo.web.annotation.RestController;
import org.leo.web.rest.ResponseEntity;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.netty.handler.codec.http.FullHttpRequest;
/**
* 频道控制器
*
* @author Leo
* @date 2018/4/3
*/
@RestController
@RequestMapping("/channels")
public final class ChannelController extends BaseController {
@PostMapping("")
public ResponseEntity createChannel(FullHttpRequest request, @RequestHeader("X-Token") String token,
@RequestBody String body) {
String userId = this.getSubjectFromJwt(token, "userId");
ChannelDTO dto = new ChannelDTO();
JSONObject json = JSONObject.parseObject(body);
dto.setType(json.getString("type"));
if ("G".equals(dto.getType())) {
dto.setName(json.getString("name"));
dto.setPurpose(json.getString("purpose"));
JSONArray members = json.getJSONArray("members");
dto.setMemberCount(members.size());
for(int i = 0; i < members.size(); i++) {
ChannelMemberDTO member = new ChannelMemberDTO();
JSONObject memberJson = members.getJSONObject(i);
member.setId(memberJson.getString("id"));
member.setNickname(memberJson.getString("nickname"));
member.setAdmin(memberJson.getString("id").equals(userId));
dto.getMembers().add(member);
}
}
if ("P".equals(dto.getType())) {
dto.setFromUserId(userId);
dto.setFromUsername(json.getString("fromUsername"));
dto.setFromUserNickname(json.getString("fromUserNickname"));
dto.setToUserId(json.getString("toUserId"));
dto.setToUsername(json.getString("toUsername"));
dto.setToUserNickname(json.getString("toUserNickname"));
dto.setName(dto.getToUserNickname() != null && !dto.getToUserNickname().trim().isEmpty() ?
dto.getToUserNickname() : dto.getToUsername());
dto.setMemberCount(2);
ChannelMemberDTO member1 = new ChannelMemberDTO();
member1.setId(userId);
member1.setAdmin(true);
dto.getMembers().add(member1);
ChannelMemberDTO member2 = new ChannelMemberDTO();
member2.setId(dto.getToUserId());
dto.getMembers().add(member2);
}
dto.setCreatorId(userId);
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
ChannelDTO returnDTO = serviceProxy.saveChannel(dto, json.getString("creatorNickname"));
UserChannelVO vo = new UserChannelVO();
BeanUtils.copyProperties(returnDTO, vo);
vo.setChannelId(returnDTO.getId());
vo.setChannelName(returnDTO.getName());
vo.setChannelDisplayName(getChannelDisplayName(returnDTO, userId));
vo.setChannelType(returnDTO.getType());
return ResponseEntity.created(vo);
}
@GetMapping("/{id}")
public ResponseEntity getById(@PathVariable("id") String id) {
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
ChannelDTO dto = serviceProxy.getById(id);
if(dto == null) {
return ResponseEntity.notFound().build();
}
ChannelVO vo = new ChannelVO();
BeanUtils.copyProperties(dto, vo);
return ResponseEntity.ok(vo);
}
@GetMapping("/{channelId}/isAdmin")
public ResponseEntity isAdmin(@PathVariable("channelId") String channelId, @RequestHeader("X-Token") String token) {
String userId = this.getSubjectFromJwt(token, "userId");
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
boolean isAdmin = serviceProxy.isAdmin(userId, channelId);
return ResponseEntity.ok(isAdmin);
}
@PatchMapping("/{channelId}")
public ResponseEntity> updateChannel(@PathVariable("channelId") String channelId, @RequestBody String body) {
JSONObject json = JSONObject.parseObject(body);
ChannelService serviceProxy = null;
if(json.containsKey("name")) {
serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
int count = serviceProxy.updateName(channelId, json.getString("name"));
return ResponseEntity.ok(count);
}
if(json.containsKey("purpose")) {
serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
int count = serviceProxy.updatePurpose(channelId, json.getString("purpose"));
return ResponseEntity.ok(count);
}
return ResponseEntity.internalServerError("not found allowed filed in body");
}
@GetMapping("/{channelId}/members")
public ResponseEntity> listMember(@PathVariable("channelId") String channelId,
@RequestParam("username") String username, @RequestParam("limit") int limit, @RequestParam("offset") int offset) {
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
Page result = serviceProxy.listMember(channelId, username, limit, offset);
return ResponseEntity.ok(result);
}
@PostMapping("/{channelId}/members")
public ResponseEntity addMember(@PathVariable("channelId") String channelId, @RequestBody String body) {
JSONObject data = JSONObject.parseObject(body);
JSONArray jsonArray = data.getJSONArray("users");
String[] userIds = new String[jsonArray.size()];
String[] userNicknames = new String[jsonArray.size()];
for(int i = 0; i < userIds.length; i++) {
userIds[i] = jsonArray.getJSONObject(i).getString("id");
userNicknames[i] = jsonArray.getJSONObject(i).getString("nickname");
}
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
int count = serviceProxy.addMember(channelId, userIds, userNicknames, data.getString("admin"));
return ResponseEntity.created(count);
}
@DeleteMapping("/{channelId}/members")
public ResponseEntity removeMember(@PathVariable("channelId") String channelId, @RequestBody String body) {
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
JSONObject data = JSONObject.parseObject(body);
int count = serviceProxy.removeMember(channelId, data.getString("memberId"), data.getString("memberNickname"),
data.getString("admin"));
if(count > 0) {
return ResponseEntity.noContent(count);
}
return ResponseEntity.notFound().build();
}
@PutMapping("/{channelId}/admin")
public ResponseEntity changeAdmin(@PathVariable("channelId") String channelId, @RequestBody String body) {
JSONObject json = JSONObject.parseObject(body);
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
int count = serviceProxy.changeAdmin(channelId, json.getString("memberId"), json.getBooleanValue("isAdmin"));
return ResponseEntity.created(count);
}
/**
* 离开频道
* @param channelId
* @param body
* @return
*/
@DeleteMapping("/{channelId}/members/{memberId}")
public ResponseEntity leaveChannel(@PathVariable("channelId") String channelId, @PathVariable("memberId") String memberId,
@RequestBody String body) {
JSONObject data = JSONObject.parseObject(body);
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
int count = serviceProxy.leaveChannel(channelId, memberId, data.getString("memberNickname"));
return ResponseEntity.noContent(count);
}
@DeleteMapping("/{channelId}")
public ResponseEntity removeChannel(@PathVariable("channelId") String channelId, @RequestHeader("X-Token") String token) {
String userId = this.getSubjectFromJwt(token, "userId");
ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
int count = serviceProxy.removeChannel(channelId, userId);
return ResponseEntity.noContent(count);
}
/**
* 得到频道的显示名称
* @param dto
* @param creatorId
* @return
*/
private String getChannelDisplayName(ChannelDTO dto, String creatorId) {
if(dto.getType().equals("G")) {
return dto.getName();
}
if(dto.getCreatorId().equals(creatorId)) {
return dto.getToUserNickname();
}
return dto.getFromUserNickname();
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/ExceptionController.java
================================================
package org.leo.im.http.controller;
import org.leo.web.exception.ResourceNotFoundException;
import org.leo.web.rest.HttpContextHolder;
import org.leo.web.rest.HttpResponse;
import org.leo.web.rest.HttpStatus;
import org.leo.web.rest.controller.ExceptionHandler;
/**
* 异常处理器
*
* @author Leo
* @date 2018/3/30
*/
public class ExceptionController implements ExceptionHandler {
/**
* 处理异常
*
* @param e
*/
@Override
public void doHandle(Exception e) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
if (e instanceof ResourceNotFoundException) {
status = HttpStatus.NOT_FOUND;
}
String errorMessage = e.getCause() == null ? "" : e.getCause().getMessage();
if (errorMessage == null) {
errorMessage = e.getMessage();
}
HttpResponse response = HttpContextHolder.getResponse();
response.write(status, errorMessage);
response.closeChannel();
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/MessageController.java
================================================
package org.leo.im.http.controller;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.leo.im.api.dto.FileDTO;
import org.leo.im.api.dto.MessageDTO;
import org.leo.im.api.provider.ServiceFactory;
import org.leo.im.api.service.MessageService;
import org.leo.im.http.file.FileStorage;
import org.leo.im.http.file.FileStorageFactory;
import org.leo.im.http.vo.MessageVO;
import org.leo.im.service.support.ServiceProxy;
import org.leo.im.util.BeanUtils;
import org.leo.web.annotation.DeleteMapping;
import org.leo.web.annotation.GetMapping;
import org.leo.web.annotation.PostMapping;
import org.leo.web.annotation.RequestBody;
import org.leo.web.annotation.RequestHeader;
import org.leo.web.annotation.RequestMapping;
import org.leo.web.annotation.RequestParam;
import org.leo.web.annotation.RestController;
import org.leo.web.annotation.UploadFile;
import org.leo.web.annotation.UrlEncodedForm;
import org.leo.web.multipart.MultipartFile;
import org.leo.web.rest.ResponseEntity;
import com.alibaba.fastjson.JSONObject;
import io.netty.handler.codec.http.FullHttpRequest;
/**
* 消息控制器
*
* @author Leo
* @date 2018/5/16
*/
@RestController()
@RequestMapping("/messages")
public final class MessageController extends BaseController {
@GetMapping("")
public ResponseEntity> listMessage(@RequestParam("channelId") String channelId,
@RequestParam("maxCreateAt") long maxCreateAt, @RequestParam("limit") int limit) {
MessageService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createMessageService());
List dtoList = serviceProxy.listMessage(channelId, maxCreateAt, limit);
List voList = new ArrayList<>(dtoList.size());
for(MessageDTO dto : dtoList) {
MessageVO vo = new MessageVO();
BeanUtils.copyProperties(dto, vo);
voList.add(vo);
}
return ResponseEntity.ok(voList);
}
@PostMapping("")
public ResponseEntity> saveMessage(FullHttpRequest request, @RequestHeader("X-Token") String token,
@RequestBody String body) {
String userId = this.getSubjectFromJwt(token, "userId");
JSONObject json = JSONObject.parseObject(body);
MessageDTO dto = new MessageDTO();
dto.setSenderId(userId);
if(json.containsKey("type")) {
dto.setType(json.getString("type"));
}
dto.setChannelId(json.getString("channelId"));
dto.setContent(json.getString("content"));
dto.setCreateAt(new Date().getTime());
MessageService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createMessageService());
MessageDTO returnDTO = serviceProxy.saveMessage(dto);
if(returnDTO != null) {
MessageVO vo = new MessageVO();
BeanUtils.copyProperties(returnDTO, vo);
return ResponseEntity.created(vo);
}
return ResponseEntity.notFound().build();
}
@PostMapping("/read")
public ResponseEntity> readMessage(@RequestHeader("X-Token") String token, @RequestBody String body) {
String userId = this.getSubjectFromJwt(token, "userId");
JSONObject json = JSONObject.parseObject(body);
MessageService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createMessageService());
int count = serviceProxy.readMessage(json.getString("channelId"), userId, json.getShortValue("total"));
return ResponseEntity.created(count);
}
@DeleteMapping("")
public ResponseEntity> removeMessage(@RequestHeader("X-Token") String token, @RequestBody String body) {
String userId = this.getSubjectFromJwt(token, "userId");
MessageService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createMessageService());
JSONObject json = JSONObject.parseObject(body);
int count = serviceProxy.removeMessage(json.getLongValue("messageId"), userId, json.getString("channelId"),
json.getString("toUserId"));
if(count == 1) {
return ResponseEntity.noContent(count);
}
return ResponseEntity.notFound().build();
}
@PostMapping("/files")
public ResponseEntity> uploadFile(@UploadFile MultipartFile file, @RequestHeader("X-Token") String token,
@UrlEncodedForm Map form) {
String userId = this.getSubjectFromJwt(token, "userId");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String fileKey = sdf.format(new Date()) + "/" + UUID.randomUUID().toString().replace("-", "");
// 保存文件
FileStorage fs = FileStorageFactory.newInstance();
fs.save(fileKey, file.getFileName(), file.getFileData());
int width = Integer.parseInt(form.get("imageWidth"));
int height = Integer.parseInt(form.get("imageHeight"));
short thumbWidth = getThumbWidth(width);
short thumbHeight = getThumbHeight(height);
short[] realThumbSize = new short[] { 0, 0 };
// 如果是图片,保存略缩图
if(this.isImage(file.getFileType())) {
realThumbSize = fs.saveThumb(fileKey + "/thumb", file.getFileName(), file.getFileData(), thumbWidth, thumbHeight);
}
// 保存文件信息到数据库
MessageService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createMessageService());
FileDTO fileDTO = new FileDTO();
fileDTO.setName(file.getFileName());
fileDTO.setExtension(getFileExtension(file.getFileName()));
fileDTO.setSize(Integer.parseInt(form.get("size")));
fileDTO.setMimeType(file.getFileType());
fileDTO.setWidth(width);
fileDTO.setHeight(height);
fileDTO.setThumbWidth(realThumbSize[0]);
fileDTO.setThumbHeight(realThumbSize[1]);
fileDTO.setPath(fileKey);
String fileId = serviceProxy.saveFile(fileDTO);
// 保存消息
MessageDTO messageDTO = new MessageDTO();
messageDTO.setSenderId(userId);
messageDTO.setChannelId(form.get("channelId"));
messageDTO.setCreateAt(new Date().getTime());
messageDTO.setFileId(fileId);
MessageDTO returnDTO = serviceProxy.saveMessage(messageDTO);
if(returnDTO != null) {
MessageVO vo = new MessageVO();
BeanUtils.copyProperties(returnDTO, vo);
return ResponseEntity.created(vo);
}
return ResponseEntity.notFound().build();
}
@GetMapping("/files")
public ResponseEntity getFile(@RequestParam("fileName") String fileName, @RequestParam("fullPath") String fullPath,
@RequestParam("mimetype") String mimetype) {
FileStorage fs = FileStorageFactory.newInstance();
RandomAccessFile raf = fs.read(fullPath);
return ResponseEntity.ok(raf, mimetype, fileName);
}
/**
* 判断是否为图片类型
* @param fileType
* @return
*/
private boolean isImage(String fileType) {
if("image/jpeg".equalsIgnoreCase(fileType)) {
return true;
}
if("image/png".equalsIgnoreCase(fileType)) {
return true;
}
return false;
}
/**
* 得到缩略图宽度
* @param width
* @return
*/
private short getThumbWidth(int width) {
if(width <= 119) {
return (short)width;
}
return 119;
}
/**
* 得到缩略图宽度
* @param width
* @return
*/
private short getThumbHeight(int height) {
if(height <= 81) {
return (short)height;
}
return 81;
}
/**
* 得到文件扩展名
* @param fileName
* @return
*/
private String getFileExtension(String fileName) {
String[] nameSplit = fileName.split("[.]");
return nameSplit[nameSplit.length - 1];
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/UserChannelController.java
================================================
package org.leo.im.http.controller;
import java.util.ArrayList;
import java.util.List;
import org.leo.im.api.dto.UserChannelDTO;
import org.leo.im.api.provider.ServiceFactory;
import org.leo.im.api.service.UserChannelService;
import org.leo.im.http.vo.UserChannelVO;
import org.leo.im.service.support.ServiceProxy;
import org.leo.im.util.BeanUtils;
import org.leo.web.annotation.GetMapping;
import org.leo.web.annotation.PatchMapping;
import org.leo.web.annotation.PathVariable;
import org.leo.web.annotation.PostMapping;
import org.leo.web.annotation.RequestBody;
import org.leo.web.annotation.RequestHeader;
import org.leo.web.annotation.RequestMapping;
import org.leo.web.annotation.RequestParam;
import org.leo.web.annotation.RestController;
import org.leo.web.rest.ResponseEntity;
@RestController
@RequestMapping("/userChannels")
public final class UserChannelController extends BaseController {
@GetMapping("/{userId}")
public ResponseEntity> listUserChannel(@PathVariable("userId") String userId,
@RequestParam("limit") int limit) {
UserChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserChannelService());
List dtoList = serviceProxy.listUserChannel(userId, null, limit);
if(dtoList.isEmpty()) {
return ResponseEntity.ok(new ArrayList());
}
List voList = new ArrayList<>(dtoList.size());
for(UserChannelDTO dto : dtoList) {
UserChannelVO vo = new UserChannelVO();
BeanUtils.copyProperties(dto, vo);
voList.add(vo);
}
return ResponseEntity.ok(voList);
}
@GetMapping("")
public ResponseEntity getUserChannel(@RequestParam("userId") String userId,
@RequestParam("channelId") String channelId) {
UserChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserChannelService());
UserChannelDTO dto = serviceProxy.get(userId, channelId);
if(dto == null) {
return ResponseEntity.notFound().build();
}
UserChannelVO vo = new UserChannelVO();
BeanUtils.copyProperties(dto, vo);
return ResponseEntity.ok(vo);
}
/**
* 修改频道显示名称
* @param body
* @return
*/
@PatchMapping("/{channelId}")
public ResponseEntity updateDisplayName(@PathVariable("channelId") String channelId, @RequestBody String displayName,
@RequestHeader("X-Token") String token) {
String userId = this.getSubjectFromJwt(token, "userId");
UserChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserChannelService());
int count = serviceProxy.updateDisplayName(channelId, userId, displayName);
return ResponseEntity.created(count);
}
/**
* 隐藏频道
* @param channelId
* @param token
* @return
*/
@PostMapping("/{channelId}/hiding")
public ResponseEntity hideChannel(@PathVariable("channelId") String channelId, @RequestHeader("X-Token") String token) {
String userId = this.getSubjectFromJwt(token, "userId");
UserChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserChannelService());
int count = serviceProxy.hideChannel(userId, channelId);
return ResponseEntity.created(count);
}
/**
* 根据名称搜索用户频道
* @param userId
* @param name
* @return
*/
@GetMapping("/{userId}/search")
public ResponseEntity> listUserChannelByName(@PathVariable("userId") String userId,
@RequestParam("name") String name) {
UserChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserChannelService());
List dtoList = serviceProxy.listByName(userId, name, null);
if(dtoList.isEmpty()) {
return ResponseEntity.ok(new ArrayList());
}
List voList = new ArrayList<>(dtoList.size());
for(UserChannelDTO dto : dtoList) {
UserChannelVO vo = new UserChannelVO();
BeanUtils.copyProperties(dto, vo);
voList.add(vo);
}
return ResponseEntity.ok(voList);
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/controller/UserController.java
================================================
package org.leo.im.http.controller;
import org.leo.im.api.service.UserService;
import org.leo.im.common.data.Page;
import org.leo.im.http.cache.CacheManagerFactory;
import org.leo.im.http.constant.CacheKeys;
import org.leo.im.http.file.AvatarStorage;
import org.leo.im.http.file.AvatarStorageFactory;
import java.io.RandomAccessFile;
import java.util.Iterator;
import java.util.Set;
import org.leo.im.api.dto.UserDTO;
import org.leo.im.api.provider.ServiceFactory;
import org.leo.im.service.support.ServiceProxy;
import org.leo.web.annotation.GetMapping;
import org.leo.web.annotation.PatchMapping;
import org.leo.web.annotation.PathVariable;
import org.leo.web.annotation.PostMapping;
import org.leo.web.annotation.PutMapping;
import org.leo.web.annotation.RequestBody;
import org.leo.web.annotation.RequestHeader;
import org.leo.web.annotation.RequestMapping;
import org.leo.web.annotation.RequestParam;
import org.leo.web.annotation.RestController;
import org.leo.web.annotation.UploadFile;
import org.leo.web.multipart.MultipartFile;
import org.leo.web.rest.HttpStatus;
import org.leo.web.rest.ResponseEntity;
import com.alibaba.fastjson.JSONObject;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
/**
* 用户控制器
*
* @author Leo
* @date 2018/4/9
*/
@RestController()
@RequestMapping("/users")
public final class UserController extends BaseController {
@GetMapping("/{id}")
public ResponseEntity getById(@PathVariable() String id) {
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
UserDTO dto = serviceProxy.getById(id);
return ResponseEntity.ok(dto);
}
@GetMapping("/me")
public ResponseEntity getCurrentUser(@RequestHeader("X-Token") String token) {
String userId = this.getSubjectFromJwt(token, "userId");
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
UserDTO dto = serviceProxy.getById(userId);
return ResponseEntity.ok(dto);
}
@PostMapping("")
public ResponseEntity> register(FullHttpRequest request, @RequestBody String body) {
// 检查验证码
JSONObject json = JSONObject.parseObject(body);
String verificationCode = json.getString("verificationCode");
if(verificationCode == null || verificationCode.trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("验证码为空");
}
String sessionId = getJSessionId(request);
if(sessionId == null || sessionId.trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("无效的请求");
}
Object verificationCodeInCache = CacheManagerFactory.getCacheManager().get(CacheKeys.VERIFICATION_CODE_PREFIX + sessionId);
if(verificationCodeInCache == null || verificationCodeInCache.toString().trim().isEmpty()) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("无效的验证码");
}
if(!verificationCode.equals(verificationCodeInCache)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build("无效的验证码");
}
// 注册用户
UserDTO dto = new UserDTO();
dto.setName(json.getString("name"));
dto.setNickname(json.getString("nickname"));
dto.setPassword(json.getString("password"));
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
serviceProxy.saveUser(dto);
return ResponseEntity.created().build();
}
@GetMapping("")
public ResponseEntity> listUser(@RequestParam("name") String name, @RequestParam("limit") int limit,
@RequestParam("offset") int offset) {
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
Page result = serviceProxy.listByNameOrNickname(name, limit, offset);
return ResponseEntity.ok(result);
}
@PatchMapping("/{id}")
public ResponseEntity patchUser(@PathVariable() String id, @RequestBody String body) {
JSONObject json = JSONObject.parseObject(body);
UserDTO dto = new UserDTO();
dto.setId(id);
if(json.containsKey("nickname")) {
dto.setNickname(json.getString("nickname"));
}
if(json.containsKey("password")) {
dto.setPassword(json.getString("password"));
}
if(json.containsKey("locked")) {
dto.setLocked(json.getBoolean("locked"));
}
if(json.containsKey("avatarUrl") && !json.getString("avatarUrl").trim().isEmpty()) {
dto.setAvatarUrl(json.getString("avatarUrl"));
}
if(json.containsKey("lastPostAt")) {
dto.setLastPostAt(json.getLong("lastPostAt"));
}
if(json.containsKey("onlineStatus")) {
dto.setOnlineStatus(json.getString("onlineStatus"));
}
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
UserDTO returnDTO = serviceProxy.updateUser(dto, false);
return ResponseEntity.created(returnDTO);
}
@PostMapping("/me/avatar")
public ResponseEntity uploadAvatar(@UploadFile MultipartFile avatar, @RequestHeader("X-Token") String token) {
String userId = this.getSubjectFromJwt(token, "userId");
String imageType = "png";
if("image/jpeg".equalsIgnoreCase(avatar.getFileType())) {
imageType = "jpg";
}
// 生成两张图片,尺寸分别为 32x32、36x36、80x80
AvatarStorage as = AvatarStorageFactory.newInstance();
as.save(userId, imageType, avatar.getFileData(), 32, 32);
as.save(userId, imageType, avatar.getFileData(), 36, 36);
as.save(userId, imageType, avatar.getFileData(), 80, 80);
return ResponseEntity.created("avatar." + imageType);
}
@GetMapping("/{id}/avatar")
public ResponseEntity getMyAvatar(@PathVariable("id") String userId, @RequestParam("width") int width,
@RequestParam("height") int height) {
// 得到用户头像
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
UserDTO dto = serviceProxy.getById(userId);
if(dto != null) {
String avatarUrl = dto.getAvatarUrl();
if(avatarUrl != null && !avatarUrl.trim().isEmpty()) {
AvatarStorage as = AvatarStorageFactory.newInstance();
RandomAccessFile raf = as.read(userId, avatarUrl, width, height);
String mimetype = avatarUrl.toLowerCase().trim().endsWith("png") ? "image/png" : "image/jpeg";
return ResponseEntity.ok(raf, mimetype);
}
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
@GetMapping("/nonChannelMembers")
public ResponseEntity> listNonChannelMember(@RequestParam("channelId") String channelId,
@RequestParam("username") String username, @RequestParam("limit") int limit, @RequestParam("offset") int offset) {
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
Page result = serviceProxy.listNonMembers(channelId, username, limit, offset);
return ResponseEntity.ok(result);
}
@PutMapping("/{userId}/password")
public ResponseEntity changePassword(@PathVariable("userId") String userId, @RequestHeader("X-Token") String token,
@RequestBody String body) {
String currentUserId = this.getSubjectFromJwt(token, "userId");
if(!userId.equals(currentUserId)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
JSONObject data = JSONObject.parseObject(body);
UserService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createUserService());
int count = serviceProxy.updatePassword(userId, data.getString("username"), data.getString("oldPassword"), data.getString("newPassword"));
return ResponseEntity.ok(count);
}
/**
* 从cookie中得到Session Id
* @return
*/
private String getJSessionId(FullHttpRequest request) {
try {
String cookieStr = request.headers().get("Cookie");
if(cookieStr == null || cookieStr.trim().isEmpty()) {
return null;
}
Set cookies = ServerCookieDecoder.STRICT.decode(cookieStr);
Iterator it = cookies.iterator();
while (it.hasNext()) {
Cookie cookie = it.next();
if (cookie.name().equals(CacheKeys.JSESSIONID)) {
if (CacheManagerFactory.getCacheManager().get(cookie.value()) != null) {
return cookie.value();
}
}
}
} catch (Exception e1) {
return null;
}
return null;
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/exception/NoSuchSettingException.java
================================================
package org.leo.im.http.exception;
/**
* 无此配置异常类
*
* @author Leo
* @date 2018/5/11
*/
public final class NoSuchSettingException extends RuntimeException {
private static final long serialVersionUID = 1911497055661761968L;
public NoSuchSettingException() {
}
public NoSuchSettingException(String message) {
super(message);
}
public NoSuchSettingException(String message, Throwable cause) {
super(message, cause);
}
public NoSuchSettingException(Throwable cause) {
super(cause);
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/AbstractLocalFileStorage.java
================================================
package org.leo.im.http.file;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
/**
* 本地文件存储抽象类
*
* @author Leo
* @date 2018/5/12
*/
abstract class AbstractLocalFileStorage {
/**
* 读取文件内容
* @param fileName
* @return
*/
public RandomAccessFile readFile(String fileName) {
try {
return new RandomAccessFile(fileName, "r");
} catch (FileNotFoundException ignore) {
return null;
}
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/AvatarStorage.java
================================================
package org.leo.im.http.file;
import java.io.RandomAccessFile;
/**
* 头像存储接口
*
* @author Leo
* @date 2018/5/11
*/
public interface AvatarStorage {
/**
* 保存头像
* @param userId
* @param fileType
* @param data
* @param width
* @param height
* @return
*/
boolean save(String userId, String fileType, byte[] data, int width, int height);
/**
* 读取头像内容
* @param userId
* @param fileName
* @param width
* @param height
* @return
*/
RandomAccessFile read(String userId, String fileName, int width, int height);
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/AvatarStorageFactory.java
================================================
package org.leo.im.http.file;
/**
* 头像存储工厂类
*
* @author Leo
* @date 2018/5/11
*/
public final class AvatarStorageFactory {
/**
* 创建头像存储类的实例
* @return
*/
public static AvatarStorage newInstance() {
if("local".equalsIgnoreCase(System.getProperty("file.settings.driver"))) {
return new LocalAvatarStorage();
}
return new LocalAvatarStorage();
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/FileStorage.java
================================================
package org.leo.im.http.file;
import java.io.RandomAccessFile;
/**
* 文件存储接口
*
* @author Leo
* @date 2018/5/11
*/
public interface FileStorage {
/**
* 保存文件
* @param key
* @param fileName
* @param data
* @return
*/
boolean save(String key, String fileName, byte[] data);
/**
* 保存预览图片
* @param key
* @param fileName
* @param data
* @param width
* @param height
* @return
*/
short[] saveThumb(String key, String fileName, byte[] data, int width, int height);
/**
* 读取文件内容
* @param fileName
* @return
*/
RandomAccessFile read(String fileName);
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/FileStorageFactory.java
================================================
package org.leo.im.http.file;
/**
* 文件存储工厂类
* @author Administrator
*
*/
public final class FileStorageFactory {
/**
* 得到文件存储类的实例
* @return
*/
public static FileStorage newInstance() {
if("local".equalsIgnoreCase(System.getProperty("file.settings.driver"))) {
return new LocalFileStorage();
}
return new LocalFileStorage();
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/LocalAvatarStorage.java
================================================
package org.leo.im.http.file;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import org.leo.im.http.exception.NoSuchSettingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.coobird.thumbnailator.Thumbnails;
/**
* 本地存储头像实现类
*
* @author Leo
* @date 2018/5/11
*/
class LocalAvatarStorage extends AbstractLocalFileStorage implements AvatarStorage {
private static Logger logger = LoggerFactory.getLogger(LocalAvatarStorage.class);
/**
* 保存头像
* @param userId
* @param fileType
* @param data
* @param width
* @param height
* @return
*/
@Override
public boolean save(String userId, String fileType, byte[] data, int width, int height) {
StringBuilder newFile = new StringBuilder(256);
newFile.append(System.getProperty("file.settings.directory"));
if(newFile.length() == 0) {
throw new NoSuchSettingException("file.settings.directory");
}
if(userId != null && !userId.trim().isEmpty()) {
newFile.append("/").append(userId);
}
// 判断目录是否存在
File dir = new File(newFile.toString());
if(!dir.exists()) {
dir.mkdir();
}
newFile.append("/avatar").append(width).append("x").append(height).append(".").append(fileType);
InputStream is = new ByteArrayInputStream(data);
try {
Thumbnails.of(is).size(width > 70 ? width : width * 2, height > 70 ? height : height * 2).toFile(newFile.toString());
} catch (IOException e) {
logger.error(e.getMessage());
return false;
}
return true;
}
/**
* 读取头像内容
* @param userId
* @param fileName
* @param width
* @param height
* @return
*/
@Override
public RandomAccessFile read(String userId, String fileName, int width, int height) {
StringBuilder file = new StringBuilder(256);
file.append(System.getProperty("file.settings.directory"));
if(file.length() == 0) {
throw new NoSuchSettingException("file.settings.directory");
}
if(userId != null && !userId.trim().isEmpty()) {
file.append("/").append(userId);
}
String[] fileNameSplit = fileName.split("\\.");
file.append("/avatar").append(width).append("x").append(height).append(".").append(fileNameSplit[fileNameSplit.length - 1]);
try {
return new RandomAccessFile(file.toString(), "r");
} catch (FileNotFoundException e) {
return null;
}
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/file/LocalFileStorage.java
================================================
package org.leo.im.http.file;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import javax.imageio.ImageIO;
import org.leo.im.http.exception.NoSuchSettingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.coobird.thumbnailator.Thumbnails;
/**
* 本地文件存储实现类
*
* @author Leo
* @date 2018/5/11
*/
class LocalFileStorage extends AbstractLocalFileStorage implements FileStorage {
private static Logger logger = LoggerFactory.getLogger(LocalFileStorage.class);
/**
* 保存文件
* @param key
* @param fileName
* @param data
*/
@Override
public boolean save(String key, String fileName, byte[] data) {
StringBuilder newFile = new StringBuilder(256);
newFile.append(System.getProperty("file.settings.directory"));
if(newFile.length() == 0) {
throw new NoSuchSettingException("file.settings.directory");
}
if(key != null && !key.trim().isEmpty()) {
newFile.append("/").append(key);
}
// 判断目录是否存在
File dir = new File(newFile.toString());
if(!dir.exists()) {
dir.mkdirs();
}
// 创建文件
newFile.append("/").append(fileName);
File file = new File(newFile.toString());
OutputStream os = null;
try {
file.createNewFile();
os = new FileOutputStream(file);
os.write(data);
return true;
} catch (IOException e) {
logger.error(e.getMessage());
return false;
} finally {
if(os != null) {
try {
os.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
}
/**
* 保存预览图片
* @param key
* @param fileName
* @param data
* @param width
* @param height
* @return
*/
@Override
public short[] saveThumb(String key, String fileName, byte[] data, int width, int height) {
StringBuilder newFile = new StringBuilder(256);
newFile.append(System.getProperty("file.settings.directory"));
if(newFile.length() == 0) {
throw new NoSuchSettingException("file.settings.directory");
}
if(key != null && !key.trim().isEmpty()) {
newFile.append("/").append(key);
}
// 判断目录是否存在
File dir = new File(newFile.toString());
if(!dir.exists()) {
dir.mkdir();
}
newFile.append("/").append(fileName);
InputStream is = new ByteArrayInputStream(data);
try {
Thumbnails.of(is).size(width, height).toFile(newFile.toString());
File picture = new File(newFile.toString());
BufferedImage sourceImage = ImageIO.read(new FileInputStream(picture));
return new short[] { (short)sourceImage.getWidth(), (short)sourceImage.getHeight() };
} catch (IOException e) {
logger.error(e.getMessage());
return null;
}
}
@Override
public RandomAccessFile read(String fileName) {
StringBuilder file = new StringBuilder(256);
file.append(System.getProperty("file.settings.directory"));
if(file.length() == 0) {
throw new NoSuchSettingException("file.settings.directory");
}
file.append("/").append(fileName);
try {
return new RandomAccessFile(file.toString(), "r");
} catch (FileNotFoundException e) {
return null;
}
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/interceptor/AuthenticationInterceptor.java
================================================
package org.leo.im.http.interceptor;
import org.leo.im.http.util.JwtUtils;
import org.leo.web.rest.HttpResponse;
import org.leo.web.rest.HttpStatus;
import org.leo.web.rest.interceptor.Interceptor;
import io.netty.handler.codec.http.FullHttpRequest;
/**
* 身份认证拦截器
*
* @author Leo
* @date 2018/4/3
*/
public class AuthenticationInterceptor implements Interceptor {
@Override
public boolean preHandle(FullHttpRequest request, HttpResponse response) throws Exception {
if (request.method().name().equalsIgnoreCase("OPTIONS")) {
return true;
}
try {
JwtUtils.parseJWT(request.headers().get("X-Token"), System.getProperty("jwt.secret"));
return true;
} catch (Exception e) {
response.write(HttpStatus.UNAUTHORIZED, "Unauthorized");
return false;
}
}
@Override
public void postHandle(FullHttpRequest request, HttpResponse response) throws Exception {
}
@Override
public void afterCompletion(FullHttpRequest request, HttpResponse response) {
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/interceptor/CorsInterceptor.java
================================================
package org.leo.im.http.interceptor;
import org.leo.web.rest.HttpResponse;
import org.leo.web.rest.interceptor.Interceptor;
import io.netty.handler.codec.http.FullHttpRequest;
/**
* 跨域拦截器
*
* @author Leo
* @date 2018/4/2
*/
public final class CorsInterceptor implements Interceptor {
@Override
public boolean preHandle(FullHttpRequest request, HttpResponse response) throws Exception {
// 使用axios发送cookie,这里不能用*,需要使用Web前端地址,如:http://localhost:8080
// response.getHeaders().put("Access-Control-Allow-Origin", "*");
response.getHeaders().put("Access-Control-Allow-Origin", System.getProperty("http.origin"));
response.getHeaders().put("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE, PATCH");
response.getHeaders().put("Access-Control-Max-Age", "3600");
response.getHeaders().put("Access-Control-Allow-Headers", "Content-Type,X-Token");
response.getHeaders().put("Access-Control-Allow-Credentials", "true");
return true;
}
@Override
public void postHandle(FullHttpRequest request, HttpResponse response) throws Exception {
}
@Override
public void afterCompletion(FullHttpRequest request, HttpResponse response) {
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/util/JwtUtils.java
================================================
package org.leo.im.http.util;
import java.util.Base64;
import java.util.Date;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
/**
* Jwt工具类
*
* @author Leo
* @date 2018/3/28
*/
public class JwtUtils {
/**
* 生成加密key
*
* @param secret
* @return
*/
private static SecretKey generalKey(String secret) {
byte[] encodedKey = Base64.getDecoder().decode(secret);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 创建jwt
*
* @param subject
* @param secret
* @param ttlMillis
* @return
*/
public static String createJWT(String subject, String secret, long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
SecretKey key = generalKey(secret);
JwtBuilder builder = Jwts.builder().setId("jwt").setIssuedAt(now).setSubject(subject)
.signWith(signatureAlgorithm, key);
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
return builder.compact();
}
/**
* 解密jwt
*
* @param jwt
* @param secret
* @return
* @throws Exception
*/
public static Claims parseJWT(String jwt, String secret) {
SecretKey key = generalKey(secret);
Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt).getBody();
return claims;
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/vo/ChannelListVO.java
================================================
package org.leo.im.http.vo;
/**
* 频道列表vo类
*
* @author Leo
* @date 2018/4/3
*/
public final class ChannelListVO {
private String id;
private String name;
private String displayName;
private String otherSideOnlineStatus;
private String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getOtherSideOnlineStatus() {
return otherSideOnlineStatus;
}
public void setOtherSideOnlineStatus(String otherSideOnlineStatus) {
this.otherSideOnlineStatus = otherSideOnlineStatus;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "ChannelListVO [id=" + id + ", name=" + name + ", displayName=" + displayName
+ ", otherSideOnlineStatus=" + otherSideOnlineStatus + ", type=" + type + "]";
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/vo/ChannelVO.java
================================================
package org.leo.im.http.vo;
import java.util.ArrayList;
import java.util.List;
import org.leo.im.api.dto.ChannelMemberDTO;
/**
* 频道vo类
* @author Leo
* @date 2018/4/12
*/
public final class ChannelVO {
private String id;
private String name;
private String displayName;
private String type;
private int memberCount;
private String otherSideId;
private String otherSideOnlineStatus;
private String creatorId;
private List members = new ArrayList<>(128);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public String getOtherSideId() {
return otherSideId;
}
public void setOtherSideId(String otherSideId) {
this.otherSideId = otherSideId;
}
public String getOtherSideOnlineStatus() {
return otherSideOnlineStatus;
}
public void setOtherSideOnlineStatus(String otherSideOnlineStatus) {
this.otherSideOnlineStatus = otherSideOnlineStatus;
}
public String getCreatorId() {
return creatorId;
}
public void setCreatorId(String creatorId) {
this.creatorId = creatorId;
}
public List getMembers() {
return members;
}
@Override
public String toString() {
return "ChannelVO [id=" + id + ", name=" + name + ", displayName=" + displayName + ", type=" + type
+ ", memberCount=" + memberCount + ", otherSideId=" + otherSideId + ", otherSideOnlineStatus="
+ otherSideOnlineStatus + ", creatorId=" + creatorId + ", members=" + members + "]";
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/vo/MessageVO.java
================================================
package org.leo.im.http.vo;
/**
* 消息vo类
*
* @author Leo
* @date 2018/5/16
*/
public final class MessageVO {
private long id;
private String channelId;
private long createAt;
private String type;
private String senderId;
private String senderName;
private String senderNickname;
private String senderOnlineStatus;
private String senderAvatarUrl;
private String senderFirstLetterOfName;
private String content;
private String fileName;
private String fileExtension;
private int fileSize;
private String fileMimeType;
private String fileThumbPath;
private String filePath;
private int imageWidth;
private int imageHeight;
private short imageThumbWidth;
private short imageThumbHeight;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public long getCreateAt() {
return createAt;
}
public void setCreateAt(long createAt) {
this.createAt = createAt;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSenderId() {
return senderId;
}
public void setSenderId(String senderId) {
this.senderId = senderId;
}
public String getSenderName() {
return senderName;
}
public void setSenderName(String senderName) {
this.senderName = senderName;
}
public String getSenderNickname() {
return senderNickname;
}
public void setSenderNickname(String senderNickname) {
this.senderNickname = senderNickname;
}
public String getSenderOnlineStatus() {
return senderOnlineStatus;
}
public void setSenderOnlineStatus(String senderOnlineStatus) {
this.senderOnlineStatus = senderOnlineStatus;
}
public String getSenderAvatarUrl() {
return senderAvatarUrl;
}
public void setSenderAvatarUrl(String senderAvatarUrl) {
this.senderAvatarUrl = senderAvatarUrl;
}
public String getSenderFirstLetterOfName() {
return senderFirstLetterOfName;
}
public void setSenderFirstLetterOfName(String senderFirstLetterOfName) {
this.senderFirstLetterOfName = senderFirstLetterOfName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileExtension() {
return fileExtension;
}
public void setFileExtension(String fileExtension) {
this.fileExtension = fileExtension;
}
public int getFileSize() {
return fileSize;
}
public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}
public String getFileMimeType() {
return fileMimeType;
}
public void setFileMimeType(String fileMimeType) {
this.fileMimeType = fileMimeType;
}
public String getFileThumbPath() {
return fileThumbPath;
}
public void setFileThumbPath(String fileThumbPath) {
this.fileThumbPath = fileThumbPath;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public int getImageWidth() {
return imageWidth;
}
public void setImageWidth(int imageWidth) {
this.imageWidth = imageWidth;
}
public int getImageHeight() {
return imageHeight;
}
public void setImageHeight(int imageHeight) {
this.imageHeight = imageHeight;
}
public short getImageThumbWidth() {
return imageThumbWidth;
}
public void setImageThumbWidth(short imageThumbWidth) {
this.imageThumbWidth = imageThumbWidth;
}
public short getImageThumbHeight() {
return imageThumbHeight;
}
public void setImageThumbHeight(short imageThumbHeight) {
this.imageThumbHeight = imageThumbHeight;
}
public String getSenderRealAvatarUrl() {
if("http://".equalsIgnoreCase(this.senderAvatarUrl) || "https://".equalsIgnoreCase(this.senderAvatarUrl)) {
return this.senderAvatarUrl;
}
if(this.senderAvatarUrl != null && !this.senderAvatarUrl.trim().isEmpty()) {
return this.senderAvatarUrl;
}
return null;
}
@Override
public String toString() {
return "MessageVO [id=" + id + ", channelId=" + channelId + ", createAt=" + createAt + ", type=" + type
+ ", senderId=" + senderId + ", senderName=" + senderName + ", senderNickname=" + senderNickname
+ ", senderOnlineStatus=" + senderOnlineStatus + ", senderAvatarUrl=" + senderAvatarUrl
+ ", senderFirstLetterOfName=" + senderFirstLetterOfName + ", content=" + content + ", fileName="
+ fileName + ", fileExtension=" + fileExtension + ", fileSize=" + fileSize + ", fileMimeType="
+ fileMimeType + ", fileThumbPath=" + fileThumbPath + ", filePath=" + filePath + ", imageWidth="
+ imageWidth + ", imageHeight=" + imageHeight + ", imageThumbWidth=" + imageThumbWidth
+ ", imageThumbHeight=" + imageThumbHeight + "]";
}
}
================================================
FILE: leo-im-http/src/main/java/org/leo/im/http/vo/UserChannelVO.java
================================================
package org.leo.im.http.vo;
/**
* 用户频道vo类
*
* @author Leo
* @date 2018/4/20
*/
public final class UserChannelVO {
private String channelId;
private String channelName;
private String channelType;
private String channelDisplayName;
private String channelDescription;
private String toUserId;
private String toUserOnlineStatus;
private short unreadMessageCount;
private int memberCount;
private String creatorId;
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public String getChannelType() {
return channelType;
}
public void setChannelType(String channelType) {
this.channelType = channelType;
}
public String getChannelDisplayName() {
return channelDisplayName;
}
public void setChannelDisplayName(String channelDisplayName) {
this.channelDisplayName = channelDisplayName;
}
public String getChannelDescription() {
return channelDescription;
}
public void setChannelDescription(String channelDescription) {
this.channelDescription = channelDescription;
}
public String getToUserId() {
return toUserId;
}
public void setToUserId(String toUserId) {
this.toUserId = toUserId;
}
public String getToUserOnlineStatus() {
return toUserOnlineStatus;
}
public void setToUserOnlineStatus(String toUserOnlineStatus) {
this.toUserOnlineStatus = toUserOnlineStatus;
}
public short getUnreadMessageCount() {
return unreadMessageCount;
}
public void setUnreadMessageCount(short unreadMessageCount) {
this.unreadMessageCount = unreadMessageCount;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public String getCreatorId() {
return creatorId;
}
public void setCreatorId(String creatorId) {
this.creatorId = creatorId;
}
@Override
public String toString() {
return "UserChannelVO [channelId=" + channelId + ", channelName=" + channelName + ", channelType=" + channelType
+ ", channelDisplayName=" + channelDisplayName + ", channelDescription=" + channelDescription
+ ", toUserId=" + toUserId + ", toUserOnlineStatus=" + toUserOnlineStatus + ", unreadMessageCount="
+ unreadMessageCount + ", memberCount=" + memberCount + ", creatorId=" + creatorId + "]";
}
}
================================================
FILE: leo-im-http/src/test/java/org/leo/im/http/AppTest.java
================================================
package org.leo.im.http;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-http/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: asm-6.1.jar thumbnailator-0.4.8.jar netty-all-4.1.24.Final
.jar fastjson-1.2.47.jar netty-rest-server-1.0.jar leo-im-api-1.0.jar
leo-im-api-provider-1.0.jar leo-im-service-1.0.jar leo-im-store-1.0.
jar mysql-connector-java-8.0.11.jar protobuf-java-2.6.0.jar druid-1.1
.9.jar leo-im-model-1.0.jar leo-im-util-1.0.jar cglib-3.2.6.jar ant-1
.9.6.jar ant-launcher-1.9.6.jar jjwt-0.9.0.jar jackson-databind-2.8.9
.jar jackson-annotations-2.8.0.jar jackson-core-2.8.9.jar leo-im-noti
fication-1.0.jar jedis-2.9.0.jar commons-pool2-2.4.2.jar leo-im-commo
n-1.0.jar slf4j-api-1.7.25.jar logback-classic-1.2.3.jar logback-core
-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-http/target/classes/META-INF/maven/org.leo.im/leo-im-http/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:34 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-http
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-http
artifactId=leo-im-http
================================================
FILE: leo-im-http/target/classes/META-INF/maven/org.leo.im/leo-im-http/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-http
leo-im-http
http://maven.apache.org
UTF-8
org.ow2.asm
asm
6.1
net.coobird
thumbnailator
0.4.8
io.netty
netty-all
${netty.version}
com.alibaba
fastjson
${fastjson.version}
org.leo
netty-rest-server
1.0
org.leo.im
leo-im-api
${parent.version}
org.leo.im
leo-im-api-provider
${project.version}
org.leo.im
leo-im-util
${project.version}
org.leo.im
leo-im-notification
${project.version}
org.leo.im
leo-im-common
${project.version}
================================================
FILE: leo-im-http/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:21 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-http
================================================
FILE: leo-im-http/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-http/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\BaseController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\interceptor\AuthenticationInterceptor.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\ChannelController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\cache\CacheManagerFactory.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\HttpServer.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\interceptor\CorsInterceptor.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\vo\ChannelVO.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\cache\CacheManager.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\AuthController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\vo\UserChannelVO.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\exception\NoSuchSettingException.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\LocalAvatarStorage.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\cache\MapCacheManager.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\LocalFileStorage.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\ExceptionController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\AvatarStorage.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\cache\Cache.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\util\JwtUtils.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\vo\ChannelListVO.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\FileStorage.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\MessageController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\UserChannelController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\vo\MessageVO.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\AvatarStorageFactory.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\controller\UserController.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\AbstractLocalFileStorage.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\file\FileStorageFactory.java
F:\Develop\open-source\leo-im-server\leo-im-http\src\main\java\org\leo\im\http\constant\CacheKeys.java
================================================
FILE: leo-im-http/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-http/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-http\src\test\java\org\leo\im\http\AppTest.java
================================================
FILE: leo-im-http/target/surefire-reports/TEST-org.leo.im.http.AppTest.xml
================================================
================================================
FILE: leo-im-http/target/surefire-reports/org.leo.im.http.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.http.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.065 sec
================================================
FILE: leo-im-migration/.classpath
================================================
================================================
FILE: leo-im-migration/.project
================================================
leo-im-migration
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-migration/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-migration/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-migration/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-migration/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-migration
leo-im-migration
http://maven.apache.org
UTF-8
org.flywaydb
flyway-core
${flyway-core.version}
================================================
FILE: leo-im-migration/src/main/java/org/leo/im/migration/FlywayMigration.java
================================================
package org.leo.im.migration;
import org.flywaydb.core.Flyway;
public class FlywayMigration {
/**
* 数据库迁移
* @param url JDBC URL
* @param user 数据库用户
* @param password 数据库口令
*/
public void migrate(String url, String user, String password) {
Flyway flyway = new Flyway();
flyway.setDataSource(url, user, password);
flyway.migrate();
}
}
================================================
FILE: leo-im-migration/src/main/resources/db/migration/V20180615___Init.sql
================================================
CREATE TABLE IF NOT EXISTS `im_channel` (
`id` char(32) NOT NULL,
`name` varchar(64) NOT NULL,
`type` char(1) NOT NULL,
`purpose` varchar(256) DEFAULT NULL,
`create_at` bigint(20) unsigned NOT NULL,
`delete_at` bigint(20) unsigned NOT NULL DEFAULT '0',
`last_post_at` bigint(20) unsigned NOT NULL DEFAULT '0',
`member_count` mediumint(8) unsigned NOT NULL DEFAULT '0',
`creator_id` char(32) NOT NULL DEFAULT '0',
`from_user_id` char(32) DEFAULT '0',
`to_user_id` char(32) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_channel_member` (
`channel_id` char(32) NOT NULL,
`user_id` char(32) NOT NULL,
`is_admin` tinyint(3) unsigned NOT NULL,
PRIMARY KEY (`channel_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_file` (
`id` char(32) NOT NULL,
`name` varchar(128) NOT NULL,
`extension` varchar(32) NOT NULL,
`size` int(11) NOT NULL,
`mime_typ` varchar(256) NOT NULL,
`width` smallint(6) NOT NULL,
`height` smallint(6) NOT NULL,
`path` varchar(128) NOT NULL,
`thumb_width` smallint(6) DEFAULT NULL,
`thumb_height` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_hide_channel` (
`user_id` char(32) NOT NULL,
`channel_id` char(32) NOT NULL,
PRIMARY KEY (`user_id`,`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_message` (
`id` bigint(20) unsigned NOT NULL,
`channel_id` char(32) COLLATE utf8mb4_bin NOT NULL,
`sender_id` char(32) COLLATE utf8mb4_bin NOT NULL,
`create_at` bigint(20) NOT NULL,
`type` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
`content` varchar(3000) COLLATE utf8mb4_bin DEFAULT NULL,
`delete_at` bigint(20) NOT NULL DEFAULT '0',
`file_id` char(32) COLLATE utf8mb4_bin DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE IF NOT EXISTS `im_unread_message_count` (
`user_id` char(32) NOT NULL,
`channel_id` char(32) NOT NULL,
`total` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`,`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_user` (
`id` char(32) NOT NULL,
`name` varchar(32) NOT NULL,
`name_first_letter` char(1) NOT NULL,
`nickname` varchar(32) NOT NULL,
`salt` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`locked` tinyint(4) NOT NULL DEFAULT '0',
`avatar_url` varchar(512) DEFAULT NULL,
`created_at` datetime NOT NULL,
`last_post_at` bigint(20) DEFAULT NULL,
`online_status` varchar(7) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_user_channel` (
`user_id` char(32) NOT NULL,
`channel_id` char(32) NOT NULL,
`display_name` varchar(64) NOT NULL,
`to_user_id` char(32) DEFAULT NULL,
PRIMARY KEY (`user_id`,`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `im_user` (`id`, `name`, `name_first_letter`, `nickname`, `salt`, `password`, `locked`, `avatar_url`, `created_at`, `last_post_at`, `online_status`) VALUES
('00000000000000000000000000000000', 'leo', 'l', '系统用户', 'MOlssyhqweLKffidserewr==', 'FDFGHTY33456FDHG000FDEKKKLLLPP', 0, NULL, '2018-06-16 21:00:00', NULL, NULL);
================================================
FILE: leo-im-migration/src/test/java/org/leo/im/migration/AppTest.java
================================================
package org.leo.im.migration;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-migration/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: flyway-core-5.1.1.jar slf4j-api-1.7.25.jar logback-classic
-1.2.3.jar logback-core-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-migration/target/classes/META-INF/maven/org.leo.im/leo-im-migration/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:09 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-migration
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-migration
artifactId=leo-im-migration
================================================
FILE: leo-im-migration/target/classes/META-INF/maven/org.leo.im/leo-im-migration/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-migration
leo-im-migration
http://maven.apache.org
UTF-8
org.flywaydb
flyway-core
${flyway-core.version}
================================================
FILE: leo-im-migration/target/classes/db/migration/V20180615___Init.sql
================================================
CREATE TABLE IF NOT EXISTS `im_channel` (
`id` char(32) NOT NULL,
`name` varchar(64) NOT NULL,
`type` char(1) NOT NULL,
`purpose` varchar(256) DEFAULT NULL,
`create_at` bigint(20) unsigned NOT NULL,
`delete_at` bigint(20) unsigned NOT NULL DEFAULT '0',
`last_post_at` bigint(20) unsigned NOT NULL DEFAULT '0',
`member_count` mediumint(8) unsigned NOT NULL DEFAULT '0',
`creator_id` char(32) NOT NULL DEFAULT '0',
`from_user_id` char(32) DEFAULT '0',
`to_user_id` char(32) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_channel_member` (
`channel_id` char(32) NOT NULL,
`user_id` char(32) NOT NULL,
`is_admin` tinyint(3) unsigned NOT NULL,
PRIMARY KEY (`channel_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_file` (
`id` char(32) NOT NULL,
`name` varchar(128) NOT NULL,
`extension` varchar(32) NOT NULL,
`size` int(11) NOT NULL,
`mime_typ` varchar(256) NOT NULL,
`width` smallint(6) NOT NULL,
`height` smallint(6) NOT NULL,
`path` varchar(128) NOT NULL,
`thumb_width` smallint(6) DEFAULT NULL,
`thumb_height` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_hide_channel` (
`user_id` char(32) NOT NULL,
`channel_id` char(32) NOT NULL,
PRIMARY KEY (`user_id`,`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_message` (
`id` bigint(20) unsigned NOT NULL,
`channel_id` char(32) COLLATE utf8mb4_bin NOT NULL,
`sender_id` char(32) COLLATE utf8mb4_bin NOT NULL,
`create_at` bigint(20) NOT NULL,
`type` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
`content` varchar(3000) COLLATE utf8mb4_bin DEFAULT NULL,
`delete_at` bigint(20) NOT NULL DEFAULT '0',
`file_id` char(32) COLLATE utf8mb4_bin DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE IF NOT EXISTS `im_unread_message_count` (
`user_id` char(32) NOT NULL,
`channel_id` char(32) NOT NULL,
`total` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`,`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_user` (
`id` char(32) NOT NULL,
`name` varchar(32) NOT NULL,
`name_first_letter` char(1) NOT NULL,
`nickname` varchar(32) NOT NULL,
`salt` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`locked` tinyint(4) NOT NULL DEFAULT '0',
`avatar_url` varchar(512) DEFAULT NULL,
`created_at` datetime NOT NULL,
`last_post_at` bigint(20) DEFAULT NULL,
`online_status` varchar(7) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `im_user_channel` (
`user_id` char(32) NOT NULL,
`channel_id` char(32) NOT NULL,
`display_name` varchar(64) NOT NULL,
`to_user_id` char(32) DEFAULT NULL,
PRIMARY KEY (`user_id`,`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `im_user` (`id`, `name`, `name_first_letter`, `nickname`, `salt`, `password`, `locked`, `avatar_url`, `created_at`, `last_post_at`, `online_status`) VALUES
('00000000000000000000000000000000', 'leo', 'l', '系统用户', 'MOlssyhqweLKffidserewr==', 'FDFGHTY33456FDHG000FDEKKKLLLPP', 0, NULL, '2018-06-16 21:00:00', NULL, NULL);
================================================
FILE: leo-im-migration/target/maven-archiver/pom.properties
================================================
#Created by Apache Maven 3.3.9
version=1.0
groupId=org.leo.im
artifactId=leo-im-migration
================================================
FILE: leo-im-migration/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-migration/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-migration\src\main\java\org\leo\im\migration\FlywayMigration.java
================================================
FILE: leo-im-model/.classpath
================================================
================================================
FILE: leo-im-model/.project
================================================
leo-im-model
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-model/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-model/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-model/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-model/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-model
leo-im-model
http://maven.apache.org
================================================
FILE: leo-im-model/src/main/java/org/leo/im/model/Channel.java
================================================
package org.leo.im.model;
import java.util.ArrayList;
import java.util.List;
/**
* 频道模型类
*
* @author Leo
* @date 2018/4/7
*/
public final class Channel {
private String id;
private String name;
private User from;
private User to;
/**
* 频道类型
* G:群聊;P:私聊
*/
private String type;
private String purpose;
private long createAt;
private long deleteAt;
private long lastPostAt;
private int memberCount;
private User creator;
private List members = new ArrayList<>(128);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getFrom() {
return from;
}
public void setFrom(User from) {
this.from = from;
}
public User getTo() {
return to;
}
public void setTo(User to) {
this.to = to;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
public long getCreateAt() {
return createAt;
}
public void setCreateAt(long createAt) {
this.createAt = createAt;
}
public long getDeleteAt() {
return deleteAt;
}
public void setDeleteAt(long deleteAt) {
this.deleteAt = deleteAt;
}
public long getLastPostAt() {
return lastPostAt;
}
public void setLastPostAt(long lastPostAt) {
this.lastPostAt = lastPostAt;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public User getCreator() {
return creator;
}
public void setCreator(User creator) {
this.creator = creator;
}
public List getMembers() {
return members;
}
@Override
public String toString() {
return "Channel [id=" + id + ", name=" + name + ", from=" + from + ", to=" + to + ", type=" + type
+ ", purpose=" + purpose + ", createAt=" + createAt + ", deleteAt=" + deleteAt + ", lastPostAt="
+ lastPostAt + ", memberCount=" + memberCount + ", creator=" + creator + ", members=" + members + "]";
}
}
================================================
FILE: leo-im-model/src/main/java/org/leo/im/model/ChannelMember.java
================================================
package org.leo.im.model;
/**
* 频道成员实体类
*
* @author Leo
* @date 2018/4/11
*/
public final class ChannelMember {
private User user;
private boolean admin;
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
public boolean getAdmin() {
return this.admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
@Override
public String toString() {
return "ChannelMember [user=" + user + ", admin=" + admin + "]";
}
}
================================================
FILE: leo-im-model/src/main/java/org/leo/im/model/File.java
================================================
package org.leo.im.model;
/**
* 文件类
*
* @author Leo
* @date 2018/6/13
*/
public class File {
private String id;
private String name;
private String extension;
private int size;
private String mimeType;
private int width;
private int height;
private short thumbWidth;
private short thumbHeight;
private String path;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public short getThumbWidth() {
return thumbWidth;
}
public void setThumbWidth(short thumbWidth) {
this.thumbWidth = thumbWidth;
}
public short getThumbHeight() {
return thumbHeight;
}
public void setThumbHeight(short thumbHeight) {
this.thumbHeight = thumbHeight;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String toString() {
return "File [id=" + id + ", name=" + name + ", extension=" + extension + ", size=" + size + ", mimeType="
+ mimeType + ", width=" + width + ", height=" + height + ", thumbWidth=" + thumbWidth + ", thumbHeight="
+ thumbHeight + ", path=" + path + "]";
}
}
================================================
FILE: leo-im-model/src/main/java/org/leo/im/model/Message.java
================================================
package org.leo.im.model;
/**
* 消息类
*
* @author Leo
* @date 2018/4/21
*/
public final class Message {
private long id;
private Channel channel;
private User sender;
private long createAt;
/**
* 消息类型(如:加某某加入群组、某某退出群组)
*/
private String type;
private String content;
private File file;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public User getSender() {
return sender;
}
public void setSender(User sender) {
this.sender = sender;
}
public long getCreateAt() {
return createAt;
}
public void setCreateAt(long createAt) {
this.createAt = createAt;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
@Override
public String toString() {
return "Message [id=" + id + ", channel=" + channel + ", sender=" + sender + ", createAt=" + createAt
+ ", type=" + type + ", content=" + content + ", file=" + file + "]";
}
}
================================================
FILE: leo-im-model/src/main/java/org/leo/im/model/User.java
================================================
package org.leo.im.model;
import java.util.Date;
/**
* 用户模型类
*
* @author Leo
* @date 2018/3/30
*/
public final class User {
private String id;
private String name;
private String firstLetterOfName;
private String nickname;
private String salt;
private String password;
private Boolean locked;
private Date createdAt;
private String avatarUr;
private long lastPostAt;
private String onlineStatus;
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getFirstLetterOfName() {
return this.firstLetterOfName;
}
public void setFirstLetterOfName(String firstLetter) {
this.firstLetterOfName = firstLetter;
}
public String getNickname() {
return this.nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getSalt() {
return this.salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getLocked() {
return this.locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public Date getCreatedAt() {
return this.createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public long getLastPostAt() {
return this.lastPostAt;
}
public void setLastPostAt(long lastPostAt) {
this.lastPostAt = lastPostAt;
}
public String getAvatarUrl() {
return this.avatarUr;
}
public void setAvatarUrl(String avatarUr) {
this.avatarUr = avatarUr;
}
public String getOnlineStatus() {
return this.onlineStatus;
}
public void setOnlineStatus(String onlineStatus) {
this.onlineStatus = onlineStatus;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", firstLetterOfName=" + firstLetterOfName + ", nickname="
+ nickname + ", salt=" + salt + ", password=" + password + ", locked=" + locked + ", createdAt="
+ createdAt + ", avatarUr=" + avatarUr + ", onlineStatus=" + onlineStatus + "]";
}
}
================================================
FILE: leo-im-model/src/main/java/org/leo/im/model/UserChannel.java
================================================
package org.leo.im.model;
/**
* 用户频道类
*
* @author Leo
* @date 2018/4/20
*/
public final class UserChannel {
private User user;
private Channel channel;
private String displayName;
private User toUser;
private short unreadMessageCount;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public User getToUser() {
return toUser;
}
public void setToUser(User toUser) {
this.toUser = toUser;
}
public short getUnreadMessageCount() {
return unreadMessageCount;
}
public void setUnreadMessageCount(short unreadMessageCount) {
this.unreadMessageCount = unreadMessageCount;
}
@Override
public String toString() {
return "UserChannel [user=" + user + ", channel=" + channel + ", displayName=" + displayName + ", toUser="
+ toUser + ", unreadMessageCount=" + unreadMessageCount + "]";
}
}
================================================
FILE: leo-im-model/src/test/java/org/leo/im/model/AppTest.java
================================================
package org.leo.im.model;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-model/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: slf4j-api-1.7.25.jar logback-classic-1.2.3.jar logback-cor
e-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-model/target/classes/META-INF/maven/org.leo.im/leo-im-model/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:10 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-model
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-model
artifactId=leo-im-model
================================================
FILE: leo-im-model/target/classes/META-INF/maven/org.leo.im/leo-im-model/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-model
leo-im-model
http://maven.apache.org
================================================
FILE: leo-im-model/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:10 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-model
================================================
FILE: leo-im-model/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-model/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-model\src\main\java\org\leo\im\model\ChannelMember.java
F:\Develop\open-source\leo-im-server\leo-im-model\src\main\java\org\leo\im\model\User.java
F:\Develop\open-source\leo-im-server\leo-im-model\src\main\java\org\leo\im\model\Channel.java
F:\Develop\open-source\leo-im-server\leo-im-model\src\main\java\org\leo\im\model\UserChannel.java
F:\Develop\open-source\leo-im-server\leo-im-model\src\main\java\org\leo\im\model\File.java
F:\Develop\open-source\leo-im-server\leo-im-model\src\main\java\org\leo\im\model\Message.java
================================================
FILE: leo-im-model/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-model/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-model\src\test\java\org\leo\im\model\AppTest.java
================================================
FILE: leo-im-model/target/surefire-reports/TEST-org.leo.im.model.AppTest.xml
================================================
================================================
FILE: leo-im-model/target/surefire-reports/org.leo.im.model.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.model.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.076 sec
================================================
FILE: leo-im-notification/.classpath
================================================
================================================
FILE: leo-im-notification/.project
================================================
leo-im-notification
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-notification/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-notification/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-notification/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-notification/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-notification
leo-im-notification
http://maven.apache.org
UTF-8
redis.clients
jedis
${jedis.version}
com.alibaba
fastjson
${fastjson.version}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/ActionNames.java
================================================
package org.leo.im.notification;
/**
* 动作名称常量类
*
* @author Leo
* @date 2018/3/29
*/
public class ActionNames {
/**
* 在线状态改变
*/
public static final String ONLINE_STATUS_CHANGED = "ONLINE_STATUS_CHANGED";
/**
* 昵称改变
*/
public static final String NICKNAME_CHANGED = "NICKNAME_CHANGED";
/**
* 头像改变
*/
public static final String AVATAR_CHANGED = "AVATAR_CHANGED";
/**
* 收到新消息
*/
public static final String NEW_MESSAGE = "NEW_MESSAGE";
/**
* 读取消息
*/
public static final String READ_MESSAGE = "READ_MESSAGE";
/**
* 创建频道
*/
public static final String CREATE_CHANNEL = "CREATE_CHANNEL";
/**
* 频道被删除
*/
public static final String CHANNEL_REMOVED = "CHANNEL_REMOVED";
/**
* 加入频道
*/
public static final String JOIN_CHANNEL = "JOIN_CHANNEL";
/**
* 离开频道
*/
public static final String LEAVE_CHANNEL = "LEAVE_CHANNEL";
/**
* 被移除频道
*/
public static final String REMOVE_FROM_CHANNEL = "REMOVE_FROM_CHANNEL";
/**
* 消息被删除事件
*/
public static final String MESSAGE_REMOVED = "MESSAGE_REMOVED";
/**
* 频道名称改变事件
*/
public static final String CHANNEL_NAME_CHANGED = "CHANNEL_NAME_CHANGED";
/**
* 频道成员数量变更通知
*/
public static final String MEMBERS_COUNT_CHANGED = "MEMBERS_COUNT_CHANGED";
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/PublishKeys.java
================================================
package org.leo.im.notification;
/**
* 发布key常量类
*
* @author Leo
* @date 2018/3/29
*/
public class PublishKeys {
/**
* 私聊消息频道
*/
public static final String PRIVATE_MESSAGE_CHANNEL;
/**
* 群聊消息频道
*/
public static final String GROUP_MESSAGE_CHANNEL;
/**
* 系统消息频道
*/
public static final String SYSTEM_MESSAGE_CHANNEL;
static {
PRIVATE_MESSAGE_CHANNEL = System.getProperty("channel.private.message") == null ? "im-channel" :
System.getProperty("channel.private.message");
GROUP_MESSAGE_CHANNEL = System.getProperty("channel.group.message") == null ? "im-channel" :
System.getProperty("channel.group.message");
SYSTEM_MESSAGE_CHANNEL = System.getProperty("channel.system.message") == null ? "im-channel" :
System.getProperty("channel.system.message");
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/Publisher.java
================================================
package org.leo.im.notification;
/**
* 发布者接口
*
* @author Leo
* @date 2018/3/28
*/
public interface Publisher {
/**
* 发布消息
* @param channel
* @param message
*/
void publish(String channel, String message);
/**
* 订阅频道
* @param subscriber
* @param channels
*/
void subscribe(Subscriber subscriber, String... channels);
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/PublisherFactory.java
================================================
package org.leo.im.notification;
import org.leo.im.notification.Publisher;
import org.leo.im.notification.QueuePublisher;
/**
* 发布者工厂类
*
* @author Leo
* @date 2018/3/29
*/
public class PublisherFactory {
/**
* 创建发布者的实例
*
* @return
*/
public static Publisher createPublisher() {
switch (System.getProperty("notification.type")) {
case "queue":
return QueuePublisher.getInstance();
default:
return QueuePublisher.getInstance();
}
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/QueuePublisher.java
================================================
package org.leo.im.notification;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 队列发布者实现类
*
* @author Leo
* @date 2018/3/30
*/
public class QueuePublisher implements Publisher {
private static final int QUEUE_CAPACITY;
private static final Logger logger = LoggerFactory.getLogger(QueuePublisher.class);
static {
Integer queueCapacity = Integer.getInteger("notification.capacity");
QUEUE_CAPACITY = (queueCapacity == null ? 10240 : queueCapacity);
}
/**
* 包含频道的哈希表
*/
private Map> channels = new ConcurrentHashMap<>(2);
private QueuePublisher() {
}
private static class InstanceHolder {
private static QueuePublisher instance = new QueuePublisher();
}
public static QueuePublisher getInstance() {
return InstanceHolder.instance;
}
/**
* 发布消息
*
* @param channel
* @param message
*/
@Override
public void publish(String channel, String message) {
BlockingQueue queue = channels.get(message);
if (queue == null) {
queue = new LinkedBlockingQueue(QUEUE_CAPACITY);
BlockingQueue returnQueue = this.channels.putIfAbsent(channel, queue);
if (returnQueue != null) {
queue = returnQueue;
}
}
try {
queue.put(message);
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
/**
* 订阅频道
*
* @param subscriber
* @param subscribeChannels
*/
@Override
public void subscribe(Subscriber subscriber, String... subscribeChannels) {
for (String channel : subscribeChannels) {
BlockingQueue queue = new LinkedBlockingQueue<>(QUEUE_CAPACITY);
BlockingQueue returnQueue = this.channels.putIfAbsent(channel, queue);
final BlockingQueue subscribeQueue = returnQueue != null ? returnQueue : queue;
Thread thread = new Thread(() -> {
for (;;) {
final String message = takeFromQueue(subscribeQueue);
if (message != null) {
ThreadPoolHolder.getThreadPool().execute(() -> {
subscriber.onMessage(channel, message);
});
}
}
});
thread.setName("SubscriberThread-" + channel);
thread.start();
}
}
/**
* 从队列中获取数据
*
* @param subscribeQueue
* @return
*/
private String takeFromQueue(BlockingQueue subscribeQueue) {
try {
return subscribeQueue.take();
} catch (InterruptedException e) {
logger.error(e.getMessage());
return null;
}
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/Subscriber.java
================================================
package org.leo.im.notification;
/**
* 订阅者接口
*
* @author Leo
* @date 2018/3/28
*/
public interface Subscriber {
/**
* 接收数据
* @param channel
* @param message
*/
void onMessage(String channel, String message);
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/ThreadPoolHolder.java
================================================
package org.leo.im.notification;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 线程池持有者
*
* @author Leo
* @date 2018/3/30
*/
public class ThreadPoolHolder {
private static final int THREAD_POOL_THREADS;
private static final int THREAD_POOL_QUEUES;
static {
Integer threads = Integer.getInteger("thread.pool.threads");
Integer queues = Integer.getInteger("thread.pool.queues");
THREAD_POOL_THREADS = threads == null ? Runtime.getRuntime().availableProcessors() * 2 : threads;
THREAD_POOL_QUEUES = queues == null ? 512 : queues;
}
// 业务线程池
private final static ExecutorService THREAD_POOL = new ThreadPoolExecutor(THREAD_POOL_THREADS, THREAD_POOL_THREADS,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(THREAD_POOL_QUEUES), new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "handlerThread_" + this.threadIndex.incrementAndGet());
}
}, new ThreadPoolExecutor.DiscardPolicy());
/**
* 得到线程池
*
* @return
*/
public static ExecutorService getThreadPool() {
return THREAD_POOL;
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/AvatarChangedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 头像改变事件
*
* @author Leo
* @date 2018/5/14
*/
public class AvatarChangedEvent implements NotificationEvent {
private String userId;
private String avatar;
public AvatarChangedEvent(String userId, String avatar) {
this.userId = userId;
this.avatar = avatar;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.AVATAR_CHANGED);
message.put("userId", userId);
message.put("avatar", avatar);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/ChannelCreatedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 创建频道事件处理器
*
* @author Leo
* @date 2018/5/27
*/
public class ChannelCreatedEvent implements NotificationEvent {
private String channelId;
private String userIds;
public ChannelCreatedEvent(String channelId, String userIds) {
this.channelId = channelId;
this.userIds = userIds;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.CREATE_CHANNEL);
message.put("channelId", this.channelId);
message.put("userIds", this.userIds);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/ChannelNameChangedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 频道名称改变事件
*
* @author Leo
* @date 2018/6/8
*/
public class ChannelNameChangedEvent implements NotificationEvent {
private String channelId;
private String channelName;
public ChannelNameChangedEvent(String channelId, String channelName) {
this.channelId = channelId;
this.channelName = channelName;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.CHANNEL_NAME_CHANGED);
message.put("channelId", this.channelId);
message.put("channelName", this.channelName);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/ChannelRemovedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 频道被删除事件
*
* @author Leo
* @date 2018/6/12
*/
public class ChannelRemovedEvent implements NotificationEvent {
private String channelId;
public ChannelRemovedEvent(String channelId) {
this.channelId = channelId;
}
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.CHANNEL_REMOVED);
message.put("channelId", this.channelId);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/JoinChannelEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
* 加入频道事件
*
* @author Leo
* @date 2018/5/28
*/
public class JoinChannelEvent implements NotificationEvent {
private String channelId;
private String[] userIds;
private String[] userNicknames;
private String admin;
private boolean sendBroadcast;
public JoinChannelEvent(String channelId, String[] userIds, String[] userNicknames, String admin, boolean sendBroadcast) {
this.channelId = channelId;
this.userIds = userIds;
this.userNicknames = userNicknames;
this.admin = admin;
this.sendBroadcast = sendBroadcast;
}
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.JOIN_CHANNEL);
message.put("channelId", this.channelId);
message.put("channelType", "G");
message.put("admin", this.admin);
message.put("sendBroadcast", this.sendBroadcast);
JSONArray userIdArray = new JSONArray();
if(this.userIds != null) {
for(String userId : this.userIds) {
JSONObject userIdJSON = new JSONObject();
userIdJSON.put("id", userId);
userIdArray.add(userIdJSON);
}
}
message.put("userIds", userIdArray);
JSONArray userNicknameArray = new JSONArray();
if(this.userNicknames != null) {
for(String nickname : this.userNicknames) {
JSONObject nicknameJSON = new JSONObject();
nicknameJSON.put("nickname", nickname);
userNicknameArray.add(nicknameJSON);
}
}
message.put("userNicknames", userNicknameArray);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/LeaveChannelEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 离开频道事件
*
* @author Leo
* @date 2018/6/11
*/
public class LeaveChannelEvent implements NotificationEvent {
private String channelId;
private String userId;
private String userNickname;
private boolean sendBroadcast;
public LeaveChannelEvent(String channelId, String userId, String userNickname, boolean sendBroadcast) {
this.channelId = channelId;
this.userId = userId;
this.userNickname = userNickname;
this.sendBroadcast = sendBroadcast;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.LEAVE_CHANNEL);
message.put("channelId", this.channelId);
message.put("channelType", "G");
message.put("sendBroadcast", this.sendBroadcast);
message.put("userId", this.userId);
message.put("userNickname", this.userNickname);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/MembersCountChangedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 成员数量变更事件
*
* @author Leo
* @date 2018/6/11
*/
public class MembersCountChangedEvent implements NotificationEvent {
private String channelId;
private int count;
public MembersCountChangedEvent(String channelId, int count) {
this.channelId = channelId;
this.count = count;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.MEMBERS_COUNT_CHANGED);
message.put("channelId", this.channelId);
message.put("count", this.count);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/MessageRemovedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 消息被删除事件
* @author Leo
* @date 2018/6/5
*/
public class MessageRemovedEvent implements NotificationEvent {
private long messageId;
private String senderId;
private String channelId;
private String toUserId;
public MessageRemovedEvent(long messageId, String senderId, String channelId, String toUserId) {
this.messageId = messageId;
this.senderId = senderId;
this.channelId = channelId;
this.toUserId = toUserId;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.MESSAGE_REMOVED);
message.put("messageId", this.messageId);
message.put("senderId", this.senderId);
message.put("channelId", this.channelId);
message.put("toUserId", toUserId);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/NewMessageEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 收到新消息事件
*
* @author Leo
* @date 2018/5/16
*/
public class NewMessageEvent implements NotificationEvent {
private JSONObject message;
public NewMessageEvent(JSONObject message) {
this.message = message;
}
/**
* 触发事件
*/
@Override
public void trigger() {
message.put("action", ActionNames.NEW_MESSAGE);
// 群发、私聊、系统消息
if(message.containsKey("type")) {
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
return;
}
if(message.containsKey("userIds")) {
PublisherFactory.createPublisher().publish(PublishKeys.PRIVATE_MESSAGE_CHANNEL, message.toJSONString());
return;
}
PublisherFactory.createPublisher().publish(PublishKeys.GROUP_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/NicknameChangedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 昵称改变事件
*
* @author Leo
* @date 2018/5/14
*/
public class NicknameChangedEvent implements NotificationEvent {
private String userId;
private String nickname;
public NicknameChangedEvent(String userId, String nickname) {
this.userId = userId;
this.nickname = nickname;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.NICKNAME_CHANGED);
message.put("userId", userId);
message.put("nickname", nickname);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/NotificationEvent.java
================================================
package org.leo.im.notification.event;
/**
* 通知事件接口
*
* @author Leo
* @date 2018/5/10
*/
public interface NotificationEvent {
/**
* 触发事件
*/
void trigger();
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/OnlineStatusChangedEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 在线状态改变事件
*
* @author Le
* @date 2018/5/10
*/
public class OnlineStatusChangedEvent implements NotificationEvent {
private String userId;
private String onlineStatus;
public OnlineStatusChangedEvent(String userId, String onlineStatus) {
this.userId = userId;
this.onlineStatus = onlineStatus;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.ONLINE_STATUS_CHANGED);
message.put("userId", userId);
message.put("onlineStatus", onlineStatus);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/ReadMessageEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 读取消息事件
*
* @author Leo
* @date 2018/5/22
*/
public class ReadMessageEvent implements NotificationEvent {
private String userId;
private String channelId;
private short total;
private boolean readAll;
public ReadMessageEvent(String userId, String channelId, short total, boolean readAll) {
this.userId = userId;
this.channelId = channelId;
this.total = total;
this.readAll = readAll;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.READ_MESSAGE);
message.put("userId", userId);
message.put("channelId", channelId);
message.put("total", total);
message.put("readAll", readAll);
PublisherFactory.createPublisher().publish(PublishKeys.PRIVATE_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/main/java/org/leo/im/notification/event/RemoveFromChannelEvent.java
================================================
package org.leo.im.notification.event;
import org.leo.im.notification.ActionNames;
import org.leo.im.notification.PublishKeys;
import org.leo.im.notification.PublisherFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
* 从频道被删除事件
*
* @author Leo
* @date 2018/6/11
*/
public class RemoveFromChannelEvent implements NotificationEvent {
private String channelId;
private String[] userIds;
private String[] userNicknames;
private String admin;
private boolean sendBroadcast;
public RemoveFromChannelEvent(String channelId, String[] userIds, String[] userNicknames, String admin, boolean sendBroadcast) {
this.channelId = channelId;
this.userIds = userIds;
this.userNicknames = userNicknames;
this.admin = admin;
this.sendBroadcast = sendBroadcast;
}
/**
* 触发事件
*/
@Override
public void trigger() {
JSONObject message = new JSONObject();
message.put("action", ActionNames.REMOVE_FROM_CHANNEL);
message.put("channelId", this.channelId);
message.put("channelType", "G");
message.put("admin", this.admin);
message.put("sendBroadcast", this.sendBroadcast);
JSONArray userIdArray = new JSONArray();
if(this.userIds != null) {
for(String userId : this.userIds) {
JSONObject userIdJSON = new JSONObject();
userIdJSON.put("id", userId);
userIdArray.add(userIdJSON);
}
}
message.put("userIds", userIdArray);
JSONArray userNicknameArray = new JSONArray();
if(this.userNicknames != null) {
for(String nickname : this.userNicknames) {
JSONObject nicknameJSON = new JSONObject();
nicknameJSON.put("nickname", nickname);
userNicknameArray.add(nicknameJSON);
}
}
message.put("userNicknames", userNicknameArray);
PublisherFactory.createPublisher().publish(PublishKeys.SYSTEM_MESSAGE_CHANNEL, message.toJSONString());
}
}
================================================
FILE: leo-im-notification/src/test/java/org/leo/im/notification/AppTest.java
================================================
package org.leo.im.notification;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-notification/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: jedis-2.9.0.jar commons-pool2-2.4.2.jar fastjson-1.2.47.ja
r slf4j-api-1.7.25.jar logback-classic-1.2.3.jar logback-core-1.2.3.j
ar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-notification/target/classes/META-INF/maven/org.leo.im/leo-im-notification/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:11 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-notification
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-notification
artifactId=leo-im-notification
================================================
FILE: leo-im-notification/target/classes/META-INF/maven/org.leo.im/leo-im-notification/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-notification
leo-im-notification
http://maven.apache.org
UTF-8
redis.clients
jedis
${jedis.version}
com.alibaba
fastjson
${fastjson.version}
================================================
FILE: leo-im-notification/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:16 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-notification
================================================
FILE: leo-im-notification/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
org\leo\im\notification\QueuePublisher$1.class
================================================
FILE: leo-im-notification/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\ReadMessageEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\QueuePublisher.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\NicknameChangedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\JoinChannelEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\NewMessageEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\PublishKeys.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\LeaveChannelEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\ChannelNameChangedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\PublisherFactory.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\Publisher.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\MessageRemovedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\ChannelCreatedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\MembersCountChangedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\OnlineStatusChangedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\ChannelRemovedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\NotificationEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\ActionNames.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\ThreadPoolHolder.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\AvatarChangedEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\event\RemoveFromChannelEvent.java
F:\Develop\open-source\leo-im-server\leo-im-notification\src\main\java\org\leo\im\notification\Subscriber.java
================================================
FILE: leo-im-notification/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-notification/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-notification\src\test\java\org\leo\im\notification\AppTest.java
================================================
FILE: leo-im-notification/target/surefire-reports/TEST-org.leo.im.notification.AppTest.xml
================================================
================================================
FILE: leo-im-notification/target/surefire-reports/org.leo.im.notification.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.notification.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.084 sec
================================================
FILE: leo-im-service/.classpath
================================================
================================================
FILE: leo-im-service/.project
================================================
leo-im-service
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-service/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-service/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-service/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-service/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-service
leo-im-service
http://maven.apache.org
org.leo.im
leo-im-api
${parent.version}
org.leo.im
leo-im-store
${parent.version}
org.leo.im
leo-im-util
${project.version}
org.leo.im
leo-im-notification
${project.version}
com.alibaba
fastjson
${fastjson.version}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/ChannelServiceImpl.java
================================================
package org.leo.im.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.leo.im.api.dto.ChannelDTO;
import org.leo.im.api.dto.ChannelListDTO;
import org.leo.im.api.dto.ChannelMemberDTO;
import org.leo.im.api.service.ChannelService;
import org.leo.im.common.data.Page;
import org.leo.im.model.Channel;
import org.leo.im.model.ChannelMember;
import org.leo.im.model.User;
import org.leo.im.model.UserChannel;
import org.leo.im.notification.event.ChannelCreatedEvent;
import org.leo.im.notification.event.ChannelNameChangedEvent;
import org.leo.im.notification.event.ChannelRemovedEvent;
import org.leo.im.notification.event.JoinChannelEvent;
import org.leo.im.notification.event.MembersCountChangedEvent;
import org.leo.im.notification.event.NotificationEvent;
import org.leo.im.notification.event.RemoveFromChannelEvent;
import org.leo.im.store.dao.ChannelDAO;
import org.leo.im.store.exception.DAOException;
import org.leo.im.store.factory.DAOFactory;
import org.leo.im.util.BeanUtils;
/**
* 频道服务实现类
*
* @author Leo
* @date 2018/4/3
*/
public final class ChannelServiceImpl implements ChannelService {
/**
* 得到频道列表
*
* @param parameters
* @param limit
* @return
*/
@Override
public List listChannel(Map parameters, int limit) {
List list = DAOFactory.createChannelDAO().list(parameters, limit);
List dtoList = new ArrayList<>(list.size());
for (Channel channel : list) {
ChannelListDTO dto = new ChannelListDTO();
BeanUtils.copyProperties(channel, dto);
dtoList.add(dto);
}
return dtoList;
}
/**
* 得到群组频道列表
*
* @param parameters
* @param limit
* @return
*/
@Override
public List listGroupChannel(Map parameters, int limit) {
List list = DAOFactory.createChannelDAO().listGroupChannel(parameters, new String[] { "O", "P" },
limit);
List dtoList = new ArrayList<>(list.size());
for (Channel channel : list) {
ChannelListDTO dto = new ChannelListDTO();
BeanUtils.copyProperties(channel, dto);
dtoList.add(dto);
}
return dtoList;
}
/**
* 添加频道
*
* @param dto
* @param creatorNickname
* @return
*/
@Override
public ChannelDTO saveChannel(ChannelDTO dto, String creatorNickname) {
ChannelDAO channelDAO = DAOFactory.createChannelDAO();
Channel channel = new Channel();
BeanUtils.copyProperties(dto, channel);
User creator = new User();
creator.setId(dto.getCreatorId());
channel.setCreator(creator);
if (dto.getFromUserId() != null && !dto.getFromUserId().trim().isEmpty()) {
User fromUser = new User();
fromUser.setId(dto.getFromUserId());
fromUser.setName(dto.getFromUsername());
fromUser.setNickname(dto.getFromUserNickname());
channel.setFrom(fromUser);
}
if (dto.getToUserId() != null && !dto.getToUserId().trim().isEmpty()) {
User toUser = new User();
toUser.setId(dto.getToUserId());
toUser.setName(dto.getToUsername());
toUser.setNickname(dto.getToUserNickname());
channel.setTo(toUser);
}
Channel returnChannel = channelDAO.save(channel);
boolean channelExists = false;
if (returnChannel == null) {
// channel已存在,从数据库中查询已存在的channel。
returnChannel = channelDAO.getByFromAndTo(dto.getFromUserId(), dto.getToUserId());
channelExists = true;
}
if (returnChannel == null) {
throw new DAOException("Channel not exists");
}
if(channelExists && dto.getType().equals("P")) {
// 删除隐藏频道
DAOFactory.createHideChannelDAO().remove(dto.getCreatorId(), returnChannel.getId());
}
if (!channelExists) {
// 得到对方用户(ToUser)的在线状态
if(dto.getType().equals("P")) {
User toUser = DAOFactory.createUserDAO().getById(dto.getToUserId());
if(toUser != null) {
returnChannel.getTo().setOnlineStatus(toUser.getOnlineStatus());
}
}
// 保存频道成员
List members = this.getMembers(dto);
DAOFactory.createChannelMemberDAO().save(returnChannel.getId(), members);
// 保存用户频道信息
List userChannels = this.getUserChannels(channel, members);
DAOFactory.createUserChannelDAO().batchSave(userChannels);
// 保存未读消息数量
if (dto.getType().equals("P")) {
// 私聊
String[] userIds = new String[] { dto.getFromUserId(), dto.getToUserId() };
DAOFactory.createUnreadMessageCountDAO().batchSave(userIds, returnChannel.getId(), (short)0);
} else {
// 群聊
String[] userIds = new String[dto.getMemberCount()];
for(int i = 0; i < dto.getMemberCount(); i++) {
userIds[i] = dto.getMembers().get(i).getId();
}
DAOFactory.createUnreadMessageCountDAO().batchSave(userIds, returnChannel.getId(), (short)0);
}
this.publishChannelCreatedEvent(returnChannel, members);
this.publishJoinChannelEvent(returnChannel, members, creatorNickname, false);
}
return getDTOFromChannel(returnChannel);
}
/**
* 根据id得到频道信息
*
* @param id
* @return
*/
@Override
public ChannelDTO getById(String id) {
Channel channel = DAOFactory.createChannelDAO().getById(id);
if (channel == null) {
return null;
}
ChannelDTO dto = new ChannelDTO();
BeanUtils.copyProperties(channel, dto);
dto.setCreatorId(channel.getCreator().getId());
return dto;
}
/**
* 得到用户是否为频道的管理员
* @param userId
* @param channelId
* @return
*/
@Override
public boolean isAdmin(String userId, String channelId) {
return DAOFactory.createChannelMemberDAO().isAdmin(userId, channelId);
}
/**
* 更新频道名称
* @param channelId
* @param name
* @return
*/
@Override
public int updateName(String channelId, String name) {
int count = DAOFactory.createChannelDAO().updateStringField(channelId, "name", name);
if(count > 0) {
this.publishNameChangedEvent(channelId, name);
}
return count;
}
/**
* 更新频道用途
* @param channelId
* @param purpose
* @return
*/
@Override
public int updatePurpose(String channelId, String purpose) {
return DAOFactory.createChannelDAO().updateStringField(channelId, "purpose", purpose);
}
/**
* 添加频道成员
* @param channelId
* @param userIds
* @param userNicknames
* @param admin
* @return
*/
@Override
public int addMember(String channelId, String[] userIds, String[] userNicknames, String admin) {
List members = new ArrayList<>(userIds.length);
for(int i = 0; i < userIds.length; i++) {
ChannelMember member = new ChannelMember();
User user = new User();
user.setId(userIds[i]);
user.setNickname(userNicknames[i]);
member.setUser(user);
member.setAdmin(false);
members.add(member);
}
int count = DAOFactory.createChannelMemberDAO().save(channelId, members);
// 更新组成员数量
if(count > 0) {
ChannelDAO dao = DAOFactory.createChannelDAO();
dao.increaseMemberCount(channelId, count);
Channel channel = dao.getById(channelId);
if(channel != null) {
List ucs = new ArrayList<>(userIds.length);
for(String userId : userIds) {
UserChannel uc = new UserChannel();
uc.setChannel(channel);
User user = new User();
user.setId(userId);
uc.setUser(user);
uc.setDisplayName(channel.getName());
ucs.add(uc);
}
DAOFactory.createUserChannelDAO().batchSave(ucs);
DAOFactory.createUnreadMessageCountDAO().batchSave(userIds, channelId, (short)0);
this.publishJoinChannelEvent(channel, members, admin, true);
}
new MembersCountChangedEvent(channelId, count).trigger();
}
return count;
}
/**
* 移除组成员
* @param channelId
* @param memberId
* @param memberNickname
* @param admin
* @return
*/
@Override
public int removeMember(String channelId, String memberId, String memberNickname, String admin) {
int count = DAOFactory.createChannelMemberDAO().removeMember(channelId, memberId);
if(count > 0) {
DAOFactory.createChannelDAO().increaseMemberCount(channelId, -1);
DAOFactory.createUserChannelDAO().remove(memberId, channelId);
DAOFactory.createUnreadMessageCountDAO().remove(channelId, memberId);
new MembersCountChangedEvent(channelId, -1).trigger();
NotificationEvent event = new RemoveFromChannelEvent(channelId, new String[] { memberId }, new String[] { memberNickname },
admin, true);
event.trigger();
}
return count;
}
/**
* 得到成员列表
* @param channelId
* @param username
* @param limit
* @param offset
* @return
*/
@Override
public Page listMember(String channelId, String username, int limit, int offset) {
Page members = DAOFactory.createChannelMemberDAO().listMember(channelId, username, limit, offset);
List dtos = new ArrayList<>(members.getRows().size());
for(ChannelMember member : members.getRows()) {
ChannelMemberDTO dto = new ChannelMemberDTO();
dto.setId(member.getUser().getId());
dto.setNickname(member.getUser().getNickname());
dto.setAdmin(member.getAdmin());
dtos.add(dto);
}
return new Page(members.getTotal(), dtos);
}
/**
* 变更频道管理员
* @param channelId
* @param memberId
* @param isAdmin
* @return
*/
@Override
public int changeAdmin(String channelId, String memberId, boolean isAdmin) {
return DAOFactory.createChannelMemberDAO().changeAdmin(channelId, memberId, isAdmin);
}
/**
* 离开频道
* @param channelId
* @param memberId
* @param memberNickname
* @return
*/
@Override
public int leaveChannel(String channelId, String memberId, String memberNickname) {
int count = DAOFactory.createChannelMemberDAO().removeMember(channelId, memberId);
if(count > 0) {
DAOFactory.createChannelDAO().increaseMemberCount(channelId, -1);
DAOFactory.createUserChannelDAO().remove(memberId, channelId);
DAOFactory.createUnreadMessageCountDAO().remove(channelId, memberId);
new MembersCountChangedEvent(channelId, -1).trigger();
}
return count;
}
/**
* 删除频道
* @param channelId
* @param adminId
*/
@Override
public int removeChannel(String channelId, String adminId) {
// 判断删除群组的管理员是否是群组创建人
ChannelDAO dao = DAOFactory.createChannelDAO();
Channel channel = dao.getById(channelId);
if(channel != null) {
if(!channel.getCreator().getId().equals(adminId)) {
return 0;
}
int count = dao.remove(channelId);
if(count > 0) {
NotificationEvent event = new ChannelRemovedEvent(channelId);
event.trigger();
}
return count;
}
return 0;
}
/**
* 从Channel得到ChannelDTO
* @param channel
* @return
*/
private ChannelDTO getDTOFromChannel(Channel channel) {
ChannelDTO dto = new ChannelDTO();
BeanUtils.copyProperties(channel, dto);
dto.setCreatorId(channel.getCreator().getId());
dto.setFromUserId(channel.getFrom() == null ? null : channel.getFrom().getId());
dto.setFromUsername(channel.getFrom() == null ? null : channel.getFrom().getName());
dto.setFromUserNickname(channel.getFrom() == null ? null : channel.getFrom().getNickname());
dto.setToUserId(channel.getTo() == null ? null : channel.getTo().getId());
dto.setToUsername(channel.getTo() == null ? null : channel.getTo().getName());
dto.setToUserNickname(channel.getTo() == null ? null : channel.getTo().getNickname());
dto.setType(channel.getType());
if(dto.getType().equals("P")) {
dto.setToUserOnlineStatus(channel.getTo().getOnlineStatus());
}
return dto;
}
/**
* 得到频道成员
*
* @param dto
* @return
*/
private List getMembers(ChannelDTO dto) {
List members = new ArrayList<>(dto.getMemberCount());
for (ChannelMemberDTO memberDto : dto.getMembers()) {
ChannelMember member = new ChannelMember();
User user = new User();
user.setId(memberDto.getId());
user.setNickname(memberDto.getNickname());
member.setUser(user);
member.setAdmin(memberDto.getAdmin());
members.add(member);
}
return members;
}
/**
* 得到用户频道
*
* @param channel
* @param members
* @return
*/
private List getUserChannels(Channel channel, List members) {
List userChannelList = null;
if (channel.getType().equals("P")) {
// 私聊
userChannelList = new ArrayList<>(2);
UserChannel userChannel1 = new UserChannel();
userChannel1.setUser(channel.getFrom());
userChannel1.setChannel(channel);
userChannel1.setDisplayName(
channel.getTo().getNickname() != null && !channel.getTo().getNickname().trim().isEmpty()
? channel.getTo().getNickname() : channel.getTo().getName());
userChannel1.setToUser(channel.getTo());
userChannelList.add(userChannel1);
UserChannel userChannel2 = new UserChannel();
userChannel2.setUser(channel.getTo());
userChannel2.setChannel(channel);
userChannel2.setDisplayName(
channel.getFrom().getNickname() != null && !channel.getFrom().getNickname().trim().isEmpty()
? channel.getFrom().getNickname() : channel.getFrom().getName());
userChannel2.setToUser(channel.getFrom());
userChannelList.add(userChannel2);
return userChannelList;
}
// 群聊
userChannelList = new ArrayList<>(members.size());
for (ChannelMember member : members) {
UserChannel userChannel = new UserChannel();
userChannel.setUser(member.getUser());
userChannel.setChannel(channel);
userChannel.setDisplayName(channel.getName());
userChannelList.add(userChannel);
}
return userChannelList;
}
/**
* 发布频道创建事件
* @param channel
* @param members
*/
private void publishChannelCreatedEvent(Channel channel, List members) {
StringBuilder userIds = null;
if(channel.getType().equals("P")) {
// 私聊
userIds = new StringBuilder(66);
userIds.append(channel.getFrom().getId()).append(",").append(channel.getTo().getId()).append(",");
} else {
userIds = new StringBuilder(33 * channel.getMemberCount());
for(ChannelMember member : members) {
userIds.append(member.getUser().getId()).append(",");
}
}
userIds.setLength(userIds.length() - 1);
NotificationEvent event = new ChannelCreatedEvent(channel.getId(), userIds.toString());
event.trigger();
}
/**
* 发布加入频道事件
* @param channel
* @param members
* @param admin
* @param sendBroadcast
*/
private void publishJoinChannelEvent(Channel channel, List members, String admin, boolean sendBroadcast) {
String[] userIds = null;
String[] userNicknames = null;
if(channel.getType().equals("G")) {
userIds = new String[members.size()];
userNicknames = new String[members.size()];
for(int i = 0; i < members.size(); i++) {
userIds[i] = members.get(i).getUser().getId();
userNicknames[i] = members.get(i).getUser().getNickname();
}
} else {
userIds = new String[] { channel.getTo().getId() };
}
NotificationEvent event = new JoinChannelEvent(channel.getId(), userIds, userNicknames, admin, sendBroadcast);
event.trigger();
}
/**
* 发布频道名称改变事件
* @param channelId
* @param channelName
*/
private void publishNameChangedEvent(String channelId, String channelName) {
NotificationEvent event = new ChannelNameChangedEvent(channelId, channelName);
event.trigger();
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/MessageServiceImpl.java
================================================
package org.leo.im.service;
import java.util.ArrayList;
import java.util.List;
import org.leo.im.api.dto.FileDTO;
import org.leo.im.api.dto.MessageDTO;
import org.leo.im.api.service.MessageService;
import org.leo.im.model.Channel;
import org.leo.im.model.File;
import org.leo.im.model.Message;
import org.leo.im.model.User;
import org.leo.im.notification.event.MessageRemovedEvent;
import org.leo.im.notification.event.NewMessageEvent;
import org.leo.im.notification.event.NotificationEvent;
import org.leo.im.notification.event.ReadMessageEvent;
import org.leo.im.store.dao.UnreadMessageCountDAO;
import org.leo.im.store.factory.DAOFactory;
import org.leo.im.util.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
/**
* 消息服务实现类
*
* @author Leo
* @date 2018/5/16
*/
public final class MessageServiceImpl implements MessageService {
private static final Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
/**
* 得到消息列表
* @param channelId
* @param maxCreateAt
* @param limit
* @return
*/
@Override
public List listMessage(String channelId, long maxCreateAt, int limit) {
List list = DAOFactory.createMessageDAO().listMessage(channelId, maxCreateAt, limit);
List dtoList = new ArrayList<>(list.size());
for(Message message : list) {
MessageDTO dto = new MessageDTO();
BeanUtils.copyProperties(message, dto);
dto.setSenderId(message.getSender().getId());
dto.setSenderName(message.getSender().getName());
dto.setSenderNickname(message.getSender().getNickname());
dto.setSenderAvatarUrl(message.getSender().getAvatarUrl());
dto.setSenderOnlineStatus(message.getSender().getOnlineStatus());
dto.setSenderFirstLetterOfName(message.getSender().getFirstLetterOfName());
if(message.getFile() != null) {
dto.setFileId(message.getFile().getId());
dto.setFileName(message.getFile().getName());
dto.setFileExtension(message.getFile().getExtension());
dto.setFileSize(message.getFile().getSize());
dto.setFileMimeType(message.getFile().getMimeType());
dto.setImageWidth(message.getFile().getWidth());
dto.setImageHeight(message.getFile().getHeight());
dto.setImageThumbWidth(message.getFile().getThumbWidth());
dto.setImageThumbHeight(message.getFile().getThumbHeight());
dto.setFilePath(message.getFile().getPath());
}
dtoList.add(dto);
}
return dtoList;
}
/**
* 根据id得到消息
* @param id
* @return
*/
@Override
public MessageDTO getById(long id) {
Message message = DAOFactory.createMessageDAO().getById(id);
if(message != null) {
MessageDTO dto = new MessageDTO();
BeanUtils.copyProperties(message, dto);
dto.setChannelId(message.getChannel().getId());
dto.setSenderId(message.getSender().getId());
dto.setSenderName(message.getSender().getName());
dto.setSenderNickname(message.getSender().getNickname());
dto.setSenderAvatarUrl(message.getSender().getAvatarUrl());
dto.setSenderOnlineStatus(message.getSender().getOnlineStatus());
dto.setSenderFirstLetterOfName(message.getSender().getFirstLetterOfName());
if(message.getFile() != null) {
dto.setFileId(message.getFile().getId());
dto.setFileName(message.getFile().getName());
dto.setFileExtension(message.getFile().getExtension());
dto.setFileSize(message.getFile().getSize());
dto.setFileMimeType(message.getFile().getMimeType());
dto.setImageWidth(message.getFile().getWidth());
dto.setImageHeight(message.getFile().getHeight());
dto.setImageThumbWidth(message.getFile().getThumbWidth());
dto.setImageThumbHeight(message.getFile().getThumbHeight());
dto.setFilePath(message.getFile().getPath());
}
return dto;
}
return null;
}
/**
* 添加消息
* @param dto
* @return
*/
@Override
public MessageDTO saveMessage(MessageDTO dto) {
Message message = new Message();
BeanUtils.copyProperties(dto, message);
Channel channel = new Channel();
channel.setId(dto.getChannelId());
message.setChannel(channel);
User sender = new User();
sender.setId(dto.getSenderId());
message.setSender(sender);
if(dto.getFileId() != null && !dto.getFileId().trim().isEmpty()) {
File file = new File();
file.setId(dto.getFileId().trim());
message.setFile(file);
}
long id = DAOFactory.createMessageDAO().save(message);
if(id > 0) {
// 更新频道的最后发送消息时间
DAOFactory.createChannelDAO().updateLastPostAt(dto.getChannelId(), dto.getCreateAt());
MessageDTO resultDTO = this.getById(id);
if(resultDTO != null) {
// 更新用户的未读消息数量
Channel channelModel = DAOFactory.createChannelDAO().getById(dto.getChannelId());
if(channelModel == null) {
logger.warn("The channel is not found, channel id: " + dto.getChannelId());
} else {
if(channelModel.getType().equals("P")) {
// 私聊
String userId = dto.getSenderId().equals(channelModel.getFrom().getId()) ? channelModel.getTo().getId() : channelModel.getFrom().getId();
DAOFactory.createUnreadMessageCountDAO().increase(userId, dto.getChannelId(), (short)1);
// 删除对方的隐藏频道
DAOFactory.createHideChannelDAO().remove(userId, dto.getChannelId());
} else {
// 群聊
DAOFactory.createUnreadMessageCountDAO().increaseGroupChannel(dto.getChannelId(), new String[]{ dto.getSenderId() }, (short)1);
}
this.publishNewMessageEvent(resultDTO, channelModel);
}
}
return resultDTO;
}
return null;
}
/**
* 批量添加消息
* @param dtos
* @return
*/
@Override
public int saveMessage(List dtos) {
List messages = new ArrayList<>(dtos.size());
for(MessageDTO dto : dtos) {
Message message = new Message();
BeanUtils.copyProperties(dto, message);
Channel channel = new Channel();
channel.setId(dto.getChannelId());
message.setChannel(channel);
User sender = new User();
sender.setId(dto.getSenderId());
message.setSender(sender);
messages.add(message);
}
int total = DAOFactory.createMessageDAO().save(messages);
DAOFactory.createChannelDAO().updateLastPostAt(dtos.get(0).getChannelId(), dtos.get(0).getCreateAt());
// 更新用户的未读消息数量
if (dtos.get(0).getChannelType().equals("G")) {
DAOFactory.createUnreadMessageCountDAO().increaseGroupChannel(dtos.get(0).getChannelId(), null, (short)(total > 99 ? 99 : total));
}
Channel channelModel = DAOFactory.createChannelDAO().getById(dtos.get(0).getChannelId());
for(MessageDTO dto : dtos) {
this.publishNewMessageEvent(dto, channelModel);
}
return total;
}
/**
* 读取消息
* @param channelId
* @param userId
* @param total
* @return
*/
@Override
public int readMessage(String channelId, String userId, short total) {
UnreadMessageCountDAO dao = DAOFactory.createUnreadMessageCountDAO();
int count = dao.decrease(userId, channelId, total);
boolean readAll = false;
if(count == 0) {
count = dao.update(userId, channelId, (short)0);
readAll = true;
}
NotificationEvent event = new ReadMessageEvent(userId, channelId, total, readAll);
event.trigger();
return count;
}
/**
* 删除消息
* @param messageId
* @param userId
* @return
*/
/**
* 删除消息
* @param messageId
* @param senderId
* @param channelId
* @param toUserId
* @return
*/
@Override
public int removeMessage(long messageId, String senderId, String channelId, String toUserId) {
int count = DAOFactory.createMessageDAO().remove(messageId, senderId);
NotificationEvent event = new MessageRemovedEvent(messageId, senderId, channelId, toUserId);
event.trigger();
return count;
}
/**
* 添加文件
* @param dto
* @return
*/
@Override
public String saveFile(FileDTO dto) {
File file = new File();
BeanUtils.copyProperties(dto, file);
return DAOFactory.createFileDAO().save(file);
}
/**
* 发布新消息
* @param dto
* @param channel
*/
private void publishNewMessageEvent(MessageDTO dto, Channel channel) {
// 判断是私聊还是群聊
JSONObject message = (JSONObject)JSONObject.toJSON(dto);
if(dto.getType() != null && !dto.getType().isEmpty()) {
message.put("type", dto.getType());
}
if(channel.getType().equals("P")) {
// 私聊
message.put("userIds", dto.getSenderId().equals(channel.getFrom().getId()) ? channel.getTo().getId() : channel.getFrom().getId());
} else {
message.put("groupIds", channel.getId());
}
NotificationEvent event = new NewMessageEvent(message);
event.trigger();
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/UnreadMessageCountServiceImpl.java
================================================
package org.leo.im.service;
import org.leo.im.api.service.UnreadMessageCountService;
import org.leo.im.store.dao.UnreadMessageCountDAO;
import org.leo.im.store.factory.DAOFactory;
/**
* 未读消息数量
* @author Administrator
*
*/
public class UnreadMessageCountServiceImpl implements UnreadMessageCountService {
/**
* 批量添加未读消息数量
* @param userIds
* @param channelId
* @param total
* @return
*/
@Override
public int batchSaveUnreadMessageCount(String[] userIds, String channelId, short total) {
UnreadMessageCountDAO dao = DAOFactory.createUnreadMessageCountDAO();
return dao.batchSave(userIds, channelId, total);
}
/**
* 更新未读消息数量
* @param userId
* @param channelId
* @param quantity
* @return
*/
@Override
public int updateUnreadMessageCount(String userId, String channelId, short total) {
UnreadMessageCountDAO dao = DAOFactory.createUnreadMessageCountDAO();
return dao.update(userId, channelId, total);
}
/**
* 批量更新未读消息数量
* @param userIds
* @param channelId
* @param quantity
* @return
*/
@Override
public int batchUpdateUnreadMessageCount(String[] userIds, String channelId, short total) {
UnreadMessageCountDAO dao = DAOFactory.createUnreadMessageCountDAO();
return dao.batchUpdate(userIds, channelId, total);
}
/**
* 批量增加未读消息数量
* @param userIds
* @param channelId
* @param quantity
* @return
*/
@Override
public int batchIncreaseUnreadMessageCount(String[] userIds, String channelId, short quantity) {
UnreadMessageCountDAO dao = DAOFactory.createUnreadMessageCountDAO();
return dao.batchIncrease(userIds, channelId, quantity);
}
/**
* 增加未读消息数量
* @param userId
* @param channelId
* @param quantity
* @return
*/
@Override
public int increaseUnreadMessageCount(String userId, String channelId, short quantity) {
UnreadMessageCountDAO dao = DAOFactory.createUnreadMessageCountDAO();
return dao.increase(userId, channelId, quantity);
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/UserChannelServiceImpl.java
================================================
package org.leo.im.service;
import java.util.ArrayList;
import java.util.List;
import org.leo.im.api.dto.UserChannelDTO;
import org.leo.im.api.service.UserChannelService;
import org.leo.im.model.UserChannel;
import org.leo.im.store.factory.DAOFactory;
/**
* 用户频道服务实现类
*
* @author Lining
* @date 2018/4/20
*/
public final class UserChannelServiceImpl implements UserChannelService {
/**
* 得到用户频道列表
* @param userId
* @param type
* @param limit
* @return
*/
@Override
public List listUserChannel(String userId, String type, int limit) {
List list = DAOFactory.createUserChannelDAO().listByUserId(userId, type, limit);
List dtoList = new ArrayList<>(list.size());
for(UserChannel userChannel : list) {
UserChannelDTO dto = new UserChannelDTO();
dto.setChannelId(userChannel.getChannel().getId());
dto.setChannelName(userChannel.getChannel().getName());
dto.setChannelType(userChannel.getChannel().getType());
dto.setChannelDisplayName(userChannel.getDisplayName());
dto.setCreatorId(userChannel.getChannel().getCreator().getId());
if(dto.getChannelType().equals("P")) {
dto.setToUserId(userChannel.getToUser().getId());
dto.setToUserOnlineStatus(userChannel.getToUser().getOnlineStatus());
}
dto.setUnreadMessageCount(userChannel.getUnreadMessageCount());
dtoList.add(dto);
}
return dtoList;
}
/**
* 得到用户频道
* @param userId
* @param channelId
* @return
*/
@Override
public UserChannelDTO get(String userId, String channelId) {
UserChannel userChannel = DAOFactory.createUserChannelDAO().get(userId, channelId);
if(userChannel == null) {
return null;
}
UserChannelDTO dto = new UserChannelDTO();
dto.setChannelId(userChannel.getChannel().getId());
dto.setChannelName(userChannel.getChannel().getName());
dto.setChannelType(userChannel.getChannel().getType());
dto.setChannelDisplayName(userChannel.getDisplayName());
dto.setMemberCount(userChannel.getChannel().getMemberCount());
dto.setCreatorId(userChannel.getChannel().getCreator().getId());
if(dto.getChannelType().equals("P")) {
dto.setToUserId(userChannel.getToUser().getId());
dto.setToUserOnlineStatus(userChannel.getToUser().getOnlineStatus());
}
dto.setUnreadMessageCount(userChannel.getUnreadMessageCount());
return dto;
}
/**
* 更新用户频道
* @param channelId
* @param userId
* @param displayName
* @return
*/
@Override
public int updateDisplayName(String channelId, String userId, String displayName) {
return DAOFactory.createUserChannelDAO().updateDisplayName(channelId, userId, displayName);
}
/**
* 隐藏频道
* @param userId
* @param channelId
* @return
*/
@Override
public int hideChannel(String userId, String channelId) {
return DAOFactory.createHideChannelDAO().save(userId, channelId);
}
/**
* 根据名称得到用户频道列表
* @param userId
* @param name
* @param type
* @return
*/
@Override
public List listByName(String userId, String name, String type) {
List list = DAOFactory.createUserChannelDAO().listByName(userId, name, type);
List dtoList = new ArrayList<>(list.size());
for(UserChannel userChannel : list) {
UserChannelDTO dto = new UserChannelDTO();
dto.setChannelId(userChannel.getChannel().getId());
dto.setChannelName(userChannel.getChannel().getName());
dto.setChannelType(userChannel.getChannel().getType());
dto.setChannelDisplayName(userChannel.getDisplayName());
dto.setCreatorId(userChannel.getChannel().getCreator().getId());
if(dto.getChannelType().equals("P")) {
dto.setToUserId(userChannel.getToUser().getId());
dto.setToUserOnlineStatus(userChannel.getToUser().getOnlineStatus());
}
dto.setUnreadMessageCount(userChannel.getUnreadMessageCount());
dtoList.add(dto);
}
return dtoList;
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/UserServiceImpl.java
================================================
package org.leo.im.service;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.leo.im.api.exception.ServiceException;
import org.leo.im.api.service.UserService;
import org.leo.im.common.data.Page;
import org.leo.im.api.dto.UserDTO;
import org.leo.im.model.User;
import org.leo.im.notification.event.AvatarChangedEvent;
import org.leo.im.notification.event.NicknameChangedEvent;
import org.leo.im.notification.event.NotificationEvent;
import org.leo.im.notification.event.OnlineStatusChangedEvent;
import org.leo.im.service.util.PasswordUtils;
import org.leo.im.store.dao.UserDAO;
import org.leo.im.store.factory.DAOFactory;
import org.leo.im.util.BeanUtils;
/**
* 用户服务实现类
*
* @author Leo
* @date 2018/4/9
*/
public final class UserServiceImpl implements UserService {
/**
* 验证用户登录
* @param name
* @param password
* @return
*/
@Override
public UserDTO verifyLogin(String name, String password) {
User user = DAOFactory.createUserDAO().getByName(name);
if(user == null) {
return null;
}
String md5Password = null;
try {
md5Password = PasswordUtils.getMd5Password(password, user.getSalt());
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new ServiceException(e);
}
if(md5Password != null && md5Password.equals(user.getPassword())) {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(user, dto);
return dto;
}
return null;
}
/**
* 根据id得到用户
* @param id
* @return
*/
@Override
public UserDTO getById(String id) {
UserDTO dto = new UserDTO();
User user = DAOFactory.createUserDAO().getById(id);
if(user != null) {
BeanUtils.copyProperties(user, dto);
}
return dto;
}
/**
* 添加用户
* @param dto
* @return
*/
@Override
public String saveUser(UserDTO dto) {
UserDAO dao = DAOFactory.createUserDAO();
if(dao.usernameExists(null, dto.getName())) {
throw new ServiceException("用户 " + dto.getName() + " 已存在");
}
User user = new User();
BeanUtils.copyProperties(dto, user);
String salt = PasswordUtils.generateSalt();
user.setSalt(salt);
String md5Password = null;
try {
md5Password = PasswordUtils.getMd5Password(user.getPassword(), salt);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new ServiceException(e);
}
user.setPassword(md5Password);
return dao.save(user);
}
/**
* 根据名称或昵称分页查询用户
* @param name
* @param limit
* @param offset
* @return
*/
@Override
public Page listByNameOrNickname(String name, int limit, int offset) {
Page userResult = DAOFactory.createUserDAO().listByNameOrNickname(name, limit, offset);
List dtoList = new ArrayList<>(userResult.getRows().size());
for(User user : userResult.getRows()) {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(user, dto);
dtoList.add(dto);
}
return new Page(userResult.getTotal(), dtoList);
}
/**
* 更新用户
* @param dto
* @param updateNullValueField
* @return
*/
@Override
public UserDTO updateUser(UserDTO dto, boolean updateNullValueField) {
User user = new User();
BeanUtils.copyProperties(dto, user);
if(dto.getPassword() != null && !dto.getPassword().trim().isEmpty()) {
String salt = PasswordUtils.generateSalt();
user.setSalt(salt);
String md5Password = null;
try {
md5Password = PasswordUtils.getMd5Password(user.getPassword(), salt);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new ServiceException(e);
}
user.setPassword(md5Password);
}
UserDAO dao = DAOFactory.createUserDAO();
if(dao.update(user, updateNullValueField) == 1) {
publishEvent(dto);
User returnUser = dao.getById(dto.getId());
UserDTO returnDTO = new UserDTO();
BeanUtils.copyProperties(returnUser, returnDTO);
return returnDTO;
}
return null;
}
/**
*
* @param channelId
* @param username
* @param limit
* @param offset
* @return
*/
public Page listNonMembers(String channelId, String username, int limit, int offset) {
Page pagedUser = DAOFactory.createUserDAO().listNonMembers(channelId, username, limit, offset);
if(pagedUser.getTotal() == 0) {
return new Page(0, new ArrayList(0));
}
List list = new ArrayList<>(pagedUser.getRows().size());
for(User user : pagedUser.getRows()) {
UserDTO dto = new UserDTO();
dto.setId(user.getId());
dto.setName(user.getName());
dto.setNickname(user.getNickname());
dto.setFirstLetterOfName(user.getFirstLetterOfName());
dto.setAvatarUrl(user.getAvatarUrl());
list.add(dto);
}
return new Page(pagedUser.getTotal(), list);
}
/**
* 批量下线用户
* @param userIds
*/
@Override
public int batchOffline(Set userIds) {
return DAOFactory.createUserDAO().offline(userIds);
}
/**
* 修改用户口令
* @param userId
* @param username
* @param oldPassword
* @param newPassword
* @return
*/
@Override
public int updatePassword(String userId, String username, String oldPassword, String newPassword) {
if(this.verifyLogin(username, oldPassword) != null) {
User user = new User();
// 更新口令
String salt = PasswordUtils.generateSalt();
try {
String newMd5Password = PasswordUtils.getMd5Password(newPassword, salt);
user.setId(userId);
user.setSalt(salt);
user.setPassword(newMd5Password);
return DAOFactory.createUserDAO().update(user, false);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
return 0;
}
}
return 0;
}
/**
* 发布消息
* @param dto
*/
private void publishEvent(UserDTO dto) {
if(dto.getOnlineStatus() != null && !dto.getOnlineStatus().trim().isEmpty()) {
NotificationEvent event = new OnlineStatusChangedEvent(dto.getId(), dto.getOnlineStatus());
event.trigger();
}
if(dto.getNickname() != null && !dto.getNickname().trim().isEmpty()) {
NotificationEvent event = new NicknameChangedEvent(dto.getId(), dto.getNickname());
event.trigger();
}
if(dto.getAvatarUrl() != null && !dto.getAvatarUrl().trim().isEmpty()) {
NotificationEvent event = new AvatarChangedEvent(dto.getId(), dto.getAvatarUrl());
event.trigger();
}
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/support/CacheableHolder.java
================================================
package org.leo.im.service.support;
/**
* 缓存注解持有者
*
* @author Leo
* @date 2018/3/19
*/
public class CacheableHolder {
private static final ThreadLocal THREADLOCAL = new ThreadLocal();
/**
* 设置是否启用缓存注解
* @param cacheable
*/
public static void setCacheable(boolean cacheable) {
THREADLOCAL.set(cacheable);
}
/**
* 得到是否启用缓存注解
* @return
*/
public static boolean getCacheable() {
Boolean cacheable = THREADLOCAL.get();
return cacheable == null ? false : cacheable;
}
/**
* 删除是否启用缓存注解
*/
public static void remove() {
THREADLOCAL.remove();
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/support/ServiceProxy.java
================================================
package org.leo.im.service.support;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import org.leo.im.api.annotation.Cacheable;
import org.leo.im.api.annotation.Transactional;
import org.leo.im.store.connection.impl.PoolConnectionFactory;
/**
* 服务代理类
*
* @author Leo
* @date 2018/3/23
*/
public final class ServiceProxy implements InvocationHandler {
/**
* 代理目标
*/
private Object target;
private ServiceProxy(Object target) {
this.target = target;
}
/**
* 通过Class来生成动态代理对象Proxy
*
* @param target
* @param connectionString
* 数据库连接字符串
* @return
*/
@SuppressWarnings("unchecked")
public static T newProxyInstance(Object target) {
return (T) java.lang.reflect.Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new ServiceProxy(target));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 得到数据库连接
Connection conn = PoolConnectionFactory.getInstance().getConnection();
// 判断方法是否启用了缓存注解
CacheableHolder.setCacheable(method.getAnnotation(Cacheable.class) != null);
// 是否启用了事务注解
if (method.getAnnotation(Transactional.class) == null) {
// 执行业务逻辑
try {
return method.invoke(this.target, args);
} finally {
PoolConnectionFactory.getInstance().closeConnection();
CacheableHolder.remove();
}
}
conn.setAutoCommit(false);
try {
Object obj = method.invoke(this.target, args);
conn.commit();
return obj;
} catch (Throwable t) {
conn.rollback();
throw t;
} finally {
PoolConnectionFactory.getInstance().closeConnection();
CacheableHolder.remove();
}
}
}
================================================
FILE: leo-im-service/src/main/java/org/leo/im/service/util/PasswordUtils.java
================================================
package org.leo.im.service.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
/**
* 密码工具类
*
* @author Leo
* @date 2018/3/20
*/
public final class PasswordUtils {
/**
* 盐的长度
*/
private static final int SALT_LENGTH = 16;
/**
* 生成盐
*
* @return
*/
public static String generateSalt() {
byte[] salt = new byte[SALT_LENGTH];
SecureRandom sr = new SecureRandom();
sr.nextBytes(salt);
return Base64.getEncoder().encodeToString(salt);
}
/**
* 得到md5加密口令
*
* @param password
* @param salt
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String getMd5Password(String password, String salt)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bs = md5.digest((password + "|" + salt + "|").getBytes());
return byteToHexString(bs);
}
/**
* 将数组转换成16进制字符串
* @param salt
* @return
*/
private static String byteToHexString(byte[] salt) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < salt.length; i++) {
String hex = Integer.toHexString(salt[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
hexString.append(hex.toUpperCase());
}
return hexString.toString();
}
}
================================================
FILE: leo-im-service/src/test/java/org/leo/im/service/AppTest.java
================================================
package org.leo.im.service;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
================================================
FILE: leo-im-service/target/classes/META-INF/MANIFEST.MF
================================================
Manifest-Version: 1.0
Built-By: Administrator
Class-Path: leo-im-api-1.0.jar leo-im-common-1.0.jar leo-im-store-1.0.
jar mysql-connector-java-8.0.11.jar protobuf-java-2.6.0.jar druid-1.1
.9.jar leo-im-model-1.0.jar leo-im-util-1.0.jar cglib-3.2.6.jar asm-6
.0.jar ant-1.9.6.jar ant-launcher-1.9.6.jar jjwt-0.9.0.jar jackson-da
tabind-2.8.9.jar jackson-annotations-2.8.0.jar jackson-core-2.8.9.jar
leo-im-notification-1.0.jar jedis-2.9.0.jar commons-pool2-2.4.2.jar
fastjson-1.2.47.jar slf4j-api-1.7.25.jar logback-classic-1.2.3.jar lo
gback-core-1.2.3.jar
Build-Jdk: 1.8.0_131
Created-By: Maven Integration for Eclipse
Main-Class: org.leo.im.starter.App
================================================
FILE: leo-im-service/target/classes/META-INF/maven/org.leo.im/leo-im-service/pom.properties
================================================
#Generated by Maven Integration for Eclipse
#Tue Jun 19 09:17:16 CST 2018
version=1.0
groupId=org.leo.im
m2e.projectName=leo-im-service
m2e.projectLocation=F\:\\Develop\\open-source\\leo-im-server\\leo-im-service
artifactId=leo-im-service
================================================
FILE: leo-im-service/target/classes/META-INF/maven/org.leo.im/leo-im-service/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-service
leo-im-service
http://maven.apache.org
org.leo.im
leo-im-api
${parent.version}
org.leo.im
leo-im-store
${parent.version}
org.leo.im
leo-im-util
${project.version}
org.leo.im
leo-im-notification
${project.version}
com.alibaba
fastjson
${fastjson.version}
================================================
FILE: leo-im-service/target/maven-archiver/pom.properties
================================================
#Generated by Maven
#Tue Jun 12 16:14:18 CST 2018
version=1.0
groupId=org.leo.im
artifactId=leo-im-service
================================================
FILE: leo-im-service/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
================================================
================================================
FILE: leo-im-service/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\ChannelServiceImpl.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\UnreadMessageCountServiceImpl.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\UserServiceImpl.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\support\ServiceProxy.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\support\CacheableHolder.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\util\PasswordUtils.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\MessageServiceImpl.java
F:\Develop\open-source\leo-im-server\leo-im-service\src\main\java\org\leo\im\service\UserChannelServiceImpl.java
================================================
FILE: leo-im-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
================================================
================================================
FILE: leo-im-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
================================================
F:\Develop\open-source\leo-im-server\leo-im-service\src\test\java\org\leo\im\service\AppTest.java
================================================
FILE: leo-im-service/target/surefire-reports/TEST-org.leo.im.service.AppTest.xml
================================================
================================================
FILE: leo-im-service/target/surefire-reports/org.leo.im.service.AppTest.txt
================================================
-------------------------------------------------------------------------------
Test set: org.leo.im.service.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.088 sec
================================================
FILE: leo-im-socket/.classpath
================================================
================================================
FILE: leo-im-socket/.project
================================================
leo-im-socket
org.eclipse.jdt.core.javabuilder
org.eclipse.m2e.core.maven2Builder
org.eclipse.jdt.core.javanature
org.eclipse.m2e.core.maven2Nature
================================================
FILE: leo-im-socket/.settings/org.eclipse.core.resources.prefs
================================================
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/=UTF-8
================================================
FILE: leo-im-socket/.settings/org.eclipse.jdt.core.prefs
================================================
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
================================================
FILE: leo-im-socket/.settings/org.eclipse.m2e.core.prefs
================================================
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
================================================
FILE: leo-im-socket/pom.xml
================================================
4.0.0
org.leo.im
leo-im
1.0
leo-im-socket
leo-im-socket
http://maven.apache.org
io.netty
netty-all
${netty.version}
org.leo.im
leo-im-util
${project.version}
org.leo.im
leo-im-api
${project.version}
org.leo.im
leo-im-api-provider
${project.version}
org.leo.im
leo-im-notification
${project.version}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/ChannelIdSet.java
================================================
package org.leo.im.socket;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Channel Id 集合类
* 使用读写锁保证一个用户多个连接保存和删除的同步性
*
* @author Leo
* @date 2018/3/29
*/
public class ChannelIdSet {
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
private Set channelIds = new HashSet<>();
/**
* 得到列表长度
*
* @return
*/
public int size() {
try {
this.rwLock.writeLock().lock();
return this.channelIds.size();
} finally {
this.rwLock.writeLock().unlock();
}
}
/**
* 得到包含Channel Id的集合
*
* @return
*/
public Set getSet() {
try {
rwLock.readLock().lock();
return this.channelIds;
} finally {
rwLock.readLock().unlock();
}
}
/**
* 添加Channel Id
*
* @param channelId
* @return
*/
public boolean add(String channelId) {
try {
rwLock.writeLock().lock();
return this.channelIds.add(channelId);
} finally {
rwLock.writeLock().unlock();
}
}
/**
* 删除Channel Id
*
* @param channelId
* @return
*/
public boolean remove(String channelId) {
try {
rwLock.writeLock().lock();
return this.channelIds.remove(channelId);
} finally {
rwLock.writeLock().unlock();
}
}
}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/ChannelsHolder.java
================================================
package org.leo.im.socket;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.ImmediateEventExecutor;
/**
* 通道持有者类
*
* @author Leo
* @date 2018/3/29
*/
public class ChannelsHolder {
private static final Map CHANNELS = new ConcurrentHashMap<>(1024);
/**
* ChannelGroup
* group会自动监测里面的channel,当channel断开时,会主动踢出该channel,永远保留当前可用的channel列表 。
*/
private static final Map CHANNEL_GROUPS = new ConcurrentHashMap<>(100);
/**
* 用户和Channel对应关系哈希Map
*/
private static final Map USER_CHANNEL_IDS = new ConcurrentHashMap<>(1024);
/**
* Channel和用户对应关系哈希Map
*/
private static final Map CHANNEL_USER_ID = new ConcurrentHashMap<>(1024);
/**
* Channel和IM频道的的对应关系哈希Map
*/
// private static final Map CHANNEL_IM_CHANNELS = new ConcurrentHashMap<>(1024);
public static Map getChannelGroups() {
return CHANNEL_GROUPS;
}
/**
* 添加Channel
* @param userId
* @param channel
*/
public static void addChannel(String userId, Channel channel) {
if(CHANNEL_GROUPS.containsKey("all")) {
CHANNEL_GROUPS.get("all").add(channel);
}
String channelId = channel.id().asShortText();
CHANNELS.putIfAbsent(channelId, channel);
ChannelIdSet channels = new ChannelIdSet();
channels.add(channelId);
ChannelIdSet returnSet = USER_CHANNEL_IDS.putIfAbsent(userId, channels);
if(returnSet != null) {
returnSet.add(channelId);
}
CHANNEL_USER_ID.putIfAbsent(channelId, userId);
}
/**
* 删除Channel
* @param channelId
*/
public static void removeChannel(String channelId) {
CHANNELS.remove(channelId);
String currentUserId = CHANNEL_USER_ID.get(channelId);
if(currentUserId != null) {
ChannelIdSet userIds = USER_CHANNEL_IDS.get(currentUserId);
if(userIds != null) {
if(userIds.remove(channelId)) {
if(userIds.size() == 0) {
USER_CHANNEL_IDS.remove(currentUserId);
}
}
}
}
CHANNEL_USER_ID.remove(channelId);
}
/**
* 根据频道id得到用户id
* @param channelId
* @return
*/
public static String getUserIdByChannelId(String channelId) {
return CHANNEL_USER_ID.get(channelId);
}
/**
* 根据用户id得到channel集合
* @param userId
* @return
*/
public static ChannelIdSet getChannelsByUserId(String userId) {
return USER_CHANNEL_IDS.get(userId);
}
/**
* 根据channel id得到channel
* @param channelId
* @return
*/
public static Channel getChannelById(String channelId) {
return CHANNELS.get(channelId);
}
/**
* 将channel添加到GroupChannel中
* @param groupId
* @param channel
*/
public static void addChannelToGroup(String groupId, Channel channel) {
DefaultChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
ChannelGroup returnChannelGroup = CHANNEL_GROUPS.putIfAbsent(groupId, channelGroup);
if(returnChannelGroup == null) {
// 不存在该ChannelGroup,第一次添加。
channelGroup.add(channel);
return;
}
// ChannelGroup已经存在
returnChannelGroup.add(channel);
}
/**
* 添加IM Channel Id
* @param channelId
* @param IMChannelId
*/
// public static void addIMChannel(String channelId, String IMChannelId) {
// CHANNEL_IM_CHANNELS.put(channelId, IMChannelId);
// }
/**
* 移除IM Channel Id
* @param channelId
*/
// public static void removeIMChannel(String channelId) {
// CHANNEL_IM_CHANNELS.remove(channelId);
// }
/**
* 得到所用用户id
* @return
*/
public static Set getUserIds() {
return USER_CHANNEL_IDS.keySet();
}
}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/SocketChannel.java
================================================
package org.leo.im.socket;
import io.netty.channel.Channel;
/**
* Socket 通道类
*
* @author Leo
* @date 2018/3/29
*/
public class SocketChannel {
private String userId;
private Channel channel;
@Override
public String toString() {
return "SocketChannel [userId=" + userId + ", channel=" + channel + "]";
}
public SocketChannel(Channel channel) {
this.channel = channel;
}
public String getUserId() {
return this.userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Channel getChannel() {
return this.channel;
}
}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/WebSocketChannelInitializer.java
================================================
package org.leo.im.socket;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.leo.im.socket.handler.TextWebSocketFrameHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.RejectedExecutionHandlers;
/**
* WebSocket 通道初始化类
*
* @author Leo
* @date 2018/3/29
*/
public class WebSocketChannelInitializer extends ChannelInitializer {
/**
* 业务线程池线程数
*/
private static int eventExecutorGroupThreads = 0;
/**
* 业务线程池队列长度
*/
private static int eventExecutorGroupQueues = 0;
static {
eventExecutorGroupThreads = Integer.getInteger("websocket.executor.threads", 0);
if(eventExecutorGroupThreads == 0) {
eventExecutorGroupThreads = Runtime.getRuntime().availableProcessors();
}
eventExecutorGroupQueues = Integer.getInteger("websocket.executor.queues", 0);
if(eventExecutorGroupQueues == 0) {
eventExecutorGroupQueues = 512;
}
}
/**
* 业务线程组
*/
private static final EventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(
eventExecutorGroupThreads, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "WebSocketRequestHandlerThread_" + this.threadIndex.incrementAndGet());
}
}, eventExecutorGroupQueues, RejectedExecutionHandlers.reject());
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// WebSocket协议本身是基于HTTP协议的,所以要使用HTTP解编码器
pipeline.addLast(new HttpServerCodec());
// 以块的方式来写的处理器
pipeline.addLast(new ChunkedWriteHandler());
// Netty是基于分段请求的,HttpObjectAggregator的作用是将请求分段再聚合,参数是聚合字节的最大长度
pipeline.addLast(new HttpObjectAggregator(8192));
// 文本消息处理器
pipeline.addLast(eventExecutorGroup, new TextWebSocketFrameHandler());
}
}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/WebSocketServer.java
================================================
package org.leo.im.socket;
import java.util.HashSet;
import java.util.Set;
import org.leo.im.notification.PublisherFactory;
import org.leo.im.socket.subscription.SubscriberFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.ImmediateEventExecutor;
/**
* WebSocket Server
*
* @author Leo
* @date 2018/4/3
*/
public class WebSocketServer {
private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
/**
* 监听端口号
*/
private int port;
/**
* Boss线程数
*/
private int bossThreads = 1;
/**
* Worker线程数
*/
private int workerThreads = 2;
public WebSocketServer(int port) {
this.port = port;
}
public int getBossThreads() {
return this.bossThreads;
}
public void setBossThreads(int bossThreads) {
this.bossThreads = bossThreads;
}
public int getWorkerThreads() {
return this.workerThreads;
}
public void setWorkerThreads(int workerThreads) {
this.workerThreads = workerThreads;
}
/**
* 启动服务
* @throws InterruptedException
*/
public void start() throws InterruptedException {
// 参考:https://www.jianshu.com/p/9a97e667cf84 http://www.importnew.com/21561.html http://wiki.jikexueyuan.com/project/netty-4-user-guide/implement-websocket-chat-function.html
/*
* ChannelOption.SO_BACKLOG对应的是TCP/IP协议listen函数中的backlog参数,
* 函数listen(int socketfd,int backlog)用来初始化服务端可连接队列,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接,
* 多个客户端来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小
*/
// BossGroup处理nio的Accept事件(TCP连接)
NioEventLoopGroup bossGroup = new NioEventLoopGroup(this.bossThreads);
// Worker处理nio的Read和Write事件(通道的I/O事件)
NioEventLoopGroup workerGroup = new NioEventLoopGroup(this.workerThreads);
try {
// handler在初始化时就会执行,而childHandler会在客户端成功connect后才执行。
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(new WebSocketChannelInitializer());
ChannelFuture f = bootstrap.bind(port).sync();
logger.info("The netty websocket server is now ready to accept requests on port {}", this.port);
// 初始化群组
// 考虑到群组可能较多,一次性加载占用资源较大,所以在每个用户登录后,将其加载的群组注册到服务中。
// initChannelGroup();
ChannelsHolder.getChannelGroups().put("all", new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE));
// 订阅消息频道,每个队列对应一个线程,如果规模不大,建议一个队列即可。
Set channelSet = new HashSet<>(3);
channelSet.add(System.getProperty("channel.private.message"));
channelSet.add(System.getProperty("channel.group.message"));
channelSet.add(System.getProperty("channel.system.message"));
Object[] objs = channelSet.toArray();
String[] channels = new String[objs.length];
for(int i = 0; i < objs.length; i++) {
channels[i] = objs[i].toString();
}
PublisherFactory.createPublisher().subscribe(SubscriberFactory.createSubscriber(), channels);
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
/**
* 初始化Netty ChannelGroup
*/
// private void initChannelGroup() {
// // 得到所有群组类型的channel
// Map parameters = new HashMap<>(1);
// parameters.put("deleteAt", 0);
// ChannelService serviceProxy = ServiceProxy.newProxyInstance(ServiceFactory.createChannelService());
// List dtoList = serviceProxy.listGroupChannel(parameters, 0);
// for(ChannelListDTO dto : dtoList) {
// ChannelsHolder.getChannelGroups().put(dto.getId(), new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE));
// }
// ChannelsHolder.getChannelGroups().put("all", new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE));
// }
}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/exception/MessageHandleException.java
================================================
package org.leo.im.socket.exception;
/**
* 消息处理异常类
*
* @author Leo
* @date 2018/3/29
*/
public final class MessageHandleException extends RuntimeException {
private static final long serialVersionUID = -2512674268771543792L;
public MessageHandleException() {
}
public MessageHandleException(String message) {
super(message);
}
public MessageHandleException(String message, Throwable cause) {
super(message, cause);
}
public MessageHandleException(Throwable cause) {
super(cause);
}
}
================================================
FILE: leo-im-socket/src/main/java/org/leo/im/socket/handler/TextWebSocketFrameHandler.java
================================================
package org.leo.im.socket.handler;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.leo.im.api.dto.UserDTO;
import org.leo.im.api.provider.ServiceFactory;
import org.leo.im.api.service.UserService;
import org.leo.im.notification.event.NotificationEvent;
import org.leo.im.notification.event.OnlineStatusChangedEvent;
import org.leo.im.service.support.ServiceProxy;
import org.leo.im.socket.ChannelsHolder;
import org.leo.im.util.JwtUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Claims;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;
/**
* Http 处理器
*
* @author Leo
* @date 2018/3/29
*/
public final class TextWebSocketFrameHandler extends SimpleChannelInboundHandler