├── .gitattributes ├── src ├── im │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ ├── log4j.properties │ │ │ └── applicationContext.xml │ │ │ └── java │ │ │ └── com │ │ │ └── fyp │ │ │ ├── WebSocketApplication.java │ │ │ └── im │ │ │ ├── processor │ │ │ ├── PingProcessor.java │ │ │ ├── ClientToGroupProcessor.java │ │ │ ├── ClientToClientProcessor.java │ │ │ ├── AbstractMsgProcessor.java │ │ │ └── MsgStoredProcessor.java │ │ │ ├── utils │ │ │ ├── LogUtil.java │ │ │ ├── SafeEncoder.java │ │ │ ├── IMUtil.java │ │ │ └── BeanUtil.java │ │ │ ├── listener │ │ │ ├── MyGroupListener.java │ │ │ ├── MyMsgListener.java │ │ │ └── MyIpStatListener.java │ │ │ ├── MsgType.java │ │ │ ├── handler │ │ │ ├── Processor.java │ │ │ └── MyMsgHandler.java │ │ │ └── TioApplication.java │ ├── pom.xml │ └── im.iml ├── web │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ ├── static │ │ │ │ │ ├── images │ │ │ │ │ │ ├── fly.jpg │ │ │ │ │ │ ├── pay.jpg │ │ │ │ │ │ ├── fork.gif │ │ │ │ │ │ ├── layim.jpg │ │ │ │ │ │ ├── logo-1.png │ │ │ │ │ │ ├── logo.png │ │ │ │ │ │ ├── photo.jpg │ │ │ │ │ │ ├── avatar │ │ │ │ │ │ │ ├── 0.jpg │ │ │ │ │ │ │ ├── 1.jpg │ │ │ │ │ │ │ ├── 2.jpg │ │ │ │ │ │ │ ├── 3.jpg │ │ │ │ │ │ │ ├── 4.jpg │ │ │ │ │ │ │ ├── 5.jpg │ │ │ │ │ │ │ ├── 6.jpg │ │ │ │ │ │ │ ├── 7.jpg │ │ │ │ │ │ │ ├── 8.jpg │ │ │ │ │ │ │ ├── 9.jpg │ │ │ │ │ │ │ ├── 00.jpg │ │ │ │ │ │ │ ├── 10.jpg │ │ │ │ │ │ │ ├── 11.jpg │ │ │ │ │ │ │ └── default.png │ │ │ │ │ │ ├── loading.gif │ │ │ │ │ │ ├── demo │ │ │ │ │ │ │ ├── huafei.jpg │ │ │ │ │ │ │ ├── gonggong.jpg │ │ │ │ │ │ │ ├── huanghou.jpg │ │ │ │ │ │ │ ├── xiaoniao.jpg │ │ │ │ │ │ │ ├── zhenhuan.jpg │ │ │ │ │ │ │ ├── huangshang.jpg │ │ │ │ │ │ │ ├── meijiejie.jpg │ │ │ │ │ │ │ └── xiaopanzi.jpg │ │ │ │ │ │ └── other │ │ │ │ │ │ │ ├── study-a.png │ │ │ │ │ │ │ └── 1437100018023.jpg │ │ │ │ │ ├── html │ │ │ │ │ │ ├── common │ │ │ │ │ │ │ ├── link.html │ │ │ │ │ │ │ ├── footer.html │ │ │ │ │ │ │ └── header.html │ │ │ │ │ │ ├── tips.html │ │ │ │ │ │ ├── 404.html │ │ │ │ │ │ ├── user │ │ │ │ │ │ │ ├── message.html │ │ │ │ │ │ │ ├── activate.html │ │ │ │ │ │ │ ├── login.html │ │ │ │ │ │ │ ├── index.html │ │ │ │ │ │ │ ├── reg.html │ │ │ │ │ │ │ ├── home.html │ │ │ │ │ │ │ ├── forget.html │ │ │ │ │ │ │ └── set.html │ │ │ │ │ │ └── jie │ │ │ │ │ │ │ ├── add.html │ │ │ │ │ │ │ └── detail.html │ │ │ │ │ ├── js │ │ │ │ │ │ └── mods │ │ │ │ │ │ │ ├── req.js │ │ │ │ │ │ │ ├── chatlog.js │ │ │ │ │ │ │ └── socket.js │ │ │ │ │ └── json │ │ │ │ │ │ ├── getMembers.json │ │ │ │ │ │ └── getList.json │ │ │ │ ├── templates │ │ │ │ │ ├── error.html │ │ │ │ │ ├── chatlog.html │ │ │ │ │ └── index.html │ │ │ │ └── application.yml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── fyp │ │ │ │ └── web │ │ │ │ ├── controllers │ │ │ │ ├── PageController.java │ │ │ │ ├── BaseController.java │ │ │ │ ├── LayIMController.java │ │ │ │ └── AccountController.java │ │ │ │ ├── WebApplication.java │ │ │ │ └── config │ │ │ │ └── WebConfig.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── fyp │ │ │ └── web │ │ │ └── WebApplicationTests.java │ ├── pom.xml │ └── web.iml ├── service │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ ├── db.properties │ │ │ ├── mapper │ │ │ │ ├── friendGroupMapper.xml │ │ │ │ ├── userBigGroupMapper.xml │ │ │ │ ├── userFriendGroupMapper.xml │ │ │ │ ├── userMapper.xml │ │ │ │ ├── bigGroupMapper.xml │ │ │ │ └── msgRecordMapper.xml │ │ │ └── mybatis-config.xml │ │ │ └── java │ │ │ └── com │ │ │ └── fyp │ │ │ └── service │ │ │ ├── mapper │ │ │ ├── FriendGroupMapper.java │ │ │ ├── UserMapper.java │ │ │ ├── UserFriendGroupMapper.java │ │ │ ├── MsgRecordMapper.java │ │ │ ├── BigGroupMapper.java │ │ │ └── UserBigGroupMapper.java │ │ │ ├── utils │ │ │ ├── Utils.java │ │ │ ├── DruidDataSourceFactory.java │ │ │ └── MyBatisUtil.java │ │ │ ├── intf │ │ │ └── LayIMService.java │ │ │ └── impl │ │ │ └── DefaultLayIMService.java │ ├── pom.xml │ └── service.iml ├── utils │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── fyp │ │ │ └── utils │ │ │ ├── convert │ │ │ └── ConvertUtil.java │ │ │ └── jwt │ │ │ ├── JwtTokenResult.java │ │ │ ├── JwtVertifyResult.java │ │ │ └── JwtUtil.java │ ├── pom.xml │ └── utils.iml ├── entity │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── fyp │ │ │ └── entity │ │ │ ├── result │ │ │ ├── UploadResult.java │ │ │ ├── GroupMemberResult.java │ │ │ ├── InitResult.java │ │ │ ├── ChatRecordResult.java │ │ │ └── JsonResult.java │ │ │ ├── UserFriendGroup.java │ │ │ ├── LayIMConstants.java │ │ │ ├── BigGroup.java │ │ │ ├── FriendGroup.java │ │ │ ├── User.java │ │ │ ├── im │ │ │ └── Message.java │ │ │ └── MsgRecord.java │ ├── entity.iml │ └── pom.xml ├── layim.iml └── pom.xml ├── .gitignore ├── README.md └── layim.sql /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /src/im/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/im/src/main/resources/log4j.properties -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/fly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/fly.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/pay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/pay.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/fork.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/fork.gif -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/layim.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/layim.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/logo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/logo-1.png -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/logo.png -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/photo.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/0.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/1.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/2.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/3.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/4.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/5.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/6.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/7.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/8.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/9.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/loading.gif -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/00.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/10.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/11.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/huafei.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/huafei.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/common/link.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/gonggong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/gonggong.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/huanghou.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/huanghou.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/xiaoniao.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/xiaoniao.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/zhenhuan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/zhenhuan.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/other/study-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/other/study-a.png -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/avatar/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/avatar/default.png -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/huangshang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/huangshang.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/meijiejie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/meijiejie.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/demo/xiaopanzi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/demo/xiaopanzi.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/static/images/other/1437100018023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanpan26/LayIM.SpringBoot/HEAD/src/web/src/main/resources/static/images/other/1437100018023.jpg -------------------------------------------------------------------------------- /src/web/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Error 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/web/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | thymeleaf: 3 | cache: false 4 | prefix: classpath:/templates/ 5 | check-template: false 6 | suffix: .html 7 | encoding: utf-8 8 | debug: false 9 | server: 10 | port: 8887 -------------------------------------------------------------------------------- /src/service/src/main/resources/db.properties: -------------------------------------------------------------------------------- 1 | # 有位兄弟好心的提醒我服务器MySQL账号密码泄露,非常感谢 2 | # 大家发现了可以去用,但是不要去攻击哈,这只是个人的一台阿里云服务器,攻击它也没什么意义 3 | driver=com.mysql.jdbc.Driver 4 | url=jdbc:mysql://120.27.68.127:3306/layim?serverTimezone=GMT%2B8 5 | username=root 6 | password=panzi123!@#$%^ -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/WebSocketApplication.java: -------------------------------------------------------------------------------- 1 | package com.fyp; 2 | 3 | import com.fyp.im.TioApplication; 4 | 5 | public class WebSocketApplication { 6 | 7 | public static void main(String[] args) throws Exception { 8 | new TioApplication().run(); 9 | } 10 | } -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/mapper/FriendGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.mapper; 2 | 3 | import com.fyp.entity.FriendGroup; 4 | 5 | import java.util.List; 6 | 7 | public interface FriendGroupMapper { 8 | List getGroupsByUserId(Long userId); 9 | } 10 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.mapper; 2 | 3 | import com.fyp.entity.User; 4 | 5 | import java.util.List; 6 | 7 | public interface UserMapper { 8 | User getUser(Long id); 9 | List getUsersByIds(List userIds); 10 | } 11 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/mapper/UserFriendGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.mapper; 2 | 3 | import com.fyp.entity.UserFriendGroup; 4 | 5 | import java.util.List; 6 | 7 | public interface UserFriendGroupMapper { 8 | List getUserIdsByGroupIds(List groupIds); 9 | } 10 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/mapper/MsgRecordMapper.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.mapper; 2 | 3 | import com.fyp.entity.MsgRecord; 4 | 5 | import java.util.List; 6 | 7 | public interface MsgRecordMapper { 8 | void addRecord(MsgRecord record); 9 | 10 | List getList(Long roomId,long lastId); 11 | } 12 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/mapper/BigGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.mapper; 2 | 3 | 4 | import com.fyp.entity.BigGroup; 5 | 6 | import java.util.List; 7 | 8 | public interface BigGroupMapper { 9 | ListgetGroupsByGroupIds(List groupIds); 10 | Long getGroupOwnerId(Long groupId); 11 | } 12 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/mapper/UserBigGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.mapper; 2 | 3 | 4 | import com.fyp.entity.BigGroup; 5 | 6 | import java.util.List; 7 | 8 | public interface UserBigGroupMapper { 9 | List getGroupsByUserId(Long userId); 10 | List getGroupMembers(Long groupId); 11 | } 12 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/processor/PingProcessor.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.processor; 2 | 3 | import org.tio.core.ChannelContext; 4 | 5 | /** 6 | * @author fanyuepan 7 | */ 8 | public class PingProcessor extends AbstractMsgProcessor { 9 | @Override 10 | protected void processInternal(ChannelContext channelContext) { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/utils/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | public class LogUtil { 7 | private static final Logger logger = LoggerFactory.getLogger(LogUtil.class); 8 | 9 | public static void debug(String message, Object... args) { 10 | logger.debug(message, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/src/main/java/com/fyp/utils/convert/ConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.fyp.utils.convert; 2 | 3 | public class ConvertUtil { 4 | /** 5 | * byte[] 2 int 6 | * */ 7 | public static int byteArrayToInt(byte[] b) { 8 | return b[3] & 0xFF | 9 | (b[2] & 0xFF) << 8 | 10 | (b[1] & 0xFF) << 16 | 11 | (b[0] & 0xFF) << 24; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | .idea/ 24 | layui/ 25 | upload/ 26 | target/ -------------------------------------------------------------------------------- /src/im/src/main/resources/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/web/src/test/java/com/fyp/web/WebApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class WebApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/listener/MyGroupListener.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.listener; 2 | 3 | import org.tio.core.ChannelContext; 4 | import org.tio.core.intf.GroupListener; 5 | 6 | public class MyGroupListener implements GroupListener { 7 | public void onAfterBind(ChannelContext channelContext, String s) throws Exception { 8 | 9 | } 10 | 11 | public void onAfterUnbind(ChannelContext channelContext, String s) throws Exception { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.utils; 2 | 3 | public class Utils { 4 | /** 5 | * 生成房间ID 6 | */ 7 | public static long generateRoomId(long from, long to, String msgType) { 8 | if (!"group".equals(msgType)) { 9 | if (from > to) { 10 | return Long.valueOf(from + "" + to); 11 | } 12 | return Long.valueOf(to + "" + from); 13 | } 14 | return to; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/web/src/main/java/com/fyp/web/controllers/PageController.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web.controllers; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class PageController { 8 | 9 | @RequestMapping("/") 10 | public String index(){ 11 | return "index"; 12 | } 13 | 14 | @RequestMapping("/chatlog") 15 | public String chatlog() { 16 | return "chatlog"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/result/UploadResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity.result; 2 | 3 | public class UploadResult { 4 | private String src; 5 | 6 | public String getSrc() { 7 | return src; 8 | } 9 | 10 | public void setSrc(String src) { 11 | this.src = src; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | private String name; 23 | } -------------------------------------------------------------------------------- /src/web/src/main/java/com/fyp/web/WebApplication.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web; 2 | 3 | import com.fyp.im.TioApplication; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication(scanBasePackages = "com.fyp.**") 8 | public class WebApplication { 9 | 10 | public static void main(String[] args) throws Exception { 11 | SpringApplication.run(WebApplication.class, args); 12 | 13 | new TioApplication().run(); 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/UserFriendGroup.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity; 2 | 3 | public class UserFriendGroup { 4 | public long getUserId() { 5 | return userId; 6 | } 7 | 8 | public void setUserId(long userId) { 9 | this.userId = userId; 10 | } 11 | 12 | public long getGroupId() { 13 | return groupId; 14 | } 15 | 16 | public void setGroupId(long groupId) { 17 | this.groupId = groupId; 18 | } 19 | 20 | private long userId; 21 | private long groupId; 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/src/main/java/com/fyp/utils/jwt/JwtTokenResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.utils.jwt; 2 | 3 | public class JwtTokenResult { 4 | 5 | public JwtTokenResult(String token){ 6 | this.token = token; 7 | } 8 | 9 | private String token; 10 | private Long expires = 7200L; 11 | 12 | public String getToken(){ 13 | return token; 14 | } 15 | 16 | public Long getExpires(){ 17 | return expires; 18 | } 19 | 20 | public Boolean IsSuccess(){ 21 | return token != null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LayIM.SpringBoot 2 | 3 | 4 | ## 项目升级中,之前代码请移步 old-version 分支 5 | 6 | ## 项目说明 7 |   项目主要技术框架:`SpringBoot(2.1.1.RELEASE)` + `Mybatis(3.4.6)` + `T-io(3.2.4.v20181218-RELEASE)` + `LayIM(3.7.7)` 数据库:`MySql`. 8 | 9 | ## 参考资料 10 | 11 | * [T-io源码:https://gitee.com/tywo45/t-io](https://gitee.com/tywo45/t-io) 12 | * [LayIM官网:http://layim.layui.com/](http://layim.layui.com/) 13 | * [SpringBoot:https://spring.io/projects/spring-boot](https://spring.io/projects/spring-boot) 14 | * [MyBatis:http://www.mybatis.org/](http://www.mybatis.org/) 15 | -------------------------------------------------------------------------------- /src/web/src/main/java/com/fyp/web/controllers/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web.controllers; 2 | 3 | import javax.servlet.http.Cookie; 4 | import javax.servlet.http.HttpServletRequest; 5 | 6 | public class BaseController { 7 | protected Long getUserId(HttpServletRequest request){ 8 | Cookie[] cookies = request.getCookies(); 9 | for (Cookie cookie : cookies){ 10 | if(cookie.getName().equals("layim_uid")){ 11 | return Long.valueOf(cookie.getValue()); 12 | } 13 | } 14 | return Long.valueOf(0L); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/service/src/main/resources/mapper/friendGroupMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/LayIMConstants.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity; 2 | 3 | public final class LayIMConstants { 4 | /** 5 | * LayIMService 标识 6 | * */ 7 | public static final String LAYIM_SERVICE = "layIMService"; 8 | /** 9 | * ChannelContext setAttribute(CURRENT_USER_ATTRIBUTE,userInfo) 10 | * */ 11 | public static final String CURRENT_USER_ATTRIBUTE = "current_user"; 12 | 13 | public static final String CHAT_TYPE_FRIEND = "friend"; 14 | public static final String CHAT_TYPE_GROUP = "group"; 15 | public static final String CHAT_TYPE_OTHER = "other"; 16 | } 17 | -------------------------------------------------------------------------------- /src/layim.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/web/src/main/java/com/fyp/web/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 6 | 7 | @Configuration 8 | public class WebConfig extends WebMvcConfigurationSupport { 9 | @Override 10 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 11 | registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/intf/LayIMService.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.intf; 2 | 3 | import com.fyp.entity.MsgRecord; 4 | import com.fyp.entity.User; 5 | import com.fyp.entity.result.JsonResult; 6 | 7 | import java.util.List; 8 | 9 | public interface LayIMService { 10 | User getByUserId(Long userId); 11 | 12 | JsonResult getInitResult(Long userId); 13 | 14 | JsonResult getMembersByGroupId(Long groupId); 15 | 16 | List getGroupIds(Long userId); 17 | 18 | JsonResult addRecord(MsgRecord record); 19 | 20 | JsonResult getChatRecords(Long userId,Long id,String type,Long lastId); 21 | } 22 | -------------------------------------------------------------------------------- /src/service/src/main/resources/mapper/userBigGroupMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/MsgType.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im; 2 | 3 | public enum MsgType { 4 | ping((byte)3), 5 | clientToClient((byte) 1), 6 | clientToGroup((byte)2); 7 | 8 | MsgType(byte value) { 9 | this.value = value; 10 | } 11 | 12 | public byte getValue() { 13 | return value; 14 | } 15 | 16 | private byte value; 17 | 18 | public static MsgType valueOf(byte value) { 19 | for (MsgType type : MsgType.values()) { 20 | if (type.getValue() == value) { 21 | return type; 22 | } 23 | } 24 | throw new IllegalArgumentException("value "+ value+" is not a MsgType"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/utils/SafeEncoder.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.utils; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | public final class SafeEncoder { 6 | 7 | public static String encode(byte[] bytes) { 8 | try { 9 | return new String(bytes, "utf-8"); 10 | } catch (UnsupportedEncodingException e) { 11 | e.printStackTrace(); 12 | ; 13 | return null; 14 | } 15 | } 16 | 17 | public static byte[] encode(String value) { 18 | try { 19 | return value.getBytes("utf-8"); 20 | } catch (UnsupportedEncodingException e) { 21 | e.printStackTrace(); 22 | ; 23 | return null; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | layim 7 | com.fyp 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | utils 13 | 14 | 15 | 16 | com.auth0 17 | java-jwt 18 | 3.4.0 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/processor/ClientToGroupProcessor.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.processor; 2 | 3 | import com.fyp.entity.LayIMConstants; 4 | import com.fyp.im.utils.IMUtil; 5 | import org.tio.core.ChannelContext; 6 | 7 | public class ClientToGroupProcessor extends MsgStoredProcessor { 8 | @Override 9 | protected void processMessage(ChannelContext channelContext){ 10 | IMUtil.sendToGroup(channelContext,getTargetId(),buildSendMessage(channelContext)); 11 | } 12 | 13 | @Override 14 | protected long getId(ChannelContext channelContext) { 15 | return getTargetId(); 16 | } 17 | 18 | @Override 19 | protected String getType(ChannelContext channelContext) { 20 | return LayIMConstants.CHAT_TYPE_GROUP; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/result/GroupMemberResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity.result; 2 | 3 | import com.fyp.entity.User; 4 | 5 | import java.util.List; 6 | 7 | public class GroupMemberResult { 8 | private int members; 9 | 10 | public int getMembers() { 11 | return members; 12 | } 13 | 14 | private List list; 15 | 16 | public List getList() { 17 | return list; 18 | } 19 | 20 | public void setList(List list) { 21 | this.list = list; 22 | this.members = list.size(); 23 | } 24 | 25 | private User owner; 26 | 27 | public User getOwner() { 28 | return owner; 29 | } 30 | 31 | public void setOwner(User user) { 32 | this.owner = user; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/service/src/main/resources/mapper/userFriendGroupMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /src/entity/entity.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/common/footer.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/processor/ClientToClientProcessor.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.processor; 2 | 3 | import com.fyp.entity.LayIMConstants; 4 | import com.fyp.im.utils.IMUtil; 5 | import org.tio.core.ChannelContext; 6 | 7 | /** 8 | * 客户端对客户端发送消息 9 | * */ 10 | public class ClientToClientProcessor extends MsgStoredProcessor { 11 | 12 | @Override 13 | protected void processMessage(ChannelContext channelContext){ 14 | IMUtil.send(channelContext,getTargetId(),buildSendMessage(channelContext)); 15 | } 16 | 17 | @Override 18 | protected long getId(ChannelContext channelContext) { 19 | return Long.valueOf(channelContext.userid); 20 | } 21 | 22 | @Override 23 | protected String getType(ChannelContext channelContext) { 24 | return LayIMConstants.CHAT_TYPE_FRIEND; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/entity/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | layim 7 | com.fyp 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | entity 13 | 14 | 15 | 16 | com.fasterxml.jackson.core 17 | jackson-annotations 18 | 2.9.0 19 | compile 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/utils/IMUtil.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.utils; 2 | 3 | import org.tio.core.ChannelContext; 4 | import org.tio.core.Tio; 5 | import org.tio.websocket.common.WsResponse; 6 | 7 | 8 | public class IMUtil { 9 | 10 | private static WsResponse buildResponse(byte[] body) { 11 | return WsResponse.fromBytes(body); 12 | } 13 | 14 | public static void sendToGroup(ChannelContext channelContext, long targetId, byte[] body) { 15 | String currentUserId = channelContext.userid; 16 | Tio.sendToGroup(channelContext.getGroupContext(), String.valueOf(targetId), buildResponse(body), ctx -> !ctx.userid.equals(currentUserId)); 17 | } 18 | 19 | public static void send(ChannelContext channelContext, long targetId, byte[] body) { 20 | Tio.sendToUser(channelContext.getGroupContext(), String.valueOf(targetId), buildResponse(body)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/src/main/java/com/fyp/utils/jwt/JwtVertifyResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.utils.jwt; 2 | 3 | public class JwtVertifyResult { 4 | 5 | public static final JwtVertifyResult NotVertified = new JwtVertifyResult(0L); 6 | 7 | public JwtVertifyResult(Long userId){ 8 | this.userId = userId; 9 | } 10 | 11 | private Long userId; 12 | 13 | public String getErrMsg() { 14 | return errMsg; 15 | } 16 | 17 | public void setErrMsg(String errMsg) { 18 | this.errMsg = errMsg; 19 | } 20 | 21 | private String errMsg; 22 | 23 | public Long getUserId(){ 24 | return userId; 25 | } 26 | 27 | public boolean isVertified(){ 28 | return userId > 0; 29 | } 30 | 31 | public static JwtVertifyResult result(String msg){ 32 | JwtVertifyResult result = new JwtVertifyResult(0L); 33 | result.setErrMsg(msg); 34 | return result; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/result/InitResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity.result; 2 | 3 | import com.fyp.entity.BigGroup; 4 | import com.fyp.entity.FriendGroup; 5 | import com.fyp.entity.User; 6 | 7 | import java.util.List; 8 | 9 | public class InitResult { 10 | public User getMine() { 11 | return mine; 12 | } 13 | 14 | public void setMine(User mine) { 15 | this.mine = mine; 16 | } 17 | 18 | public List getFriend() { 19 | return friend; 20 | } 21 | 22 | public void setFriend(List friend) { 23 | this.friend = friend; 24 | } 25 | 26 | public List getGroup() { 27 | return group; 28 | } 29 | 30 | public void setGroup(List group) { 31 | this.group = group; 32 | } 33 | 34 | private User mine; 35 | private List friend; 36 | private List group; 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/BigGroup.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity; 2 | 3 | public class BigGroup { 4 | private String groupname; 5 | private String avatar; 6 | private String description; 7 | private Long id; 8 | 9 | public Long getId() { 10 | return id; 11 | } 12 | 13 | public void setId(Long id) { 14 | this.id = id; 15 | } 16 | 17 | public String getGroupname() { 18 | return groupname; 19 | } 20 | 21 | public void setGroupname(String groupname) { 22 | this.groupname = groupname; 23 | } 24 | 25 | public String getAvatar() { 26 | return avatar; 27 | } 28 | 29 | public void setAvatar(String avatar) { 30 | this.avatar = avatar; 31 | } 32 | 33 | public String getDescription() { 34 | return description; 35 | } 36 | 37 | public void setDescription(String description) { 38 | this.description = description; 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /src/service/src/main/resources/mapper/userMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | id,avatar,user_name,sign 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/utils/BeanUtil.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.utils; 2 | 3 | import com.fyp.service.intf.LayIMService; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.support.ClassPathXmlApplicationContext; 6 | 7 | import java.util.List; 8 | 9 | public class BeanUtil { 10 | 11 | private static ApplicationContext context; 12 | 13 | private static ApplicationContext getApplicationContext(){ 14 | if (context == null){ 15 | context = new ClassPathXmlApplicationContext("applicationContext.xml"); 16 | } 17 | return context; 18 | } 19 | 20 | public static Object getBean(String beanName){ 21 | return getApplicationContext().getBean(beanName); 22 | } 23 | 24 | public static void main(String[] args) { 25 | LayIMService bean = (LayIMService) getBean("layIMService"); 26 | List groupids = bean.getGroupIds(203328L); 27 | System.out.println(groupids); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/FriendGroup.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity; 2 | 3 | import java.util.List; 4 | 5 | public class FriendGroup { 6 | 7 | public FriendGroup(){ 8 | setOnline(0); 9 | } 10 | 11 | public String getGroupname() { 12 | return groupname; 13 | } 14 | public void setGroupname(String name) { 15 | this.groupname = name; 16 | } 17 | public Long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(Long id) { 22 | this.id = id; 23 | } 24 | 25 | public List getList() { 26 | return list; 27 | } 28 | 29 | public void setList(List list) { 30 | this.list = list; 31 | } 32 | 33 | public Integer getOnline() { 34 | return online; 35 | } 36 | 37 | public void setOnline(Integer online) { 38 | this.online = online; 39 | } 40 | 41 | private Integer online; 42 | private List list; 43 | private String groupname; 44 | private Long id; 45 | } 46 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/handler/Processor.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.handler; 2 | 3 | import com.fyp.im.MsgType; 4 | import com.fyp.im.processor.AbstractMsgProcessor; 5 | import com.fyp.im.processor.ClientToClientProcessor; 6 | import com.fyp.im.processor.ClientToGroupProcessor; 7 | import com.fyp.im.processor.PingProcessor; 8 | import org.tio.core.ChannelContext; 9 | 10 | public class Processor { 11 | /** 12 | * 消息处理入口 13 | */ 14 | public static Object process(ChannelContext channelContext, byte[] body) { 15 | getProcessor(body[4]).process(channelContext, body); 16 | return null; 17 | } 18 | 19 | private static AbstractMsgProcessor getProcessor(byte msgType) { 20 | MsgType type = MsgType.valueOf(msgType); 21 | switch (type) { 22 | case clientToClient: 23 | return new ClientToClientProcessor(); 24 | case clientToGroup: 25 | return new ClientToGroupProcessor(); 26 | case ping: 27 | return new PingProcessor(); 28 | } 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity; 2 | 3 | public class User { 4 | public static final User Anonymous = new User("匿名",""); 5 | 6 | public User(){ 7 | 8 | } 9 | public User(String name,String avatar){ 10 | setUsername(name); 11 | setAvatar(avatar); 12 | } 13 | 14 | public String getAvatar() { 15 | return avatar; 16 | } 17 | 18 | public void setAvatar(String avatar) { 19 | this.avatar = avatar; 20 | } 21 | 22 | public String getUsername() { 23 | return username; 24 | } 25 | 26 | public void setUsername(String username) { 27 | this.username = username; 28 | } 29 | 30 | public String getSign() { 31 | return sign; 32 | } 33 | 34 | public void setSign(String sign) { 35 | this.sign = sign; 36 | } 37 | 38 | public Long getId() { 39 | return id; 40 | } 41 | 42 | public void setId(Long id) { 43 | this.id = id; 44 | } 45 | 46 | private Long id; 47 | private String avatar; 48 | private String username; 49 | private String sign; 50 | } 51 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/js/mods/req.js: -------------------------------------------------------------------------------- 1 | layui.define(['jquery','layer'],function (exports) { 2 | var $ = layui.jquery; 3 | var layer = layui.layer; 4 | 5 | var req = { 6 | loading:true, 7 | get:function (url,data,success,error) { 8 | ajax('GET',url,data,success,error) 9 | }, 10 | post:function (url,data,success,error) { 11 | ajax('POST',url,data,success,error) 12 | }, 13 | }; 14 | var ajax =function(type,url,data,success,error) { 15 | var loading; 16 | $.ajax({ 17 | url:url, 18 | type:type||'get', 19 | data:data||{}, 20 | beforeSend:function () { 21 | if(req.loading) { 22 | loading = layer.open({type: 3}); 23 | } 24 | }, 25 | success:function (d) { 26 | success &&success(d); 27 | loading &&layer.close(loading); 28 | }, 29 | error:function (d) { 30 | error&&error(d); 31 | loading&&layer.close(loading); 32 | } 33 | }); 34 | } 35 | 36 | exports("req",req); 37 | }) -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/im/Message.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity.im; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Message implements Serializable { 6 | private long id; 7 | private String username; 8 | private String content; 9 | private String avatar; 10 | 11 | public long getId() { 12 | return id; 13 | } 14 | 15 | public void setId(long id) { 16 | this.id = id; 17 | } 18 | 19 | public String getUsername() { 20 | return username; 21 | } 22 | 23 | public void setUsername(String username) { 24 | this.username = username; 25 | } 26 | 27 | public String getContent() { 28 | return content; 29 | } 30 | 31 | public void setContent(String content) { 32 | this.content = content; 33 | } 34 | 35 | public String getAvatar() { 36 | return avatar; 37 | } 38 | 39 | public void setAvatar(String avatar) { 40 | this.avatar = avatar; 41 | } 42 | 43 | public String getType() { 44 | return type; 45 | } 46 | 47 | public void setType(String type) { 48 | this.type = type; 49 | } 50 | 51 | private String type; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/utils/DruidDataSourceFactory.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.utils; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import org.apache.ibatis.datasource.DataSourceFactory; 5 | 6 | import javax.sql.DataSource; 7 | import java.sql.SQLException; 8 | import java.util.Properties; 9 | 10 | public class DruidDataSourceFactory implements DataSourceFactory { 11 | 12 | private Properties props; 13 | 14 | public void setProperties(Properties properties) { 15 | this.props = properties; 16 | } 17 | 18 | private String getProperty(String name){ 19 | return this.props.getProperty(name); 20 | } 21 | 22 | public DataSource getDataSource() { 23 | DruidDataSource dataSource = new DruidDataSource(); 24 | 25 | dataSource.setDriverClassName(getProperty("driver")); 26 | dataSource.setUrl(getProperty("url")); 27 | dataSource.setUsername(getProperty("username")); 28 | dataSource.setPassword(getProperty("password")); 29 | 30 | try { 31 | dataSource.init(); 32 | }catch (SQLException ex){ 33 | ex.printStackTrace(); 34 | } 35 | return dataSource; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/im/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | layim 7 | com.fyp 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | im 13 | 14 | 15 | 16 | com.fyp 17 | utils 18 | 1.0-SNAPSHOT 19 | 20 | 21 | org.t-io 22 | tio-websocket-server 23 | 3.2.4.v20181218-RELEASE 24 | 25 | 26 | com.fyp 27 | service 28 | 1.0-SNAPSHOT 29 | compile 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/utils/MyBatisUtil.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.utils; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.apache.ibatis.session.SqlSession; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 | 8 | 9 | import java.io.InputStream; 10 | 11 | public class MyBatisUtil { 12 | private static final String configFile = "mybatis-config.xml"; 13 | 14 | private static SqlSessionFactory sqlSessionFactory = null; 15 | 16 | private static SqlSessionFactory createSqlSessionFactory(){ 17 | try{ 18 | if(sqlSessionFactory == null) { 19 | InputStream inputStream = Resources.getResourceAsStream(configFile); 20 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 21 | } 22 | return sqlSessionFactory; 23 | } 24 | catch (Exception e){ 25 | e.printStackTrace(); 26 | } 27 | return null; 28 | } 29 | 30 | public static SqlSession getSession() { 31 | SqlSessionFactory factory = createSqlSessionFactory(); 32 | return factory.openSession(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/service/src/main/resources/mapper/bigGroupMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 18 | 21 | 24 | 25 | -------------------------------------------------------------------------------- /src/utils/utils.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/web/src/main/java/com/fyp/web/controllers/LayIMController.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web.controllers; 2 | 3 | import com.fyp.entity.result.JsonResult; 4 | 5 | import com.fyp.service.intf.LayIMService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | 14 | @RestController 15 | @RequestMapping("/layim") 16 | public class LayIMController extends BaseController{ 17 | 18 | @Autowired 19 | private LayIMService layIMService; 20 | 21 | /** 22 | * LayIM初始化 23 | * */ 24 | @GetMapping("init") 25 | public JsonResult getInitData(HttpServletRequest request){ 26 | return layIMService.getInitResult(getUserId(request)); 27 | } 28 | 29 | /** 30 | * 获取群员列表 31 | * */ 32 | @GetMapping("member") 33 | public JsonResult getGroupMembers(Long id){ 34 | return layIMService.getMembersByGroupId(id); 35 | } 36 | 37 | /** 38 | * 获取消息记录 39 | * */ 40 | @GetMapping("chat/history") 41 | public JsonResult getChatHistory(HttpServletRequest request,Long id,String type,Long lastId){ 42 | return layIMService.getChatRecords(getUserId(request) ,id,type,lastId); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/service/src/main/resources/mapper/msgRecordMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | INSERT INTO msg_record (id,from_id,to_id,room_id,contents,create_at,mtype) values (#{id},#{from},#{to},#{room},#{contents},#{createAt},#{msgType}) 19 | 20 | 21 | 29 | -------------------------------------------------------------------------------- /src/web/src/main/java/com/fyp/web/controllers/AccountController.java: -------------------------------------------------------------------------------- 1 | package com.fyp.web.controllers; 2 | 3 | import com.fyp.entity.result.JsonResult; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import javax.servlet.http.Cookie; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | @RestController 14 | @RequestMapping("/account") 15 | public class AccountController extends BaseController{ 16 | 17 | /** 18 | * 登录获取Token 19 | * */ 20 | @GetMapping("token") 21 | public JsonResult getToken(HttpServletRequest request) { 22 | Long userId = getUserId(request); 23 | if (userId > 0) { 24 | return JsonResult.success(com.fyp.utils.jwt.JwtUtil.createToken(userId)); 25 | } 26 | return JsonResult.fail("no login"); 27 | } 28 | 29 | /** 30 | * 模拟用户登录,写入cookie 31 | * */ 32 | @GetMapping("login") 33 | public JsonResult login(String userId, HttpServletResponse response) throws IOException { 34 | Cookie cookie = new Cookie("layim_uid", userId); 35 | cookie.setMaxAge(7200); 36 | cookie.setPath("/"); 37 | response.addCookie(cookie); 38 | response.sendRedirect("/"); 39 | return JsonResult.success(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/MsgRecord.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity; 2 | 3 | public class MsgRecord { 4 | private long id; 5 | private long from; 6 | private long to; 7 | private long room; 8 | 9 | public long getId() { 10 | return id; 11 | } 12 | 13 | public void setId(long id) { 14 | this.id = id; 15 | } 16 | 17 | public long getFrom() { 18 | return from; 19 | } 20 | 21 | public void setFrom(long from) { 22 | this.from = from; 23 | } 24 | 25 | public long getTo() { 26 | return to; 27 | } 28 | 29 | public void setTo(long to) { 30 | this.to = to; 31 | } 32 | 33 | public long getRoom() { 34 | return room; 35 | } 36 | 37 | public void setRoom(long room) { 38 | this.room = room; 39 | } 40 | 41 | public String getContents() { 42 | return contents; 43 | } 44 | 45 | public void setContents(String contents) { 46 | this.contents = contents; 47 | } 48 | 49 | public int getMsgType() { 50 | return msgType; 51 | } 52 | 53 | public void setMsgType(byte msgType) { 54 | this.msgType = msgType; 55 | } 56 | 57 | public long getCreateAt() { 58 | return createAt; 59 | } 60 | 61 | public void setCreateAt(long createAt) { 62 | this.createAt = createAt; 63 | } 64 | 65 | private String contents; 66 | private byte msgType; 67 | private long createAt; 68 | } 69 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/common/header.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 12 | 13 | 35 |
36 |
37 | -------------------------------------------------------------------------------- /src/service/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/result/ChatRecordResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity.result; 2 | 3 | public class ChatRecordResult implements Comparable{ 4 | private long id; 5 | 6 | public boolean isSelf() { 7 | return self; 8 | } 9 | 10 | public void setSelf(boolean self) { 11 | this.self = self; 12 | } 13 | 14 | private boolean self; 15 | 16 | public long getId() { 17 | return id; 18 | } 19 | 20 | public void setId(long id) { 21 | this.id = id; 22 | } 23 | 24 | public String getAvatar() { 25 | return avatar; 26 | } 27 | 28 | public void setAvatar(String avatar) { 29 | this.avatar = avatar; 30 | } 31 | 32 | public long getTimestamp() { 33 | return timestamp; 34 | } 35 | 36 | public void setTimestamp(long timestamp) { 37 | this.timestamp = timestamp; 38 | } 39 | 40 | public String getContent() { 41 | return content; 42 | } 43 | 44 | public void setContent(String content) { 45 | this.content = content; 46 | } 47 | 48 | public String getUsername() { 49 | return username; 50 | } 51 | 52 | public void setUsername(String username) { 53 | this.username = username; 54 | } 55 | 56 | private String username; 57 | private String avatar; 58 | private long timestamp; 59 | private String content; 60 | 61 | @Override 62 | public int compareTo(ChatRecordResult o) { 63 | if (o.id == this.id) { 64 | return 0; 65 | } 66 | return o.id > this.id ? -1 : 1; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | layim 7 | com.fyp 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | service 13 | 14 | 15 | com.fyp 16 | entity 17 | 1.0-SNAPSHOT 18 | 19 | 20 | com.fyp 21 | utils 22 | 1.0-SNAPSHOT 23 | 24 | 25 | org.mybatis 26 | mybatis 27 | 3.4.6 28 | 29 | 30 | mysql 31 | mysql-connector-java 32 | 8.0.16 33 | 34 | 35 | com.alibaba 36 | druid 37 | 1.1.12 38 | 39 | 40 | org.springframework 41 | spring-context 42 | 5.1.3.RELEASE 43 | compile 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/listener/MyMsgListener.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.listener; 2 | 3 | 4 | import org.tio.core.ChannelContext; 5 | import org.tio.core.intf.Packet; 6 | import org.tio.websocket.server.WsServerAioListener; 7 | 8 | /** 9 | * 这里碰到了一个坑,应该extends WsServerAioListener,结果我 implements ServerAioListener 导致 WebSocket连接失败,浪费了我一上午的时间。 10 | * 2018-12-25 11:44 11 | * */ 12 | public class MyMsgListener extends WsServerAioListener { 13 | 14 | @Override 15 | public void onAfterConnected(ChannelContext channelContext, boolean isConnected, boolean isReconnect) throws Exception { 16 | super.onAfterConnected(channelContext, isConnected, isReconnect); 17 | } 18 | 19 | @Override 20 | public void onAfterDecoded(ChannelContext channelContext, Packet packet, int packetSize) throws Exception { 21 | super.onAfterDecoded(channelContext, packet, packetSize); 22 | } 23 | 24 | @Override 25 | public void onAfterHandled(ChannelContext channelContext, Packet packet, long cost) throws Exception { 26 | super.onAfterHandled(channelContext, packet, cost); 27 | } 28 | 29 | @Override 30 | public void onAfterReceivedBytes(ChannelContext channelContext, int receivedBytes) throws Exception { 31 | super.onAfterReceivedBytes(channelContext, receivedBytes); 32 | } 33 | 34 | @Override 35 | public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess) throws Exception { 36 | super.onAfterSent(channelContext, packet, isSentSuccess); 37 | } 38 | 39 | @Override 40 | public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) throws Exception { 41 | super.onBeforeClose(channelContext, throwable, remark, isRemove); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/entity/src/main/java/com/fyp/entity/result/JsonResult.java: -------------------------------------------------------------------------------- 1 | package com.fyp.entity.result; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | public class JsonResult { 6 | 7 | private static final int SUCCESS_COCE = 0; 8 | private static final int FAIL_COCE = 1; 9 | 10 | public JsonResult(){ 11 | 12 | } 13 | 14 | private JsonResult(String msg){ 15 | this(FAIL_COCE,msg,null); 16 | } 17 | 18 | private JsonResult(Object data){ 19 | this(SUCCESS_COCE,"",data); 20 | } 21 | 22 | private JsonResult(Integer code, String msg, Object data){ 23 | this.data = data; 24 | this.code = code; 25 | this.msg = msg; 26 | } 27 | 28 | private Integer code; 29 | private String msg; 30 | private Object data; 31 | 32 | public Integer getCode() { 33 | return code; 34 | } 35 | public String getMsg() { 36 | return msg; 37 | } 38 | public Object getData() { 39 | return data; 40 | } 41 | 42 | @JsonIgnore 43 | public boolean isSuccess(){ 44 | return code == SUCCESS_COCE; 45 | } 46 | 47 | @JsonIgnore 48 | public boolean isFail(){ 49 | return !isSuccess(); 50 | } 51 | /** 52 | * 成功结果,有返回值 53 | * */ 54 | public static JsonResult success(Object data){ 55 | return new JsonResult(data); 56 | } 57 | /** 58 | * 成功结果无返回值 59 | * */ 60 | public static JsonResult success(){ 61 | return success(null); 62 | } 63 | /** 64 | * 失败结果 65 | * */ 66 | public static JsonResult fail(String msg){ 67 | return new JsonResult(msg); 68 | } 69 | /** 70 | * 失败结果 71 | * */ 72 | public static JsonResult fail(String msg,Object data){ 73 | return new JsonResult(FAIL_COCE,msg, data); 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /src/web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.1.RELEASE 9 | 10 | 11 | com.fyp 12 | web 13 | 0.0.1-SNAPSHOT 14 | web 15 | 16 | 17 | 18 | com.fyp 19 | utils 20 | 1.0-SNAPSHOT 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-thymeleaf 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | 38 | com.fyp 39 | service 40 | 1.0-SNAPSHOT 41 | 42 | 43 | com.fyp 44 | im 45 | 1.0-SNAPSHOT 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/TioApplication.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im; 2 | 3 | import com.fyp.im.handler.MyMsgHandler; 4 | import com.fyp.im.listener.MyMsgListener; 5 | import com.fyp.im.listener.MyGroupListener; 6 | import com.fyp.im.listener.MyIpStatListener; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | import org.tio.server.ServerGroupContext; 12 | import org.tio.websocket.server.WsServerConfig; 13 | import org.tio.websocket.server.WsServerStarter; 14 | import org.tio.websocket.server.handler.IWsMsgHandler; 15 | 16 | @Component 17 | public class TioApplication { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(TioApplication.class); 20 | 21 | private WsServerStarter wsServerStarter; 22 | private ServerGroupContext serverGroupContext; 23 | 24 | public TioApplication() throws Exception { 25 | initServerStarter("127.0.0.1",8889); 26 | initGroupContext(); 27 | } 28 | 29 | private void initServerStarter(String ip,int port) throws Exception{ 30 | WsServerConfig config = new WsServerConfig(port); 31 | config.setBindIp(ip); 32 | wsServerStarter = new WsServerStarter(config, new MyMsgHandler()); 33 | } 34 | 35 | private void initGroupContext(){ 36 | serverGroupContext = wsServerStarter.getServerGroupContext(); 37 | 38 | serverGroupContext.setName("Tio for LayIM"); 39 | serverGroupContext.setIpStatListener(new MyIpStatListener()); 40 | serverGroupContext.setGroupListener(new MyGroupListener()); 41 | serverGroupContext.setServerAioListener(new MyMsgListener()); 42 | serverGroupContext.setHeartbeatTimeout(0); 43 | } 44 | 45 | 46 | public void run() throws Exception { 47 | wsServerStarter.start(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/js/mods/chatlog.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var _type, _id,_his; 3 | var param = { 4 | init: function (type, id, his) { 5 | _type = type; 6 | _id = id; 7 | _his = his; 8 | helper.loadMsg(); 9 | $('#chatLogMore').on('click', function () { 10 | helper.loadMsg(); 11 | }); 12 | } 13 | }; 14 | 15 | var record = true; 16 | var helper = { 17 | loadMsg: function () { 18 | if (!record) { return; } 19 | var $li = $('#LAY_view').find('li').first(); 20 | var t = 0; 21 | if ($li.length > 0) { 22 | t = $li.data('timestamp'); 23 | } 24 | $('#chatLogMore').find('span').text('正在加载...'); 25 | $.get(_his, {type: _type, id: _id, stamp: t, page: 20 }, function (res) { 26 | if (res && res.trim() != '') { 27 | if ($li.length) { 28 | $(res).insertBefore($li); 29 | } else { 30 | $(res).insertAfter('#chatLogMore'); 31 | } 32 | //转换 content 33 | $('#LAY_view li[trans="0"]').each(function () { 34 | var o = $(this).find('.layim-chat-text'), ot = o.text().trim(), n = parent.layui.layim.content(ot); 35 | o.html(n); 36 | $(this).attr('trans', "1"); 37 | }); 38 | $('#chatLogMore').find('span').text('查看更多记录'); 39 | if (t == 0) { 40 | $(document).scrollTop($(document).height()); 41 | } 42 | } else { 43 | $('#chatLogMore').find('span').text('无更多记录了'); 44 | record = false; 45 | } 46 | }); 47 | } 48 | } 49 | window.chatLogParam = param; 50 | })(); 51 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/processor/AbstractMsgProcessor.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.processor; 2 | 3 | import com.fyp.utils.convert.ConvertUtil; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.tio.core.ChannelContext; 7 | 8 | import java.util.Arrays; 9 | 10 | public abstract class AbstractMsgProcessor { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger(AbstractMsgProcessor.class); 13 | private byte[] body; 14 | private static final int PREFIX_LENGTH = 5; 15 | private static final int BODY_LENGTH_LENGTH = 4; 16 | private static final int PLACEHOLDER_LENGTH = 9; 17 | private byte[] realBody; 18 | private int targetId; 19 | 20 | public AbstractMsgProcessor() { 21 | 22 | } 23 | 24 | private void setBody(byte[] body) { 25 | if (body == null || body.length < 9) { 26 | throw new IllegalArgumentException("illegal msg body"); 27 | } 28 | this.body = body; 29 | } 30 | 31 | /** 32 | * 消息处理入口 33 | * */ 34 | public final void process(ChannelContext channelContext, byte[] body) { 35 | setBody(body); 36 | processInternal(channelContext); 37 | } 38 | 39 | protected abstract void processInternal(ChannelContext channelContext); 40 | 41 | /** 42 | * 获取接收人的ID 43 | */ 44 | protected final int getTargetId() { 45 | if (targetId == 0) { 46 | byte[] targetIdBytes = Arrays.copyOf(body, BODY_LENGTH_LENGTH); 47 | targetId = ConvertUtil.byteArrayToInt(targetIdBytes); 48 | } 49 | return targetId; 50 | } 51 | 52 | protected final int getBodyLength() { 53 | byte[] bodyLengthBytes = Arrays.copyOfRange(body, PREFIX_LENGTH, PLACEHOLDER_LENGTH); 54 | return ConvertUtil.byteArrayToInt(bodyLengthBytes); 55 | } 56 | 57 | protected final byte getMsgType(){ 58 | return body[4]; 59 | } 60 | 61 | protected final byte[] getBody() { 62 | if (realBody == null) { 63 | int length = getBodyLength(); 64 | int totalLength = PLACEHOLDER_LENGTH + length; 65 | if (body.length != totalLength) { 66 | throw new IllegalArgumentException("illegal body length"); 67 | } 68 | realBody = Arrays.copyOfRange(body, PLACEHOLDER_LENGTH, totalLength); 69 | } 70 | return realBody; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/processor/MsgStoredProcessor.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.processor; 2 | 3 | import com.fyp.entity.MsgRecord; 4 | import com.fyp.entity.User; 5 | import com.fyp.entity.im.Message; 6 | import com.fyp.entity.LayIMConstants; 7 | import com.fyp.im.utils.BeanUtil; 8 | import com.fyp.im.utils.SafeEncoder; 9 | import com.fyp.service.intf.LayIMService; 10 | import org.tio.core.ChannelContext; 11 | import org.tio.utils.json.Json; 12 | 13 | import java.util.concurrent.Executors; 14 | 15 | public abstract class MsgStoredProcessor extends AbstractMsgProcessor{ 16 | 17 | private void recordMsgAsync(ChannelContext channelContext){ 18 | Executors.newCachedThreadPool().execute(() -> recordMsg(channelContext)); 19 | } 20 | 21 | protected final byte[] buildSendMessage(ChannelContext channelContext) { 22 | Message message = new Message(); 23 | 24 | User user = (User) channelContext.getAttribute(LayIMConstants.CURRENT_USER_ATTRIBUTE); 25 | if(null == user){ 26 | throw new NullPointerException("current user is null"); 27 | } 28 | message.setUsername(user.getUsername()); 29 | message.setAvatar(user.getAvatar()); 30 | message.setContent(SafeEncoder.encode(getBody())); 31 | message.setType(getType(channelContext)); 32 | message.setId(getId(channelContext)); 33 | return SafeEncoder.encode(Json.toJson(message)); 34 | } 35 | 36 | protected abstract long getId(ChannelContext channelContext); 37 | protected abstract String getType(ChannelContext channelContext); 38 | 39 | private void recordMsg(ChannelContext channelContext) { 40 | LayIMService service = ((LayIMService) BeanUtil.getBean("layIMService")); 41 | MsgRecord record = new MsgRecord(); 42 | record.setTo(getTargetId()); 43 | record.setFrom(Long.valueOf(channelContext.userid)); 44 | record.setContents(SafeEncoder.encode(getBody())); 45 | record.setCreateAt(System.currentTimeMillis()); 46 | record.setId(System.currentTimeMillis()); 47 | record.setMsgType(getMsgType()); 48 | service.addRecord(record); 49 | } 50 | 51 | protected abstract void processMessage(ChannelContext channelContext); 52 | 53 | protected void processInternal(ChannelContext channelContext) { 54 | recordMsgAsync(channelContext); 55 | processMessage(channelContext); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.fyp 8 | layim 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | entity 13 | im 14 | service 15 | web 16 | utils 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 3.8.0 24 | 25 | 1.8 26 | 1.8 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-jar-plugin 32 | 33 | 34 | 35 | true 36 | lib/ 37 | com.fyp.web.WebApplication 38 | 39 | 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-dependency-plugin 45 | 46 | 47 | copy 48 | install 49 | 50 | copy-dependencies 51 | 52 | 53 | ${project.build.directory}/lib 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/json/getMembers.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0 3 | ,"msg": "" 4 | ,"data": { 5 | "owner": { 6 | "username": "贤心" 7 | ,"id": "100001" 8 | ,"avatar": "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" 9 | ,"sign": "这些都是测试数据,实际使用请严格按照该格式返回" 10 | } 11 | ,"members": 12 12 | ,"list": [{ 13 | "username": "贤心" 14 | ,"id": "100001" 15 | ,"avatar": "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" 16 | ,"sign": "这些都是测试数据,实际使用请严格按照该格式返回" 17 | },{ 18 | "username": "Z_子晴" 19 | ,"id": "108101" 20 | ,"avatar": "http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg" 21 | ,"sign": "微电商达人" 22 | },{ 23 | "username": "Lemon_CC" 24 | ,"id": "102101" 25 | ,"avatar": "http://tp2.sinaimg.cn/1833062053/180/5643591594/0" 26 | ,"sign": "" 27 | },{ 28 | "username": "马小云" 29 | ,"id": "168168" 30 | ,"avatar": "http://tp4.sinaimg.cn/2145291155/180/5601307179/1" 31 | ,"sign": "让天下没有难写的代码" 32 | },{ 33 | "username": "徐小峥" 34 | ,"id": "666666" 35 | ,"avatar": "http://tp2.sinaimg.cn/1783286485/180/5677568891/1" 36 | ,"sign": "代码在囧途,也要写到底" 37 | },{ 38 | "username": "罗玉凤" 39 | ,"id": "121286" 40 | ,"avatar": "http://tp1.sinaimg.cn/1241679004/180/5743814375/0" 41 | ,"sign": "在自己实力不济的时候,不要去相信什么媒体和记者。他们不是善良的人,有时候候他们的采访对当事人而言就是陷阱" 42 | },{ 43 | "username": "长泽梓Azusa" 44 | ,"id": "100001222" 45 | ,"avatar": "http://tva1.sinaimg.cn/crop.0.0.180.180.180/86b15b6cjw1e8qgp5bmzyj2050050aa8.jpg" 46 | ,"sign": "我是日本女艺人长泽あずさ" 47 | },{ 48 | "username": "大鱼_MsYuyu" 49 | ,"id": "12123454" 50 | ,"avatar": "http://tp1.sinaimg.cn/5286730964/50/5745125631/0" 51 | ,"sign": "我瘋了!這也太準了吧 超級笑點低" 52 | },{ 53 | "username": "谢楠" 54 | ,"id": "10034001" 55 | ,"avatar": "http://tp4.sinaimg.cn/1665074831/180/5617130952/0" 56 | ,"sign": "" 57 | },{ 58 | "username": "柏雪近在它香" 59 | ,"id": "3435343" 60 | ,"avatar": "http://tp2.sinaimg.cn/2518326245/180/5636099025/0" 61 | ,"sign": "" 62 | },{ 63 | "username": "林心如" 64 | ,"id": "76543" 65 | ,"avatar": "http://tp3.sinaimg.cn/1223762662/180/5741707953/0" 66 | ,"sign": "我爱贤心" 67 | },{ 68 | "username": "佟丽娅" 69 | ,"id": "4803920" 70 | ,"avatar": "http://tp4.sinaimg.cn/1345566427/180/5730976522/0" 71 | ,"sign": "我也爱贤心吖吖啊" 72 | }] 73 | } 74 | } -------------------------------------------------------------------------------- /src/service/service.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/utils/src/main/java/com/fyp/utils/jwt/JwtUtil.java: -------------------------------------------------------------------------------- 1 | package com.fyp.utils.jwt; 2 | 3 | import com.auth0.jwt.JWT; 4 | import com.auth0.jwt.JWTVerifier; 5 | import com.auth0.jwt.algorithms.Algorithm; 6 | import com.auth0.jwt.exceptions.JWTCreationException; 7 | import com.auth0.jwt.exceptions.JWTVerificationException; 8 | import com.auth0.jwt.interfaces.Claim; 9 | import com.auth0.jwt.interfaces.DecodedJWT; 10 | 11 | import java.util.*; 12 | 13 | public class JwtUtil { 14 | 15 | private static final String SECRET = "3734b137-1b5f-4434-8ce8-b68ed1ec1aaf"; 16 | 17 | /** 18 | * 创建一个TOKEN 19 | * */ 20 | public static JwtTokenResult createToken(Long userId){ 21 | try { 22 | Algorithm algorithm = Algorithm.HMAC256(SECRET); 23 | Map map = new HashMap(); 24 | 25 | Date nowDate = new Date(); 26 | Calendar cal = new GregorianCalendar(); 27 | cal.setTime(nowDate); 28 | cal.add(Calendar.HOUR_OF_DAY, 2); 29 | Date expireDate = cal.getTime(); 30 | 31 | map.put("alg", "HS256"); 32 | map.put("typ", "JWT"); 33 | 34 | String token = JWT.create() 35 | .withHeader(map) 36 | .withClaim("uid", userId) 37 | .withIssuer("LayIMServer") 38 | .withSubject("LayIM_AccessToken") 39 | .withAudience("Web") 40 | .withIssuedAt(nowDate) 41 | .withExpiresAt(expireDate) 42 | .sign(algorithm); 43 | return new JwtTokenResult(token); 44 | 45 | } catch (JWTCreationException exception){ 46 | exception.printStackTrace(); 47 | } 48 | return new JwtTokenResult(null); 49 | } 50 | 51 | /** 52 | * 解析Token 53 | * */ 54 | public static JwtVertifyResult verifyToken(String token) { 55 | try { 56 | Algorithm algorithm = Algorithm.HMAC256(SECRET); 57 | JWTVerifier verifier = JWT.require(algorithm) 58 | .withIssuer("LayIMServer") 59 | .build(); 60 | DecodedJWT jwt = verifier.verify(token); 61 | Map claims = jwt.getClaims(); 62 | Claim claim = claims.get("uid"); 63 | if (claim != null) { 64 | return new JwtVertifyResult(claim.asLong()); 65 | } 66 | } catch (JWTVerificationException exception) { 67 | return JwtVertifyResult.result(exception.getMessage()); 68 | } 69 | return JwtVertifyResult.NotVertified; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/listener/MyIpStatListener.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.listener; 2 | 3 | import org.tio.core.ChannelContext; 4 | import org.tio.core.GroupContext; 5 | import org.tio.core.intf.Packet; 6 | import org.tio.core.stat.IpStat; 7 | import org.tio.core.stat.IpStatListener; 8 | 9 | public class MyIpStatListener implements IpStatListener { 10 | /** 11 | * 统计时间段到期后,用户可以在这个方法中实现把相关数据入库或是打日志等 12 | * 13 | * @param groupContext 14 | * @param ipStat 15 | */ 16 | public void onExpired(GroupContext groupContext, IpStat ipStat) { 17 | 18 | } 19 | 20 | /** 21 | * 建链后触发本方法,注:建链不一定成功,需要关注参数isConnected 22 | * 23 | * @param channelContext 24 | * @param isConnected 是否连接成功,true:表示连接成功,false:表示连接失败 25 | * @param isReconnect 是否是重连, true: 表示这是重新连接,false: 表示这是第一次连接 26 | * @param ipStat 27 | * @throws Exception 28 | * @author: tanyaowu 29 | */ 30 | public void onAfterConnected(ChannelContext channelContext, boolean isConnected, boolean isReconnect, IpStat ipStat) throws Exception { 31 | 32 | } 33 | 34 | /** 35 | * 解码异常时 36 | * 37 | * @param channelContext 38 | * @param ipStat 39 | */ 40 | public void onDecodeError(ChannelContext channelContext, IpStat ipStat) { 41 | 42 | } 43 | 44 | /** 45 | * 发送后(注:不一定会发送成功) 46 | * 47 | * @param channelContext 48 | * @param packet 49 | * @param isSentSuccess 50 | * @param ipStat 51 | * @throws Exception 52 | */ 53 | public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess, IpStat ipStat) throws Exception { 54 | 55 | } 56 | 57 | /** 58 | * 解码成功后 59 | * 60 | * @param channelContext 61 | * @param packet 62 | * @param packetSize 63 | * @param ipStat 64 | * @throws Exception 65 | */ 66 | public void onAfterDecoded(ChannelContext channelContext, Packet packet, int packetSize, IpStat ipStat) throws Exception { 67 | 68 | } 69 | 70 | /** 71 | * 接收到一些字节数据后 72 | * 73 | * @param channelContext 74 | * @param receivedBytes 75 | * @param ipStat 76 | * @throws Exception 77 | */ 78 | public void onAfterReceivedBytes(ChannelContext channelContext, int receivedBytes, IpStat ipStat) throws Exception { 79 | 80 | } 81 | 82 | /** 83 | * 处理一个消息包后 84 | * 85 | * @param channelContext 86 | * @param packet 87 | * @param ipStat 88 | * @param cost 耗时,单位:毫秒 89 | * @throws Exception 90 | */ 91 | public void onAfterHandled(ChannelContext channelContext, Packet packet, IpStat ipStat, long cost) throws Exception { 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/im/src/main/java/com/fyp/im/handler/MyMsgHandler.java: -------------------------------------------------------------------------------- 1 | package com.fyp.im.handler; 2 | 3 | import com.fyp.entity.User; 4 | import com.fyp.entity.LayIMConstants; 5 | import com.fyp.im.utils.BeanUtil; 6 | import com.fyp.service.intf.LayIMService; 7 | import com.fyp.utils.jwt.JwtUtil; 8 | import com.fyp.utils.jwt.JwtVertifyResult; 9 | import org.tio.core.ChannelContext; 10 | import org.tio.core.Tio; 11 | import org.tio.http.common.HttpRequest; 12 | import org.tio.http.common.HttpResponse; 13 | import org.tio.http.common.HttpResponseStatus; 14 | import org.tio.websocket.common.WsRequest; 15 | import org.tio.websocket.server.handler.IWsMsgHandler; 16 | 17 | import java.util.List; 18 | 19 | 20 | /** 21 | * WebSocket 核心消息处理 22 | * */ 23 | public class MyMsgHandler implements IWsMsgHandler { 24 | /** 25 | * 握手 26 | * */ 27 | public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception { 28 | String token = httpRequest.getParam("access_token"); 29 | JwtVertifyResult result = JwtUtil.verifyToken(token); 30 | if (result.isVertified()) { 31 | bindUser(channelContext, result.getUserId()); 32 | } else { 33 | httpResponse.setStatus(HttpResponseStatus.C401); 34 | } 35 | return httpResponse; 36 | } 37 | 38 | private LayIMService getLayIMService(){ 39 | return (LayIMService) BeanUtil.getBean(LayIMConstants.LAYIM_SERVICE); 40 | } 41 | 42 | private void bindUser(ChannelContext channelContext, Long userId) { 43 | //绑定用户 44 | Tio.bindUser(channelContext, userId.toString()); 45 | //绑定User属性信息 46 | User user = getLayIMService().getByUserId(userId); 47 | channelContext.setAttribute(LayIMConstants.CURRENT_USER_ATTRIBUTE, user); 48 | //绑定群组 49 | List groupIds = getLayIMService().getGroupIds(userId); 50 | for (Long id : groupIds) { 51 | Tio.bindGroup(channelContext, id.toString()); 52 | } 53 | } 54 | 55 | /** 56 | * 握手完毕 57 | * */ 58 | public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception { 59 | } 60 | 61 | /** 62 | * 字节传输 63 | * */ 64 | public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception { 65 | return Processor.process(channelContext, bytes); 66 | } 67 | 68 | /** 69 | * 关闭 70 | * */ 71 | public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception { 72 | return null; 73 | } 74 | 75 | /** 76 | * 文本传输 77 | * */ 78 | public Object onText(WsRequest wsRequest, String s, ChannelContext channelContext) throws Exception { 79 | return null; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/tips.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 提示页面 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 49 |
50 |
51 | 52 |
53 |
54 |
55 |

56 |

这是一个基于 layui 的轻量级问答社区页面模版

57 |
58 |
59 |
60 | 61 | 69 | 70 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 404 - Fly社区 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 49 |
50 |
51 | 52 |
53 |
54 |
55 |

56 |

你瞧!页面或者数据被 纸飞机 运到火星了

57 |
58 |
59 |
60 | 61 | 62 | 63 | 71 | 72 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/web/src/main/resources/templates/chatlog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 聊天记录 8 | 9 | 12 | 13 | 14 |
15 |
    16 |
    查看更多记录
    17 |
18 |
19 | 28 | 29 | 30 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/json/getList.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0 3 | ,"msg": "" 4 | ,"data": { 5 | "mine": { 6 | "username": "纸飞机" 7 | ,"id": "100000" 8 | ,"status": "online" 9 | ,"sign": "在深邃的编码世界,做一枚轻盈的纸飞机" 10 | ,"avatar": "http://cdn.firstlinkapp.com/upload/2016_6/1465575923433_33812.jpg" 11 | } 12 | ,"friend": [{ 13 | "groupname": "前端码屌" 14 | ,"id": 1 15 | ,"online": 2 16 | ,"list": [{ 17 | "username": "贤心" 18 | ,"id": "100001" 19 | ,"avatar": "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" 20 | ,"sign": "这些都是测试数据,实际使用请严格按照该格式返回" 21 | },{ 22 | "username": "Z_子晴" 23 | ,"id": "108101" 24 | ,"avatar": "http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg" 25 | ,"sign": "微电商达人" 26 | },{ 27 | "username": "Lemon_CC" 28 | ,"id": "102101" 29 | ,"avatar": "http://tp2.sinaimg.cn/1833062053/180/5643591594/0" 30 | ,"sign": "" 31 | },{ 32 | "username": "马小云" 33 | ,"id": "168168" 34 | ,"avatar": "http://tp4.sinaimg.cn/2145291155/180/5601307179/1" 35 | ,"sign": "让天下没有难写的代码" 36 | ,"status": "offline" 37 | },{ 38 | "username": "徐小峥" 39 | ,"id": "666666" 40 | ,"avatar": "http://tp2.sinaimg.cn/1783286485/180/5677568891/1" 41 | ,"sign": "代码在囧途,也要写到底" 42 | }] 43 | },{ 44 | "groupname": "网红" 45 | ,"id": 2 46 | ,"online": 3 47 | ,"list": [{ 48 | "username": "罗玉凤" 49 | ,"id": "121286" 50 | ,"avatar": "http://tp1.sinaimg.cn/1241679004/180/5743814375/0" 51 | ,"sign": "在自己实力不济的时候,不要去相信什么媒体和记者。他们不是善良的人,有时候候他们的采访对当事人而言就是陷阱" 52 | },{ 53 | "username": "长泽梓Azusa" 54 | ,"id": "100001222" 55 | ,"sign": "我是日本女艺人长泽あずさ" 56 | ,"avatar": "http://tva1.sinaimg.cn/crop.0.0.180.180.180/86b15b6cjw1e8qgp5bmzyj2050050aa8.jpg" 57 | },{ 58 | "username": "大鱼_MsYuyu" 59 | ,"id": "12123454" 60 | ,"avatar": "http://tp1.sinaimg.cn/5286730964/50/5745125631/0" 61 | ,"sign": "我瘋了!這也太準了吧 超級笑點低" 62 | },{ 63 | "username": "谢楠" 64 | ,"id": "10034001" 65 | ,"avatar": "http://tp4.sinaimg.cn/1665074831/180/5617130952/0" 66 | ,"sign": "" 67 | },{ 68 | "username": "柏雪近在它香" 69 | ,"id": "3435343" 70 | ,"avatar": "http://tp2.sinaimg.cn/2518326245/180/5636099025/0" 71 | ,"sign": "" 72 | }] 73 | },{ 74 | "groupname": "我心中的女神" 75 | ,"id": 3 76 | ,"online": 1 77 | ,"list": [{ 78 | "username": "林心如" 79 | ,"id": "76543" 80 | ,"avatar": "http://tp3.sinaimg.cn/1223762662/180/5741707953/0" 81 | ,"sign": "我爱贤心" 82 | },{ 83 | "username": "佟丽娅" 84 | ,"id": "4803920" 85 | ,"avatar": "http://tp4.sinaimg.cn/1345566427/180/5730976522/0" 86 | ,"sign": "我也爱贤心吖吖啊" 87 | }] 88 | }] 89 | ,"group": [{ 90 | "groupname": "前端群" 91 | ,"id": "101" 92 | ,"avatar": "http://tp2.sinaimg.cn/2211874245/180/40050524279/0" 93 | },{ 94 | "groupname": "Fly社区官方群" 95 | ,"id": "102" 96 | ,"avatar": "http://tp2.sinaimg.cn/5488749285/50/5719808192/1" 97 | }] 98 | } 99 | } -------------------------------------------------------------------------------- /src/im/im.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/web/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SpringBoot and LayIM 7 | 10 | 11 | 12 | 13 | 14 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/message.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 我的消息 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 | 71 | 72 |
73 | 74 |
75 |
76 | 77 |
78 |
79 | 80 |
81 | 82 | 96 |
97 |
98 |
99 | 100 |
101 | 102 | 103 | 111 | 112 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/activate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 激活邮箱 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | 19 | 27 | 28 | 42 |
43 |
44 | 45 |
46 | 72 | 73 |
74 | 75 |
76 |
77 | 78 |
79 |
80 |
    81 |
  • 82 | 激活邮箱 83 |
  • 84 |
85 |
86 |
    87 |
  • 88 | 89 | xx@xx.com 90 | 91 | (尚未激活) 92 | 93 |
  • 94 |
  • 95 |
    96 | 1. 如果您未收到邮件,或激活链接失效,您可以 97 | 重新发送邮件,或者 98 | 更换邮箱; 99 |
    100 |
    101 | 2. 如果您始终没有收到 Fly 发送的邮件,请注意查看您邮箱中的垃圾邮件; 102 |
    103 |
    104 | 3. 如果你实在无法激活邮件,您还可以联系:admin@xx.com 105 |
    106 |
  • 107 |
108 |
109 |
110 |
111 | 112 |
113 | 114 | 122 | 123 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 登入 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 | 46 |
47 |
48 |
    49 |
  • 登入
  • 50 |
  • 注册
  • 51 |
52 |
53 |
54 |
55 |
56 |
57 | 58 |
59 | 60 |
61 |
62 |
63 | 64 |
65 | 66 |
67 |
68 |
69 | 70 |
71 | 72 |
73 |
74 | 1+1=? 75 |
76 |
77 |
78 | 79 | 80 | 忘记密码? 81 | 82 |
83 |
84 | 或者使用社交账号登入 85 | 86 | 87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | 95 |
96 | 97 | 105 | 106 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/jie/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 发表问题 编辑问题 公用 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 |
46 |

发表问题

47 | 48 | 49 | 50 |
51 |
52 |
53 | 54 |
55 | 56 |
57 |
58 |
59 |
60 | 61 |
62 | 63 |
64 |
65 |
66 | 67 |
68 | 74 |
75 |
76 |
77 | 78 |
79 | 85 |
86 |
87 |
88 |
89 | 90 |
91 | 92 |
93 |
94 | 1+1=? 95 |
96 |
97 |
98 | 99 |
100 |
101 |
102 |
103 |
104 | 105 | 106 | 114 | 115 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 用户中心 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 | 71 | 72 |
73 | 74 |
75 |
76 | 77 |
78 | 83 |
84 |
    85 |
  • 我发的帖(89
  • 86 |
  • 我收藏的帖(16
  • 87 |
88 |
89 |
90 | 110 |
111 |
112 |
113 | 118 |
119 |
120 |
121 |
122 |
123 |
124 | 125 | 133 | 134 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/reg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 注册 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 | 46 |
47 |
48 |
    49 |
  • 登入
  • 50 |
  • 注册
  • 51 |
52 |
53 |
54 |
55 |
56 |
57 | 58 |
59 | 60 |
61 |
将会成为您唯一的登入名
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 | 73 |
74 |
6到16个字符
75 |
76 |
77 | 78 |
79 | 80 |
81 |
82 |
83 | 84 |
85 | 86 |
87 |
88 | {{d.vercode}} 89 |
90 |
91 |
92 | 93 |
94 |
95 | 或者直接使用社交账号快捷注册 96 | 97 | 98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | 106 |
107 | 108 | 116 | 117 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 用户主页 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 | {{info.username}} 46 |

47 | 贤心 48 | 49 | 50 | 51 | 54 |

55 |

56 | 67206飞吻 57 | 2015-06-17 加入 58 | 来自杭州 59 |

60 |

(人生仿若一场修行)

61 |
62 | 63 |
64 |
65 |
66 |

贤心 最近的提问

67 | 105 | 106 |
107 |
108 | 109 |
110 |
111 |

贤心 最近的回答

112 |
    113 |
  • 114 |

    115 | 1分钟前 116 | 在tips能同时渲染多个吗?中回答: 117 |

    118 |
    119 | 尝试给layer.photos加上这个属性试试: 120 |
    121 | full: true         
    122 | 
    123 | 文档没有提及 124 |
    125 |
  • 126 |
  • 127 |

    128 | 5分钟前 129 | 在在Fly社区用的是什么系统啊?中回答: 130 |

    131 |
    132 | Fly社区采用的是NodeJS。分享出来的只是前端模版 133 |
    134 |
  • 135 |
136 | 137 |
138 |
139 | 140 |
141 | 142 | 150 | 151 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/forget.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 找回密码/重置密码 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |
    48 |
  • 找回密码
  • 49 |
50 |
51 |
52 |
53 |
54 |
55 | 56 |
57 | 58 |
59 |
60 |
61 | 62 |
63 | 64 |
65 |
66 | {{d.vercode}} 67 |
68 |
69 |
70 | 71 |
72 |
73 |
74 | 75 | 76 | 77 | 113 |
114 |
115 |
116 |
117 |
118 | 119 | 127 | 128 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /src/service/src/main/java/com/fyp/service/impl/DefaultLayIMService.java: -------------------------------------------------------------------------------- 1 | package com.fyp.service.impl; 2 | 3 | import com.fyp.entity.*; 4 | import com.fyp.entity.result.ChatRecordResult; 5 | import com.fyp.entity.result.GroupMemberResult; 6 | import com.fyp.entity.result.InitResult; 7 | import com.fyp.entity.result.JsonResult; 8 | import com.fyp.service.intf.LayIMService; 9 | import com.fyp.service.mapper.*; 10 | import com.fyp.service.utils.MyBatisUtil; 11 | import com.fyp.service.utils.Utils; 12 | import org.apache.ibatis.session.SqlSession; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.*; 16 | import java.util.stream.Collectors; 17 | 18 | import static com.fyp.entity.LayIMConstants.*; 19 | 20 | @Service 21 | public class DefaultLayIMService implements LayIMService { 22 | 23 | public User getByUserId(Long userId) { 24 | SqlSession session = MyBatisUtil.getSession(); 25 | try { 26 | UserMapper userMapper = session.getMapper(UserMapper.class); 27 | return userMapper.getUser(userId); 28 | } finally { 29 | session.close(); 30 | } 31 | } 32 | 33 | public JsonResult getInitResult(Long userId) { 34 | 35 | SqlSession session = MyBatisUtil.getSession(); 36 | try { 37 | UserMapper userMapper = session.getMapper(UserMapper.class); 38 | FriendGroupMapper friendGroupMapper = session.getMapper(FriendGroupMapper.class); 39 | 40 | BigGroupMapper bigGroupMapper = session.getMapper(BigGroupMapper.class); 41 | UserBigGroupMapper userBigGroupMapper = session.getMapper(UserBigGroupMapper.class); 42 | 43 | InitResult initResult = new InitResult(); 44 | initResult.setMine(userMapper.getUser(userId)); 45 | List friendGroups = friendGroupMapper.getGroupsByUserId(userId); 46 | if (!friendGroups.isEmpty()) { 47 | UserFriendGroupMapper userFriendGroupMapper = session.getMapper(UserFriendGroupMapper.class); 48 | List friendGroupIds = friendGroups 49 | .stream() 50 | .map(x -> x.getId()) 51 | .collect(Collectors.toList()); 52 | 53 | List userFriendGroups = userFriendGroupMapper.getUserIdsByGroupIds(friendGroupIds); 54 | //根据所有的用户ID查询出用户信息 55 | if (!userFriendGroups.isEmpty()) { 56 | List friendIds = userFriendGroups 57 | .stream() 58 | .map(x -> x.getUserId()) 59 | .collect(Collectors.toList()); 60 | List friends = userMapper.getUsersByIds(friendIds); 61 | 62 | friendGroups.stream().forEach(x -> { 63 | List userIdInGroup = userFriendGroups.stream() 64 | .filter(u -> u.getGroupId() == x.getId()) 65 | .map(m -> m.getUserId()) 66 | .collect(Collectors.toList()); 67 | 68 | x.setList(friends.stream() 69 | .filter(f -> userIdInGroup.contains(f.getId())) 70 | .collect(Collectors.toList())); 71 | }); 72 | } 73 | 74 | initResult.setFriend(friendGroups); 75 | } 76 | List myGroupIds = userBigGroupMapper.getGroupsByUserId(userId); 77 | List myGroups = bigGroupMapper.getGroupsByGroupIds(myGroupIds); 78 | initResult.setGroup(myGroups); 79 | return JsonResult.success(initResult); 80 | } finally { 81 | session.close(); 82 | } 83 | } 84 | 85 | @Override 86 | public JsonResult getMembersByGroupId(Long groupId) { 87 | GroupMemberResult result = new GroupMemberResult(); 88 | if (groupId <= 0) { 89 | return JsonResult.success(result); 90 | } 91 | SqlSession session = MyBatisUtil.getSession(); 92 | try { 93 | BigGroupMapper bigGroupMapper = session.getMapper(BigGroupMapper.class); 94 | UserBigGroupMapper userBigGroupMapper = session.getMapper(UserBigGroupMapper.class); 95 | UserMapper userMapper = session.getMapper(UserMapper.class); 96 | 97 | Long userId = bigGroupMapper.getGroupOwnerId(groupId); 98 | result.setOwner(userMapper.getUser(userId)); 99 | 100 | List memberIds = userBigGroupMapper.getGroupMembers(groupId); 101 | List users = userMapper.getUsersByIds(memberIds); 102 | result.setList(users); 103 | return JsonResult.success(result); 104 | } finally { 105 | session.close(); 106 | } 107 | } 108 | 109 | @Override 110 | public List getGroupIds(Long userId) { 111 | SqlSession session = MyBatisUtil.getSession(); 112 | try { 113 | UserBigGroupMapper userBigGroupMapper = session.getMapper(UserBigGroupMapper.class); 114 | return userBigGroupMapper.getGroupsByUserId(userId); 115 | } finally { 116 | session.close(); 117 | } 118 | } 119 | 120 | @Override 121 | public JsonResult addRecord(MsgRecord record) { 122 | if (record.getTo() <= 0) { 123 | return JsonResult.fail("无效的接收人"); 124 | } 125 | if (record.getContents() == null || record.getContents().isEmpty()) { 126 | return JsonResult.fail("空的消息内容"); 127 | } 128 | record.setCreateAt(System.currentTimeMillis()); 129 | record.setRoom(Utils.generateRoomId(record.getFrom(), record.getTo(), record.getMsgType() == 2 ? CHAT_TYPE_GROUP : CHAT_TYPE_OTHER)); 130 | SqlSession session = MyBatisUtil.getSession(); 131 | try { 132 | MsgRecordMapper msgRecordMapper = session.getMapper(MsgRecordMapper.class); 133 | msgRecordMapper.addRecord(record); 134 | session.commit(); 135 | } finally { 136 | session.close(); 137 | } 138 | return JsonResult.success(); 139 | } 140 | 141 | @Override 142 | public JsonResult getChatRecords(Long userId,Long id, String type, Long lastId) { 143 | if(!type.equals(CHAT_TYPE_FRIEND)&&!type.equals(CHAT_TYPE_GROUP)) { 144 | throw new IllegalArgumentException("type should be group or friend"); 145 | } 146 | boolean isChatGroup = type.equals(CHAT_TYPE_GROUP); 147 | SqlSession session = MyBatisUtil.getSession(); 148 | try { 149 | MsgRecordMapper msgRecordMapper = session.getMapper(MsgRecordMapper.class); 150 | List records = new ArrayList<>(20); 151 | List list = msgRecordMapper.getList(Utils.generateRoomId(userId,id,type),lastId); 152 | 153 | if(list.isEmpty()){ 154 | return JsonResult.success(records); 155 | } 156 | List userIds; 157 | if(isChatGroup){ 158 | userIds = list 159 | .stream() 160 | .map(x -> x.getFrom()) 161 | .distinct() 162 | .collect(Collectors.toList()); 163 | }else { 164 | userIds = new ArrayList<>(2); 165 | userIds.add(userId); 166 | userIds.add(id); 167 | } 168 | UserMapper userMapper = session.getMapper(UserMapper.class); 169 | List users = userMapper.getUsersByIds(userIds); 170 | 171 | for (MsgRecord record : list) { 172 | ChatRecordResult res = new ChatRecordResult(); 173 | res.setId(record.getId()); 174 | 175 | Optional user = users.stream().filter(x -> x.getId().equals(record.getFrom())).findFirst(); 176 | res.setAvatar(user.orElse(User.Anonymous).getAvatar()); 177 | res.setUsername(user.orElse(User.Anonymous).getUsername()); 178 | 179 | res.setContent(record.getContents()); 180 | res.setSelf(userId.equals(record.getFrom())); 181 | res.setTimestamp(record.getCreateAt()); 182 | records.add(res); 183 | } 184 | Collections.sort(records); 185 | return JsonResult.success(records); 186 | } finally { 187 | session.close(); 188 | } 189 | 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/user/set.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 帐号设置 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 26 | 27 | 41 |
42 |
43 | 44 |
45 | 71 | 72 |
73 | 74 |
75 |
76 | 77 |
78 |
79 |
    80 |
  • 我的资料
  • 81 |
  • 头像
  • 82 |
  • 密码
  • 83 |
  • 帐号绑定
  • 84 |
85 |
86 |
87 |
88 |
89 | 90 |
91 | 92 |
93 |
如果您在邮箱已激活的情况下,变更了邮箱,需重新验证邮箱
94 |
95 |
96 | 97 |
98 | 99 |
100 |
101 |
102 | 103 | 104 |
105 |
106 |
107 |
108 | 109 |
110 | 111 |
112 |
113 |
114 | 115 |
116 | 117 |
118 |
119 |
120 | 121 |
122 |
123 | 124 |
125 |
126 |
127 |

建议尺寸168*168,支持jpg、png、gif,最大不能超过30KB

128 |
129 | 130 |
131 | 132 | 133 |
134 |
135 |
136 | 137 |
138 | 139 |
140 | 141 |
142 | 143 |
144 |
145 |
146 | 147 |
148 | 149 |
150 |
6到16个字符
151 |
152 |
153 | 154 |
155 | 156 |
157 |
158 |
159 | 160 |
161 | 162 |
163 | 164 |
165 |
    166 |
  • 167 | 168 | 已成功绑定,您可以使用QQ帐号直接登录Fly社区,当然,您也可以 169 | 解除绑定 170 | 171 | 173 |
  • 174 |
  • 175 | 176 | 178 | 179 | 立即绑定 180 | ,即可使用微博帐号登录Fly社区 181 |
  • 182 |
183 |
184 |
185 | 186 |
187 |
188 |
189 | 190 | 191 | 199 | 200 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/js/mods/socket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author fyp 3 | * @create 2017-11-21 4 | * @remark websocket 模块化封装 5 | * */ 6 | 7 | layui.define(['jquery','layer'],function (exports) { 8 | var $ = layui.jquery; 9 | var layer = layui.layer; 10 | var reconnectInterval = null; 11 | var defaultOptions = { 12 | log:true, 13 | server:'ws://127.0.0.1:8888', 14 | token:'/layim/token', 15 | reconn:false 16 | }; 17 | 18 | var msgType={ 19 | chatFriend:1, 20 | chatGroup:2, 21 | ping:3 22 | }; 23 | 24 | var util=(function () { 25 | var util = function () { 26 | }; 27 | 28 | var textEncoder,textDecoder; 29 | 30 | function encodeNotSupportTextEncoder(str){ 31 | var bytes = new Array(); 32 | var len, c; 33 | len = str.length; 34 | for(var i = 0; i < len; i++) { 35 | c = str.charCodeAt(i); 36 | if(c >= 0x010000 && c <= 0x10FFFF) { 37 | bytes.push(((c >> 18) & 0x07) | 0xF0); 38 | bytes.push(((c >> 12) & 0x3F) | 0x80); 39 | bytes.push(((c >> 6) & 0x3F) | 0x80); 40 | bytes.push((c & 0x3F) | 0x80); 41 | } else if(c >= 0x000800 && c <= 0x00FFFF) { 42 | bytes.push(((c >> 12) & 0x0F) | 0xE0); 43 | bytes.push(((c >> 6) & 0x3F) | 0x80); 44 | bytes.push((c & 0x3F) | 0x80); 45 | } else if(c >= 0x000080 && c <= 0x0007FF) { 46 | bytes.push(((c >> 6) & 0x1F) | 0xC0); 47 | bytes.push((c & 0x3F) | 0x80); 48 | } else { 49 | bytes.push(c & 0xFF); 50 | } 51 | } 52 | return new Uint8Array(bytes); 53 | } 54 | function decodeNotSupportTextDecoder(data) { 55 | var out, i, len, c; 56 | var char2, char3; 57 | out = ""; 58 | len = data.length; 59 | i = 0; 60 | while (i < len) { 61 | c = data[i++]; 62 | switch (c >> 4) { 63 | case 0: 64 | case 1: 65 | case 2: 66 | case 3: 67 | case 4: 68 | case 5: 69 | case 6: 70 | case 7: 71 | out += String.fromCharCode(c); 72 | break; 73 | case 12: 74 | case 13: 75 | char2 = data[i++]; 76 | out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); 77 | break; 78 | case 14: 79 | char2 = data[i++]; 80 | char3 = data[i++]; 81 | out += String.fromCharCode(((c & 0x0F) << 12) | 82 | ((char2 & 0x3F) << 6) | 83 | ((char3 & 0x3F) << 0)); 84 | break; 85 | } 86 | } 87 | return out; 88 | } 89 | function encodeByTextEncoder(str){ 90 | if(!textEncoder){ 91 | textEncoder = new TextEncoder() 92 | } 93 | return textEncoder.encode(str); 94 | } 95 | function decodeByTextDecoder(data) { 96 | if(!textDecoder){ 97 | textDecoder = new TextDecoder() 98 | } 99 | return textDecoder.decode(data); 100 | } 101 | 102 | util.prototype.encode = function (str) { 103 | if(typeof (TextEncoder)==="undefined"){ 104 | return encodeNotSupportTextEncoder(str); 105 | } 106 | return encodeByTextEncoder(str); 107 | }; 108 | util.prototype.decode=function (data) { 109 | if (typeof (TextDecoder) === "undefined") { 110 | return decodeNotSupportTextDecoder(data); 111 | } 112 | return decodeByTextDecoder(data); 113 | }; 114 | return new util(); 115 | })(); 116 | 117 | //发送消息前替换掉 118 | var placeholder = 'placehold';// 9 个长度的占位符 4 targetId + 1 msgType + 4 bodyLength + body 119 | var tool={ 120 | ws:null, 121 | options :{}, 122 | wsUseful:function(){ 123 | return !!window['WebSocket']; 124 | }, 125 | log:function (msg) { 126 | this.options.log&&console.log(msg); 127 | }, 128 | init:function (options) { 129 | this.options = options; 130 | this.log('加载配置:'+JSON.stringify(tool.options)); 131 | this.connect(); 132 | }, 133 | token:function (callback) { 134 | $.get(tool.options.token,function (res) { 135 | if(res.code>0){ 136 | layer.msg("未登录"); 137 | }else{ 138 | callback(res.data.token); 139 | } 140 | }) 141 | }, 142 | decode:function(d) { 143 | console.log(d); 144 | return JSON.parse(util.decode(new Uint8Array(d))) 145 | }, 146 | encode:function(d) { 147 | var str = placeholder + d; 148 | return util.encode(str); 149 | }, 150 | connect:function () { 151 | if(this.wsUseful()) { 152 | this.token(function (token) { 153 | tool.ws = new WebSocket(tool.options.server + '?access_token=' + token); 154 | tool.ws.binaryType = 'arraybuffer'; 155 | tool.regWsEvent(); 156 | }); 157 | } 158 | }, 159 | regWsEvent:function () { 160 | if(this.ws){ 161 | this.ws.onmessage = function (event) { 162 | var d = tool.decode(event.data); 163 | call.msg&&call.msg(d); 164 | }; 165 | this.ws.onclose = function (event) { 166 | call.close&&call.close(event); 167 | tool.reconnect(); 168 | }; 169 | this.ws.onopen = function (event) { 170 | call.open&&call.open(event); 171 | if(reconnectInterval){ 172 | clearInterval(reconnectInterval); 173 | reconnectInterval = null; 174 | } 175 | setInterval(function () { 176 | tool.heartbeat(); 177 | },10000); 178 | }; 179 | this.ws.onerror = function (event) { 180 | call.error&&call.error(event); 181 | }; 182 | } 183 | }, 184 | reconnect:function () { 185 | if(tool.options.reconn) { 186 | if (reconnectInterval == null) { 187 | reconnectInterval = setInterval(function () { 188 | tool.log("正在尝试重连..."); 189 | tool.connect(); 190 | }, 2000); 191 | } 192 | } 193 | }, 194 | build:function(data) { 195 | //根据layim提供的data数据,进行解析 196 | var mine = data.mine, 197 | to = data.to, 198 | group = to.type === 'group'; 199 | //构造消息 200 | var targetId = to.id, 201 | dataBuff = this.encode(mine.content), 202 | view1 = new DataView(dataBuff.buffer), 203 | bodyLength =dataBuff.buffer.byteLength - placeholder.length; 204 | //接收人ID 205 | view1.setInt32(0, targetId); 206 | //消息类型 207 | view1.setInt8(4, group ? msgType.chatGroup : msgType.chatFriend); 208 | //消息长度 209 | view1.setInt32(5,bodyLength); 210 | return view1.buffer; 211 | }, 212 | heartbeat:function () { 213 | var targetId = 0, 214 | dataBuff = this.encode('ping'), 215 | view1 = new DataView(dataBuff.buffer), 216 | bodyLength =dataBuff.buffer.byteLength - placeholder.length; 217 | //接收人ID 218 | view1.setInt32(0, targetId); 219 | //消息类型 220 | view1.setInt8(4, msgType.ping); 221 | //消息长度 222 | view1.setInt32(5,bodyLength); 223 | var d = view1.buffer; 224 | this.ws.send(d); 225 | }, 226 | send:function (data) { 227 | var d = this.build(data); 228 | this.ws.send(d); 229 | } 230 | }; 231 | //回调 232 | var call ={}; 233 | var socket = function () { 234 | if (!tool.wsUseful()) { 235 | layer.msg("该浏览器不支持websocket"); 236 | } 237 | } 238 | socket.prototype.config=function (options) { 239 | $.extend(defaultOptions,options); 240 | tool.init(options); 241 | } 242 | socket.prototype.on=function(event,callback) { 243 | if(typeof callback === 'function'){ 244 | (!call[event]) && (call[event] = callback); 245 | tool.log('注册事件:【'+event+'】'); 246 | } 247 | return this; 248 | } 249 | socket.prototype.send=function(data){ 250 | tool.send(data); 251 | } 252 | 253 | exports('socket',new socket()); 254 | }) 255 | 256 | -------------------------------------------------------------------------------- /src/web/web.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/web/src/main/resources/static/html/jie/detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Fly Template v2.0,基于 layui 的轻量级社区模版 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | 19 | 27 | 28 | 50 |
51 |
52 | 53 | 54 |
55 |
56 |
57 |
58 |

Fly Template v2.0,基于 layui 的轻量级社区模版

59 |
60 | 置顶帖 61 | 精帖 62 | 63 | 未结贴 64 | 65 | 66 | 71 | 72 |
73 | 517 74 | 98032 75 |
76 |
77 |
78 | 79 | 80 | 81 | 贤心 82 | 1分钟前发布 83 | 84 | 85 |
86 | 悬赏:20飞吻 87 | 编辑此贴 88 | 收藏 89 | 90 |
91 |
92 | 93 |
94 |

95 | 该模版由 layui官方社区(fly.layui.com)倾情提供,只为表明我们对 layui 执着的信念、以及对未来持续加强的承诺。该模版基于 layui 搭建而成,可作为简约型问答社区的页面支撑。 96 |

97 |

更新日志:

98 |
 99 | # v2.0 2017-03-15
100 | * 采用 layui 1.0.9_rls 作为UI支撑
101 | * 所有页面更换为卡片式布局
102 | * 首页增加置顶板块
103 | * Detail页增加收藏按钮
104 | * 用户中心改造,增加左侧导航
105 | * 消息中心、登入、注册、找回密码等页面UI升级
106 | 
107 |

108 | 码云:http://git.oschina.net/sentsin/fly 109 |
GitHub:https://github.com/layui/fly 110 |

111 |

112 | Fly社区 113 |

114 |
115 |
116 | 117 |
118 | 119 | 182 | 183 |
184 |
185 |
186 |
187 | 188 |
189 |
190 |
191 | 192 | 193 |
194 |
195 |
196 |
197 |
198 |
199 | 200 |
201 |
202 |
最近热帖
203 |
204 | 使用 layui 秒搭后台大布局(基本结构) 205 | 6087 206 |
207 |
208 | Java实现LayIM后端的核心代码 209 | 767 210 |
211 |
212 | 使用 layui 秒搭后台大布局(基本结构) 213 | 6087 214 |
215 |
216 | Java实现LayIM后端的核心代码 217 | 767 218 |
219 |
220 | 使用 layui 秒搭后台大布局(基本结构) 221 | 6087 222 |
223 |
224 | Java实现LayIM后端的核心代码 225 | 767 226 |
227 |
228 | 使用 layui 秒搭后台大布局(基本结构) 229 | 6087 230 |
231 |
232 | Java实现LayIM后端的核心代码 233 | 767 234 |
235 |
236 | 237 |
238 |
近期热议
239 |
240 | 使用 layui 秒搭后台大布局之基本结构 241 | 96 242 |
243 |
244 | 使用 layui 秒搭后台大布局之基本结构 245 | 96 246 |
247 |
248 | 使用 layui 秒搭后台大布局之基本结构 249 | 96 250 |
251 |
252 | 使用 layui 秒搭后台大布局之基本结构 253 | 96 254 |
255 |
256 | 使用 layui 秒搭后台大布局之基本结构 257 | 96 258 |
259 |
260 | 使用 layui 秒搭后台大布局之基本结构 261 | 96 262 |
263 |
264 | 使用 layui 秒搭后台大布局之基本结构 265 | 96 266 |
267 |
268 | 使用 layui 秒搭后台大布局之基本结构 269 | 96 270 |
271 |
272 |
273 |
274 | 275 | 276 | 284 | 285 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /layim.sql: -------------------------------------------------------------------------------- 1 | -- MySQL dump 10.13 Distrib 5.7.12, for Win64 (x86_64) 2 | -- 3 | -- Host: localhost Database: layim 4 | -- ------------------------------------------------------ 5 | -- Server version 5.7.17-log 6 | 7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 10 | /*!40101 SET NAMES utf8 */; 11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 12 | /*!40103 SET TIME_ZONE='+00:00' */; 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | 18 | -- 19 | -- Table structure for table `apply` 20 | -- 21 | 22 | DROP TABLE IF EXISTS `apply`; 23 | /*!40101 SET @saved_cs_client = @@character_set_client */; 24 | /*!40101 SET character_set_client = utf8 */; 25 | CREATE TABLE `apply` ( 26 | `id` bigint(20) NOT NULL, 27 | `create_at` bigint(20) DEFAULT NULL, 28 | `avatar` varchar(255) DEFAULT NULL, 29 | `isread` bit(1) NOT NULL, 30 | `name` varchar(255) DEFAULT NULL, 31 | `remark` varchar(255) DEFAULT NULL, 32 | `result` int(11) NOT NULL, 33 | `toid` bigint(20) NOT NULL, 34 | `type` int(11) NOT NULL, 35 | `uid` bigint(20) NOT NULL, 36 | `group_id` bigint(20) DEFAULT NULL, 37 | PRIMARY KEY (`id`) 38 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 39 | /*!40101 SET character_set_client = @saved_cs_client */; 40 | 41 | -- 42 | -- Dumping data for table `apply` 43 | -- 44 | 45 | LOCK TABLES `apply` WRITE; 46 | /*!40000 ALTER TABLE `apply` DISABLE KEYS */; 47 | INSERT INTO `apply` VALUES (144896,1513567903924,'/images/demo/xiaoniao.jpg','','安小鸟','123456',1,203328,1,843968,204096),(226432,1513567672133,'/images/demo/zhenhuan.jpg','','甄嬛','123564',1,203328,1,602624,615936),(374336,1513567318034,'/images/demo/xiaopanzi.jpg','','小小小盘子','1231231',1,203328,1,421440,781569),(385984,1513585488046,NULL,'\0',NULL,'雍正王 同意了你的好友请求',1,421440,3,0,0),(702144,1513585486586,NULL,'\0',NULL,'雍正王 同意了你的好友请求',1,602624,3,0,0),(713792,1513585484723,NULL,'',NULL,'雍正王 同意了你的好友请求',1,843968,3,0,0); 48 | /*!40000 ALTER TABLE `apply` ENABLE KEYS */; 49 | UNLOCK TABLES; 50 | 51 | -- 52 | -- Table structure for table `big_group` 53 | -- 54 | 55 | DROP TABLE IF EXISTS `big_group`; 56 | /*!40101 SET @saved_cs_client = @@character_set_client */; 57 | /*!40101 SET character_set_client = utf8 */; 58 | CREATE TABLE `big_group` ( 59 | `id` bigint(20) NOT NULL, 60 | `create_at` bigint(20) DEFAULT NULL, 61 | `avatar` varchar(120) DEFAULT NULL, 62 | `description` varchar(100) DEFAULT NULL, 63 | `group_name` varchar(20) DEFAULT NULL, 64 | `uid` bigint(20) DEFAULT NULL, 65 | PRIMARY KEY (`id`), 66 | KEY `FKol8kn1ah7lj1olypbu7r40tsw` (`uid`), 67 | CONSTRAINT `FKol8kn1ah7lj1olypbu7r40tsw` FOREIGN KEY (`uid`) REFERENCES `user` (`id`) 68 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 69 | /*!40101 SET character_set_client = @saved_cs_client */; 70 | 71 | -- 72 | -- Dumping data for table `big_group` 73 | -- 74 | 75 | LOCK TABLES `big_group` WRITE; 76 | /*!40000 ALTER TABLE `big_group` DISABLE KEYS */; 77 | INSERT INTO `big_group` VALUES (1,0,'/static/images/demo/huangshang.jpg',NULL,'皇室大家族',203328); 78 | /*!40000 ALTER TABLE `big_group` ENABLE KEYS */; 79 | UNLOCK TABLES; 80 | 81 | -- 82 | -- Table structure for table `friend_group` 83 | -- 84 | 85 | DROP TABLE IF EXISTS `friend_group`; 86 | /*!40101 SET @saved_cs_client = @@character_set_client */; 87 | /*!40101 SET character_set_client = utf8 */; 88 | CREATE TABLE `friend_group` ( 89 | `id` bigint(20) NOT NULL, 90 | `create_at` bigint(20) DEFAULT NULL, 91 | `name` varchar(20) DEFAULT NULL, 92 | `uid` bigint(20) DEFAULT NULL, 93 | PRIMARY KEY (`id`), 94 | KEY `FKawe6k1o9mujam11lxiwcwbqpu` (`uid`), 95 | CONSTRAINT `FKawe6k1o9mujam11lxiwcwbqpu` FOREIGN KEY (`uid`) REFERENCES `user` (`id`) 96 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 97 | /*!40101 SET character_set_client = @saved_cs_client */; 98 | 99 | -- 100 | -- Dumping data for table `friend_group` 101 | -- 102 | 103 | LOCK TABLES `friend_group` WRITE; 104 | /*!40000 ALTER TABLE `friend_group` DISABLE KEYS */; 105 | INSERT INTO `friend_group` VALUES (204096,1512628211849,'我的好友',843968),(251841,1512628191335,'姐妹们',308800),(369153,1512628345563,'后宫佳丽',203328),(472641,1512628172160,'主子',306816),(615936,1512627979684,'我的对手',602624),(781569,1512628497492,'我的好友',421440),(887488,1512628145472,'我的敌人',514048); 106 | /*!40000 ALTER TABLE `friend_group` ENABLE KEYS */; 107 | UNLOCK TABLES; 108 | 109 | -- 110 | -- Table structure for table `msg_record` 111 | -- 112 | 113 | DROP TABLE IF EXISTS `msg_record`; 114 | /*!40101 SET @saved_cs_client = @@character_set_client */; 115 | /*!40101 SET character_set_client = utf8 */; 116 | CREATE TABLE `msg_record` ( 117 | `id` bigint(20) NOT NULL, 118 | `from_id` int(11) DEFAULT NULL, 119 | `to_id` int(11) DEFAULT NULL, 120 | `room_id` bigint(20) DEFAULT NULL, 121 | `contents` varchar(2000) DEFAULT NULL, 122 | `create_at` bigint(20) DEFAULT NULL, 123 | `mtype` int(11) DEFAULT NULL, 124 | PRIMARY KEY (`id`) 125 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 126 | /*!40101 SET character_set_client = @saved_cs_client */; 127 | 128 | -- 129 | -- Dumping data for table `msg_record` 130 | -- 131 | 132 | LOCK TABLES `msg_record` WRITE; 133 | /*!40000 ALTER TABLE `msg_record` DISABLE KEYS */; 134 | INSERT INTO `msg_record` VALUES (1548899624909,203328,421440,421440203328,'hello,thank you very much',1548899624909,0),(1548899630877,421440,203328,421440203328,'你好呀',1548899630877,0),(1548899635678,421440,203328,421440203328,'我是小盘子',1548899635678,0),(1548899640021,203328,421440,421440203328,'en ,nihao',1548899640021,0),(1548899643866,203328,421440,421440203328,'face[哼] ',1548899643866,0),(1548899666500,203328,421440,421440203328,'face[微笑] ',1548899666500,0),(1548899673147,421440,203328,421440203328,'face[兔子] ',1548899673147,0),(1548899676453,421440,203328,421440203328,'11',1548899676453,0),(1548899677167,421440,203328,421440203328,'22',1548899677167,0),(1548899677855,421440,203328,421440203328,'33',1548899677855,0),(1548899678564,421440,203328,421440203328,'44',1548899678564,0),(1548899679329,421440,203328,421440203328,'55',1548899679329,0),(1548899680103,421440,203328,421440203328,'66',1548899680103,0),(1548899682716,203328,421440,421440203328,'77',1548899682716,0),(1548899683505,203328,421440,421440203328,'77',1548899683505,0),(1548899684316,203328,421440,421440203328,'88',1548899684316,0),(1548899685534,203328,421440,421440203328,'96',1548899685534,0),(1548899686333,203328,421440,421440203328,'5',1548899686333,0),(1548899687029,203328,421440,421440203328,'4',1548899687029,0),(1548899687644,203328,421440,421440203328,'1',1548899687644,0),(1548899688300,203328,421440,421440203328,'2',1548899688300,0),(1548899688974,203328,421440,421440203328,'3',1548899688974,0),(1548899689510,203328,421440,421440203328,'2',1548899689510,0),(1548899690181,203328,421440,421440203328,'1',1548899690181,0),(1548991657446,203328,1,2033281,'123456',1548991657446,0),(1548991662186,203328,1,2033281,'俄文额无',1548991662186,0),(1548991838386,203328,1,2033281,'和谷歌会更好',1548991838386,0),(1548991853625,203328,1,2033281,'丰东股份郭德纲',1548991853625,0),(1548992056375,203328,1,1,'123456',1548992056376,2),(1548992058175,203328,1,1,'4125364564123',1548992058175,2),(1548992060165,203328,1,1,'1231256465',1548992060165,2),(1548992529570,203328,1,1,'1',1548992529570,2),(1548992530695,203328,1,1,'2',1548992530695,2),(1548992535261,203328,1,1,'3',1548992535261,2),(1548992536238,203328,1,1,'4',1548992536238,2),(1548992537972,203328,1,1,'5',1548992537972,2),(1548992539300,203328,1,1,'6',1548992539300,2),(1548992540391,203328,1,1,'7',1548992540391,2),(1548992542535,203328,1,1,'8',1548992542535,2),(1548992543319,203328,1,1,'9',1548992543319,2),(1548992544408,203328,1,1,'10',1548992544408,2),(1548992545032,203328,1,1,'11',1548992545032,2),(1548992545670,203328,1,1,'12',1548992545670,2),(1548992546310,203328,1,1,'13',1548992546310,2),(1548992546903,203328,1,1,'14',1548992546903,2),(1548992547503,203328,1,1,'15',1548992547503,2),(1548992548102,203328,1,1,'16',1548992548102,2),(1548992548655,203328,1,1,'17',1548992548655,2),(1548992549254,203328,1,1,'18',1548992549254,2),(1548992549845,203328,1,1,'19',1548992549845,2),(1548992550446,203328,1,1,'20',1548992550446,2),(1548992551015,203328,1,1,'21',1548992551015,2),(1548992551649,203328,1,1,'22',1548992551649,2),(1548992552872,203328,1,1,'23',1548992552872,2),(1548992553558,203328,1,1,'24',1548992553558,2),(1548992554159,203328,1,1,'25',1548992554159,2),(1548992554767,203328,1,1,'26',1548992554767,2),(1548992555366,203328,1,1,'27',1548992555366,2),(1548992556069,203328,1,1,'28',1548992556069,2),(1551150826551,203328,421440,421440203328,'halou ',1551150826551,1),(1551150833333,421440,203328,421440203328,'en ,zai ',1551150833333,1),(1551150835856,421440,203328,421440203328,'你好吗?',1551150835856,1),(1551150838393,203328,421440,421440203328,'haoda ',1551150838393,1),(1551150877091,203328,421440,421440203328,'我们的聊天记录',1551150877091,1),(1551150881008,421440,203328,421440203328,'嗯嗯',1551150881008,1),(1551150906189,421440,1,1,'哈哈哈',1551150906189,2),(1551150917030,421440,1,1,'小盘子,你收不到吗',1551150917030,2),(1551150921772,203328,1,1,'?',1551150921772,2),(1551151011072,421440,203328,421440203328,'111',1551151011072,1),(1551151023607,203328,1,1,'群聊测试',1551151023607,2),(1551151028080,421440,1,1,'群聊和UI福',1551151028080,2); 135 | /*!40000 ALTER TABLE `msg_record` ENABLE KEYS */; 136 | UNLOCK TABLES; 137 | 138 | -- 139 | -- Table structure for table `user` 140 | -- 141 | 142 | DROP TABLE IF EXISTS `user`; 143 | /*!40101 SET @saved_cs_client = @@character_set_client */; 144 | /*!40101 SET character_set_client = utf8 */; 145 | CREATE TABLE `user` ( 146 | `id` bigint(20) NOT NULL, 147 | `create_at` bigint(20) DEFAULT NULL, 148 | `avatar` varchar(255) DEFAULT NULL, 149 | `sign` varchar(255) DEFAULT NULL, 150 | `user_name` varchar(255) DEFAULT NULL, 151 | PRIMARY KEY (`id`) 152 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 153 | /*!40101 SET character_set_client = @saved_cs_client */; 154 | 155 | -- 156 | -- Dumping data for table `user` 157 | -- 158 | 159 | LOCK TABLES `user` WRITE; 160 | /*!40000 ALTER TABLE `user` DISABLE KEYS */; 161 | INSERT INTO `user` VALUES (203328,1512628345557,'/static/images/demo/huangshang.jpg','爱妃多的数不过来,愁煞朕了','雍正王'),(306816,1512628172154,'/static/images/demo/gonggong.jpg','誓死效忠皇后','江福海'),(308800,1512628191325,'/static/images/demo/huanghou.jpg','在我面前你还敢怀孩子?','皇后'),(421440,1512628497485,'/static/images/demo/xiaopanzi.jpg','看戏中。。。','小小小盘子'),(514048,1512628145362,'/static/images/demo/huafei.jpg','贱人就是矫情','华妃'),(602624,1512627979581,'/static/images/demo/zhenhuan.jpg','呵呵','甄嬛'),(843968,1512628211842,'/static/images/demo/xiaoniao.jpg','皇后,杀了皇后','安小鸟'); 162 | /*!40000 ALTER TABLE `user` ENABLE KEYS */; 163 | UNLOCK TABLES; 164 | 165 | -- 166 | -- Table structure for table `user_account` 167 | -- 168 | 169 | DROP TABLE IF EXISTS `user_account`; 170 | /*!40101 SET @saved_cs_client = @@character_set_client */; 171 | /*!40101 SET character_set_client = utf8 */; 172 | CREATE TABLE `user_account` ( 173 | `id` bigint(20) NOT NULL, 174 | `password` varchar(20) NOT NULL, 175 | `username` varchar(20) NOT NULL, 176 | `create_at` bigint(20) DEFAULT NULL, 177 | PRIMARY KEY (`id`), 178 | UNIQUE KEY `UK_castjbvpeeus0r8lbpehiu0e4` (`username`) 179 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 180 | /*!40101 SET character_set_client = @saved_cs_client */; 181 | 182 | -- 183 | -- Dumping data for table `user_account` 184 | -- 185 | 186 | LOCK TABLES `user_account` WRITE; 187 | /*!40000 ALTER TABLE `user_account` DISABLE KEYS */; 188 | INSERT INTO `user_account` VALUES (203328,'123123','huangshang',1512628345557),(306816,'123123','gonggong',1512628172154),(308800,'123123','huanghou',1512628191325),(421440,'123123','admin',1512628497485),(514048,'123123','huafei',1512628145362),(602624,'123123','zhenhuan',1512627979581),(843968,'123123','xiaoniao',1512628211842); 189 | /*!40000 ALTER TABLE `user_account` ENABLE KEYS */; 190 | UNLOCK TABLES; 191 | 192 | -- 193 | -- Table structure for table `user_big_group` 194 | -- 195 | 196 | DROP TABLE IF EXISTS `user_big_group`; 197 | /*!40101 SET @saved_cs_client = @@character_set_client */; 198 | /*!40101 SET character_set_client = utf8 */; 199 | CREATE TABLE `user_big_group` ( 200 | `uid` bigint(20) NOT NULL, 201 | `group_id` bigint(20) NOT NULL, 202 | KEY `FKftgx1bft0t9o6xo74evcfhlsd` (`group_id`), 203 | KEY `FKpyb8edgdcgjw5pd0g3mrmf3vt` (`uid`), 204 | CONSTRAINT `FKftgx1bft0t9o6xo74evcfhlsd` FOREIGN KEY (`group_id`) REFERENCES `big_group` (`id`), 205 | CONSTRAINT `FKpyb8edgdcgjw5pd0g3mrmf3vt` FOREIGN KEY (`uid`) REFERENCES `user` (`id`) 206 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 207 | /*!40101 SET character_set_client = @saved_cs_client */; 208 | 209 | -- 210 | -- Dumping data for table `user_big_group` 211 | -- 212 | 213 | LOCK TABLES `user_big_group` WRITE; 214 | /*!40000 ALTER TABLE `user_big_group` DISABLE KEYS */; 215 | INSERT INTO `user_big_group` VALUES (843968,1),(602624,1),(514048,1),(421440,1),(308800,1),(306816,1),(203328,1); 216 | /*!40000 ALTER TABLE `user_big_group` ENABLE KEYS */; 217 | UNLOCK TABLES; 218 | 219 | -- 220 | -- Table structure for table `user_friend_group` 221 | -- 222 | 223 | DROP TABLE IF EXISTS `user_friend_group`; 224 | /*!40101 SET @saved_cs_client = @@character_set_client */; 225 | /*!40101 SET character_set_client = utf8 */; 226 | CREATE TABLE `user_friend_group` ( 227 | `uid` bigint(20) NOT NULL, 228 | `group_id` bigint(20) NOT NULL, 229 | KEY `FKiio3b59cbsn1orj8ps2mlxk8j` (`group_id`), 230 | KEY `FK3g6jqnmqu3lobq57235cawwq` (`uid`), 231 | CONSTRAINT `FK3g6jqnmqu3lobq57235cawwq` FOREIGN KEY (`uid`) REFERENCES `user` (`id`), 232 | CONSTRAINT `FKiio3b59cbsn1orj8ps2mlxk8j` FOREIGN KEY (`group_id`) REFERENCES `friend_group` (`id`) 233 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 234 | /*!40101 SET character_set_client = @saved_cs_client */; 235 | 236 | -- 237 | -- Dumping data for table `user_friend_group` 238 | -- 239 | 240 | LOCK TABLES `user_friend_group` WRITE; 241 | /*!40000 ALTER TABLE `user_friend_group` DISABLE KEYS */; 242 | INSERT INTO `user_friend_group` VALUES (203328,204096),(203328,615936),(203328,781569),(843968,369153),(602624,369153),(421440,369153); 243 | /*!40000 ALTER TABLE `user_friend_group` ENABLE KEYS */; 244 | UNLOCK TABLES; 245 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 246 | 247 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 248 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 249 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 250 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 251 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 252 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 253 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 254 | 255 | -- Dump completed on 2019-03-13 14:23:24 256 | --------------------------------------------------------------------------------