├── .classpath ├── .factorypath ├── .gitattributes ├── .project ├── .settings ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.apt.core.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.m2e.core.prefs └── org.springframework.ide.eclipse.prefs ├── LearnPigChat └── Chapter1 │ ├── image │ ├── 6a95c3a857b747658ad1696531323ec0.jpg │ └── a188e3df8d8d44c5bd16bf838c922bbf.jpg │ ├── 前端 │ └── index.html │ └── 后端 │ └── netty │ ├── CustomHandler.java │ ├── HelloServer.java │ ├── HelloServerInitializer.java │ └── websocket │ ├── ChatHandler.java │ ├── WSServer.java │ └── WSServerInitialzer.java ├── README.md ├── image ├── 1.jpg ├── 10.jpg ├── 11.jpg ├── 12.jpg ├── 13.jpg ├── 14.jpg ├── 15.jpg ├── 2.jpg ├── 3.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg └── 9.jpg ├── pom.xml ├── src └── main │ ├── java │ ├── com │ │ └── imooc │ │ │ ├── Application.java │ │ │ ├── FastdfsImporter.java │ │ │ ├── NettyBooter.java │ │ │ ├── SpringUtil.java │ │ │ ├── controller │ │ │ └── UserController.java │ │ │ ├── enums │ │ │ ├── MsgActionEnum.java │ │ │ ├── MsgSignFlagEnum.java │ │ │ ├── OperatorFriendRequestTypeEnum.java │ │ │ └── SearchFriendsStatusEnum.java │ │ │ ├── mapper │ │ │ ├── ChatMsgMapper.java │ │ │ ├── FriendsRequestMapper.java │ │ │ ├── MyFriendsMapper.java │ │ │ ├── UsersMapper.java │ │ │ └── UsersMapperCustom.java │ │ │ ├── netty │ │ │ ├── ChatHandler.java │ │ │ ├── ChatMsg.java │ │ │ ├── DataContent.java │ │ │ ├── HeartBeatHandler.java │ │ │ ├── UserChannelRel.java │ │ │ ├── WSServer.java │ │ │ └── WSServerInitialzer.java │ │ │ ├── pojo │ │ │ ├── ChatMsg.java │ │ │ ├── FriendsRequest.java │ │ │ ├── MyFriends.java │ │ │ ├── Users.java │ │ │ ├── bo │ │ │ │ └── UsersBO.java │ │ │ └── vo │ │ │ │ ├── FriendRequestVO.java │ │ │ │ ├── MyFriendsVO.java │ │ │ │ └── UsersVO.java │ │ │ ├── service │ │ │ ├── UserService.java │ │ │ └── impl │ │ │ │ └── UserServiceImpl.java │ │ │ └── utils │ │ │ ├── FastDFSClient.java │ │ │ ├── FileUtils.java │ │ │ ├── IMoocJSONResult.java │ │ │ ├── JsonUtils.java │ │ │ ├── MD5Utils.java │ │ │ ├── MyMapper.java │ │ │ └── QRCodeUtils.java │ └── org │ │ └── n3r │ │ └── idworker │ │ ├── Code.java │ │ ├── DayCode.java │ │ ├── Id.java │ │ ├── IdWorker.java │ │ ├── InvalidSystemClock.java │ │ ├── RandomCodeStrategy.java │ │ ├── Sid.java │ │ ├── Test.java │ │ ├── WorkerIdStrategy.java │ │ ├── strategy │ │ ├── DayPrefixRandomCodeStrategy.java │ │ ├── DefaultRandomCodeStrategy.java │ │ ├── DefaultWorkerIdStrategy.java │ │ └── FileLock.java │ │ └── utils │ │ ├── HttpReq.java │ │ ├── IPv4Utils.java │ │ ├── Ip.java │ │ ├── Props.java │ │ ├── Serializes.java │ │ └── Utils.java │ └── resources │ ├── application.properties │ └── mapper │ ├── ChatMsgMapper.xml │ ├── FriendsRequestMapper.xml │ ├── MyFriendsMapper.xml │ ├── UsersMapper.xml │ └── UsersMapperCustom.xml ├── target └── classes │ ├── application.properties │ ├── com │ └── imooc │ │ ├── Application.class │ │ ├── FastdfsImporter.class │ │ ├── NettyBooter.class │ │ ├── SpringUtil.class │ │ ├── controller │ │ └── UserController.class │ │ ├── enums │ │ ├── MsgActionEnum.class │ │ ├── MsgSignFlagEnum.class │ │ ├── OperatorFriendRequestTypeEnum.class │ │ └── SearchFriendsStatusEnum.class │ │ ├── mapper │ │ ├── ChatMsgMapper.class │ │ ├── FriendsRequestMapper.class │ │ ├── MyFriendsMapper.class │ │ ├── UsersMapper.class │ │ └── UsersMapperCustom.class │ │ ├── netty │ │ ├── ChatHandler.class │ │ ├── ChatMsg.class │ │ ├── DataContent.class │ │ ├── HeartBeatHandler.class │ │ ├── UserChannelRel.class │ │ ├── WSServer$SingletionWSServer.class │ │ ├── WSServer.class │ │ └── WSServerInitialzer.class │ │ ├── pojo │ │ ├── ChatMsg.class │ │ ├── FriendsRequest.class │ │ ├── MyFriends.class │ │ ├── Users.class │ │ ├── bo │ │ │ └── UsersBO.class │ │ └── vo │ │ │ ├── FriendRequestVO.class │ │ │ ├── MyFriendsVO.class │ │ │ └── UsersVO.class │ │ ├── service │ │ ├── UserService.class │ │ └── impl │ │ │ └── UserServiceImpl.class │ │ └── utils │ │ ├── FastDFSClient.class │ │ ├── FileUtils.class │ │ ├── IMoocJSONResult.class │ │ ├── JsonUtils.class │ │ ├── MD5Utils.class │ │ ├── MyMapper.class │ │ └── QRCodeUtils.class │ ├── mapper │ ├── ChatMsgMapper.xml │ ├── FriendsRequestMapper.xml │ ├── MyFriendsMapper.xml │ ├── UsersMapper.xml │ └── UsersMapperCustom.xml │ └── org │ └── n3r │ └── idworker │ ├── Code.class │ ├── DayCode.class │ ├── Id.class │ ├── IdWorker.class │ ├── InvalidSystemClock.class │ ├── RandomCodeStrategy.class │ ├── Sid$1.class │ ├── Sid.class │ ├── Test.class │ ├── WorkerIdStrategy.class │ ├── strategy │ ├── DayPrefixRandomCodeStrategy.class │ ├── DefaultRandomCodeStrategy$1.class │ ├── DefaultRandomCodeStrategy.class │ ├── DefaultWorkerIdStrategy$1.class │ ├── DefaultWorkerIdStrategy$2.class │ ├── DefaultWorkerIdStrategy.class │ └── FileLock.class │ └── utils │ ├── HttpReq.class │ ├── IPv4Utils.class │ ├── Ip.class │ ├── Props$Silent.class │ ├── Props.class │ ├── Serializes.class │ └── Utils.class └── 前端UI代码 └── imooc-zhuxin ├── .project ├── chatting.html ├── css ├── chat.css ├── header.css ├── mui.css ├── mui.indexedlist.css ├── mui.min.css └── registLogin │ ├── arrow.jpg │ ├── main.css │ └── util.css ├── fontico ├── demo.css ├── demo_fontclass.html ├── demo_symbol.html ├── demo_unicode.html ├── iconfont.css ├── iconfont.eot ├── iconfont.js ├── iconfont.svg ├── iconfont.ttf └── iconfont.woff ├── fonts └── mui.ttf ├── image ├── addfriends.png ├── bg.png ├── download.png ├── error.png ├── face-default-cat.png ├── friends.png ├── givememoney.png ├── good.png ├── qrcode.png ├── scanscan.png ├── success.png └── upload.png ├── imooc-chatlist.html ├── imooc-contact.html ├── imooc-discover.html ├── imooc-me.html ├── index.html ├── js ├── app.js ├── mui.indexedlist.js ├── mui.js ├── mui.min.js └── nickname.js ├── login.html ├── manifest.json ├── mp3 ├── di_didi.mp3 ├── msn.mp3 └── send.mp3 ├── myQRCode.html ├── myface.html ├── mynickname.html ├── plugin ├── cropper │ ├── css │ │ ├── cropper.css │ │ └── main.css │ ├── images │ │ └── picture.jpg │ ├── index.html │ ├── js │ │ ├── cropper.js │ │ └── main.js │ └── uploader.html └── v3.1.6 │ ├── css │ ├── cropper.css │ └── main.css │ ├── images │ └── picture.jpg │ ├── index.html │ ├── js │ ├── cropper.js │ └── main.js │ └── myface-uploader.html ├── scanme.html ├── searchFriends.html ├── searchFriendsResult.html └── unpackage ├── .confirmed_dependencies └── .dependencies /.classpath: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | imooc-zhuxin-netty 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.springframework.ide.eclipse.boot.validation.springbootbuilder 15 | 16 | 17 | 18 | 19 | org.springframework.ide.eclipse.core.springbuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.ide.eclipse.core.springnature 31 | org.eclipse.jdt.core.javanature 32 | org.eclipse.m2e.core.maven2Nature 33 | 34 | 35 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/test/java=UTF-8 5 | encoding//src/test/resources=UTF-8 6 | encoding/=UTF-8 7 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.apt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.apt.aptEnabled=true 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 3 | org.eclipse.jdt.core.compiler.processAnnotations=enabled 4 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.settings/org.springframework.ide.eclipse.prefs: -------------------------------------------------------------------------------- 1 | boot.validation.initialized=true 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/image/6a95c3a857b747658ad1696531323ec0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/LearnPigChat/Chapter1/image/6a95c3a857b747658ad1696531323ec0.jpg -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/image/a188e3df8d8d44c5bd16bf838c922bbf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/LearnPigChat/Chapter1/image/a188e3df8d8d44c5bd16bf838c922bbf.jpg -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/前端/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
发送消息:
10 | 11 | 12 | 13 |
接受消息:
14 |
15 | 16 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/后端/netty/CustomHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | import io.netty.handler.codec.http.DefaultFullHttpResponse; 9 | import io.netty.handler.codec.http.FullHttpResponse; 10 | import io.netty.handler.codec.http.HttpHeaderNames; 11 | import io.netty.handler.codec.http.HttpObject; 12 | import io.netty.handler.codec.http.HttpRequest; 13 | import io.netty.handler.codec.http.HttpResponseStatus; 14 | import io.netty.handler.codec.http.HttpVersion; 15 | import io.netty.util.CharsetUtil; 16 | 17 | /** 18 | * @Description: 创建自定义助手类 19 | */ 20 | // SimpleChannelInboundHandler: 对于请求来讲,其实相当于[入站,入境] 21 | public class CustomHandler extends SimpleChannelInboundHandler { 22 | 23 | @Override 24 | protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) 25 | throws Exception { 26 | // 获取channel 27 | Channel channel = ctx.channel(); 28 | 29 | if (msg instanceof HttpRequest) { 30 | // 显示客户端的远程地址 31 | System.out.println(channel.remoteAddress()); 32 | 33 | // 定义发送的数据消息 34 | ByteBuf content = Unpooled.copiedBuffer("Hello netty~", CharsetUtil.UTF_8); 35 | 36 | // 构建一个http response 37 | FullHttpResponse response = 38 | new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 39 | HttpResponseStatus.OK, 40 | content); 41 | // 为响应增加数据类型和长度 42 | response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); 43 | response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()); 44 | 45 | // 把响应刷到客户端 46 | ctx.writeAndFlush(response); 47 | } 48 | 49 | } 50 | 51 | @Override 52 | public void channelRegistered(ChannelHandlerContext ctx) throws Exception { 53 | System.out.println("channel。。。注册"); 54 | super.channelRegistered(ctx); 55 | } 56 | 57 | @Override 58 | public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { 59 | System.out.println("channel。。。移除"); 60 | super.channelUnregistered(ctx); 61 | } 62 | 63 | @Override 64 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 65 | System.out.println("channel。。。活跃"); 66 | super.channelActive(ctx); 67 | } 68 | 69 | @Override 70 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 71 | System.out.println("channel。。。不活跃"); 72 | super.channelInactive(ctx); 73 | } 74 | 75 | @Override 76 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 77 | System.out.println("channeld读取完毕。。。"); 78 | super.channelReadComplete(ctx); 79 | } 80 | 81 | @Override 82 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 83 | System.out.println("用户事件触发。。。"); 84 | super.userEventTriggered(ctx, evt); 85 | } 86 | 87 | @Override 88 | public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { 89 | System.out.println("channel可写更改"); 90 | super.channelWritabilityChanged(ctx); 91 | } 92 | 93 | @Override 94 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 95 | System.out.println("补货到异常"); 96 | super.exceptionCaught(ctx, cause); 97 | } 98 | 99 | @Override 100 | public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 101 | System.out.println("助手类添加"); 102 | super.handlerAdded(ctx); 103 | } 104 | 105 | @Override 106 | public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 107 | System.out.println("助手类移除"); 108 | super.handlerRemoved(ctx); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/后端/netty/HelloServer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * @Description: 实现客户端发送一个请求,服务器会返回 hello netty 12 | */ 13 | public class HelloServer { 14 | 15 | public static void main(String[] args) throws Exception { 16 | 17 | // 定义一对线程组 18 | // 主线程组, 用于接受客户端的连接,但是不做任何处理,跟老板一样,不做事 19 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 20 | // 从线程组, 老板线程组会把任务丢给他,让手下线程组去做任务 21 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 22 | 23 | try { 24 | // netty服务器的创建, ServerBootstrap 是一个启动类 25 | ServerBootstrap serverBootstrap = new ServerBootstrap(); 26 | serverBootstrap.group(bossGroup, workerGroup) // 设置主从线程组 27 | .channel(NioServerSocketChannel.class) // 设置nio的双向通道 28 | .childHandler(new HelloServerInitializer()); // 子处理器,用于处理workerGroup 29 | 30 | // 启动server,并且设置8088为启动的端口号,同时启动方式为同步 31 | ChannelFuture channelFuture = serverBootstrap.bind(8088).sync(); 32 | 33 | // 监听关闭的channel,设置位同步方式 34 | channelFuture.channel().closeFuture().sync(); 35 | } finally { 36 | bossGroup.shutdownGracefully(); 37 | workerGroup.shutdownGracefully(); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/后端/netty/HelloServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpServerCodec; 7 | 8 | /** 9 | * @Description: 初始化器,channel注册后,会执行里面的相应的初始化方法 10 | */ 11 | public class HelloServerInitializer extends ChannelInitializer { 12 | 13 | @Override 14 | protected void initChannel(SocketChannel channel) throws Exception { 15 | // 通过SocketChannel去获得对应的管道 16 | ChannelPipeline pipeline = channel.pipeline(); 17 | 18 | // 通过管道,添加handler 19 | // HttpServerCodec是由netty自己提供的助手类,可以理解为拦截器 20 | // 当请求到服务端,我们需要做解码,响应到客户端做编码 21 | pipeline.addLast("HttpServerCodec", new HttpServerCodec()); 22 | 23 | // 添加自定义的助手类,返回 "hello netty~" 24 | pipeline.addLast("customHandler", new CustomHandler()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/后端/netty/websocket/ChatHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty.websocket; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | import io.netty.channel.group.ChannelGroup; 9 | import io.netty.channel.group.DefaultChannelGroup; 10 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 11 | import io.netty.util.concurrent.GlobalEventExecutor; 12 | 13 | /** 14 | * 15 | * @Description: 处理消息的handler 16 | * TextWebSocketFrame: 在netty中,是用于为websocket专门处理文本的对象,frame是消息的载体 17 | */ 18 | public class ChatHandler extends SimpleChannelInboundHandler { 19 | 20 | // 用于记录和管理所有客户端的channle 21 | private static ChannelGroup clients = 22 | new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 23 | 24 | @Override 25 | protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) 26 | throws Exception { 27 | // 获取客户端传输过来的消息 28 | String content = msg.text(); 29 | System.out.println("接受到的数据:" + content); 30 | 31 | // for (Channel channel: clients) { 32 | // channel.writeAndFlush( 33 | // new TextWebSocketFrame( 34 | // "[服务器在]" + LocalDateTime.now() 35 | // + "接受到消息, 消息为:" + content)); 36 | // } 37 | // 下面这个方法,和上面的for循环,一致 38 | clients.writeAndFlush( 39 | new TextWebSocketFrame( 40 | "[服务器在]" + LocalDateTime.now() 41 | + "接受到消息, 消息为:" + content)); 42 | 43 | } 44 | 45 | /** 46 | * 当客户端连接服务端之后(打开连接) 47 | * 获取客户端的channle,并且放到ChannelGroup中去进行管理 48 | */ 49 | @Override 50 | public void handlerAdded(ChannelHandlerContext ctx) throws Exception { 51 | clients.add(ctx.channel()); 52 | } 53 | 54 | @Override 55 | public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 56 | // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端的channel 57 | // clients.remove(ctx.channel()); 58 | System.out.println("客户端断开,channle对应的长id为:" 59 | + ctx.channel().id().asLongText()); 60 | System.out.println("客户端断开,channle对应的短id为:" 61 | + ctx.channel().id().asShortText()); 62 | } 63 | 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/后端/netty/websocket/WSServer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty.websocket; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | public class WSServer { 10 | 11 | public static void main(String[] args) throws Exception { 12 | 13 | EventLoopGroup mainGroup = new NioEventLoopGroup(); 14 | EventLoopGroup subGroup = new NioEventLoopGroup(); 15 | 16 | try { 17 | ServerBootstrap server = new ServerBootstrap(); 18 | server.group(mainGroup, subGroup) 19 | .channel(NioServerSocketChannel.class) 20 | .childHandler(new WSServerInitialzer()); 21 | 22 | ChannelFuture future = server.bind(8088).sync(); 23 | 24 | future.channel().closeFuture().sync(); 25 | } finally { 26 | mainGroup.shutdownGracefully(); 27 | subGroup.shutdownGracefully(); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /LearnPigChat/Chapter1/后端/netty/websocket/WSServerInitialzer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty.websocket; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.http.HttpServerCodec; 8 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 9 | import io.netty.handler.stream.ChunkedWriteHandler; 10 | 11 | public class WSServerInitialzer extends ChannelInitializer { 12 | 13 | @Override 14 | protected void initChannel(SocketChannel ch) throws Exception { 15 | ChannelPipeline pipeline = ch.pipeline(); 16 | 17 | // websocket 基于http协议,所以要有http编解码器 18 | pipeline.addLast(new HttpServerCodec()); 19 | // 对写大数据流的支持 20 | pipeline.addLast(new ChunkedWriteHandler()); 21 | // 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse 22 | // 几乎在netty中的编程,都会使用到此hanler 23 | pipeline.addLast(new HttpObjectAggregator(1024*64)); 24 | 25 | // ====================== 以上是用于支持http协议 ====================== 26 | 27 | // ====================== 以下是支持httpWebsocket ====================== 28 | 29 | /** 30 | * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws 31 | * 本handler会帮你处理一些繁重的复杂的事 32 | * 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳 33 | * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同 34 | */ 35 | pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); 36 | 37 | // 自定义的handler 38 | pipeline.addLast(new ChatHandler()); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PigChat 2 | Netty+SpringBoot+FastDFS+Html5实现聊天App 3 | 4 |
5 | 6 | 项目实现详解:
7 | [Netty+SpringBoot+FastDFS+Html5实现聊天App详解(一)](https://segmentfault.com/a/1190000018144704)
8 | [Netty+SpringBoot+FastDFS+Html5实现聊天App详解(二)](https://segmentfault.com/a/1190000018165542)
9 | [Netty+SpringBoot+FastDFS+Html5实现聊天App详解(三)](https://segmentfault.com/a/1190000018175282)
10 | [Netty+SpringBoot+FastDFS+Html5实现聊天App详解(四)](https://segmentfault.com/a/1190000018179149)
11 | [Netty+SpringBoot+FastDFS+Html5实现聊天App详解(五)](https://segmentfault.com/a/1190000018185625)
12 | [Netty+SpringBoot+FastDFS+Html5实现聊天App详解(六)](https://segmentfault.com/a/1190000018208067)
13 | 14 | 15 |


16 | ## 数据库 17 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/1.jpg) 18 |

19 | ## 用户表 20 | face_image为用户的头像,需要保存小图与大图,qrcode为该用户对应的二维码 21 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/2.jpg) 22 |

23 | ## 朋友关系表 24 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/3.jpg) 25 |

26 | ## 好友申请表 27 | 记录发送好友请求申请的数据表 28 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/4.jpg) 29 |

30 | ## 聊天记录表 31 | sign_flag表示消息的签收状态,为0表示未签收,为1表示已签收 32 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/5.jpg) 33 |


34 | ## 项目结构 35 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/6.jpg) 36 |

37 | ### utils包 38 | #### FileUtils 主要提供了一些与文件相关的操作 39 | #### IMoocJSONResult 是自定义的响应给前端的数据结构 40 | #### JsonUtils 提供了一些关于json转换的操作 41 | #### MD5Utils 提供了对字符串进行md5加密的操作 42 | #### QRCodeUtils 提供了一些关于二维码的相关操作 43 | #### FastDFSClient 提供了各种上传文件以及删除文件的操作 44 |

45 | ### enums包 46 | #### MsgActionEnum 发送消息的动作的枚举,类似于消息的类型 47 | #### MsgSignFlagEnum 消息签收状态的枚举 48 | #### OperatorFriendRequestTypeEnum 忽略或者通过好友请求的枚举 49 | #### SearchFriendsStatusEnum 添加好友前置状态的枚举 50 |

51 | ### pojo包 52 | 增加了bo包与vo包,分别存放business object与value object / view object; 53 |

54 | ### mapper包 55 | 增加了一个自定义的UsersMapperCustom,在其中自定义了查询好友请求列表,查询好友列表,以及批量签收聊天消息的方法; 56 |

57 | ### service包 58 | 提供如下方法:
59 | #### queryUsernameIsExist 判断用户名是否存在 60 | #### queryUserForLogin 查询用户是否存在 61 | #### saveUser 用户注册 62 | #### updateUserInfo 修改用户记录 63 | #### preconditionSearchFriends 搜索朋友的前置条件 64 | #### queryUserInfoByUsername 根据用户名查询用户对象 65 | #### sendFriendRequest 添加好友请求记录,保存到数据库 66 | #### queryFriendRequestList 查询好友请求 67 | #### deleteFriendRequest 删除好友请求记录 68 | #### passFriendRequest 通过好友请求 69 | #### queryMyFriends 查询好友列表 70 | #### saveMsg 保存聊天消息到数据库 71 | #### updateMsgSigned 批量签收消息 72 | #### getUnReadMsgList 获取未签收消息列表 73 |

74 | ### controller包 75 | 提供如下接口:
76 | #### registOrLogin 用户注册/登录 77 | #### uploadFaceBase64 上传用户头像 78 | #### setNickname 设置用户昵称 79 | #### searchUser 搜索好友 80 | #### addFriendRequest 发送添加好友的请求 81 | #### queryFriendRequests 发送添加好友的请求 82 | #### operFriendRequest 接受方通过或者忽略朋友请求 83 | #### myFriends 查询我的好友列表 84 | #### getUnReadMsgList 用户手机端获取未签收的消息列表 85 |


86 | ## 测试效果 87 | ### 注册与登录 88 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/7.jpg) 89 | ### 个人信息 90 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/8.jpg) 91 | ### 更换头像 92 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/9.jpg) 93 | ### 添加好友 94 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/10.jpg) 95 | ### 二维码添加好友 96 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/11.jpg) 97 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/12.jpg) 98 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/13.jpg) 99 | ### 接受好友请求后开始聊天 100 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/14.jpg) 101 | ![](https://github.com/ShimmerPig/PigChat/blob/master/image/15.jpg) 102 |


103 | -------------------------------------------------------------------------------- /image/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/1.jpg -------------------------------------------------------------------------------- /image/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/10.jpg -------------------------------------------------------------------------------- /image/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/11.jpg -------------------------------------------------------------------------------- /image/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/12.jpg -------------------------------------------------------------------------------- /image/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/13.jpg -------------------------------------------------------------------------------- /image/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/14.jpg -------------------------------------------------------------------------------- /image/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/15.jpg -------------------------------------------------------------------------------- /image/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/2.jpg -------------------------------------------------------------------------------- /image/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/3.jpg -------------------------------------------------------------------------------- /image/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/4.jpg -------------------------------------------------------------------------------- /image/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/5.jpg -------------------------------------------------------------------------------- /image/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/6.jpg -------------------------------------------------------------------------------- /image/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/7.jpg -------------------------------------------------------------------------------- /image/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/8.jpg -------------------------------------------------------------------------------- /image/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/image/9.jpg -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.imooc 4 | imooc-zhuxin-netty 5 | 0.0.1-SNAPSHOT 6 | 7 | imooc-zhuxin-netty 8 | imooc-zhuxin-netty 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.5.RELEASE 14 | 15 | 16 | 17 | 18 | UTF-8 19 | UTF-8 20 | 1.8 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-devtools 32 | true 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-configuration-processor 43 | true 44 | 45 | 46 | 47 | io.netty 48 | netty-all 49 | 4.1.25.Final 50 | 51 | 52 | 53 | 54 | commons-codec 55 | commons-codec 56 | 1.11 57 | 58 | 59 | org.apache.commons 60 | commons-lang3 61 | 3.4 62 | 63 | 64 | org.apache.commons 65 | commons-io 66 | 1.3.2 67 | 68 | 69 | 70 | mysql 71 | mysql-connector-java 72 | 5.1.41 73 | 74 | 75 | 76 | 77 | org.mybatis.spring.boot 78 | mybatis-spring-boot-starter 79 | 1.3.1 80 | 81 | 82 | 83 | tk.mybatis 84 | mapper-spring-boot-starter 85 | 1.2.4 86 | 87 | 88 | 89 | com.github.pagehelper 90 | pagehelper-spring-boot-starter 91 | 1.2.3 92 | 93 | 94 | 95 | 96 | com.github.tobato 97 | fastdfs-client 98 | 1.26.2 99 | 100 | 101 | 102 | org.springframework 103 | spring-test 104 | 105 | 106 | 107 | 108 | com.google.zxing 109 | javase 110 | 3.3.3 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | org.springframework.boot 119 | spring-boot-maven-plugin 120 | 121 | true 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/Application.java: -------------------------------------------------------------------------------- 1 | package com.imooc; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.ComponentScan; 8 | 9 | import tk.mybatis.spring.annotation.MapperScan; 10 | 11 | @EnableAutoConfiguration 12 | @SpringBootApplication 13 | @MapperScan(basePackages="com.imooc.mapper") 14 | @ComponentScan(basePackages= {"com.imooc","org.n3r.idworker"}) 15 | public class Application { 16 | 17 | @Bean 18 | public SpringUtil getSpringUtil() { 19 | return new SpringUtil(); 20 | } 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(Application.class, args); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/FastdfsImporter.java: -------------------------------------------------------------------------------- 1 | package com.imooc; 2 | import org.springframework.context.annotation.Configuration; 3 | import org.springframework.context.annotation.EnableMBeanExport; 4 | import org.springframework.context.annotation.Import; 5 | import org.springframework.jmx.support.RegistrationPolicy; 6 | 7 | import com.github.tobato.fastdfs.FdfsClientConfig; 8 | 9 | @Configuration 10 | @Import(FdfsClientConfig.class) 11 | @EnableMBeanExport(registration=RegistrationPolicy.IGNORE_EXISTING) 12 | public class FastdfsImporter { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/NettyBooter.java: -------------------------------------------------------------------------------- 1 | package com.imooc; 2 | 3 | import org.springframework.context.ApplicationListener; 4 | import org.springframework.context.event.ContextRefreshedEvent; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.imooc.netty.WSServer; 8 | 9 | @Component 10 | public class NettyBooter implements ApplicationListener{ 11 | 12 | @Override 13 | public void onApplicationEvent(ContextRefreshedEvent event) { 14 | if(event.getApplicationContext().getParent()==null) { 15 | try { 16 | WSServer.getInstance().start(); 17 | } catch (Exception e) { 18 | e.printStackTrace(); 19 | } 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/SpringUtil.java: -------------------------------------------------------------------------------- 1 | package com.imooc; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | 7 | /** 8 | * @Description: 提供手动获取被spring管理的bean对象 9 | */ 10 | public class SpringUtil implements ApplicationContextAware { 11 | 12 | private static ApplicationContext applicationContext; 13 | 14 | @Override 15 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 16 | if (SpringUtil.applicationContext == null) { 17 | SpringUtil.applicationContext = applicationContext; 18 | } 19 | } 20 | 21 | // 获取applicationContext 22 | public static ApplicationContext getApplicationContext() { 23 | return applicationContext; 24 | } 25 | 26 | // 通过name获取 Bean. 27 | public static Object getBean(String name) { 28 | return getApplicationContext().getBean(name); 29 | } 30 | 31 | // 通过class获取Bean. 32 | public static T getBean(Class clazz) { 33 | return getApplicationContext().getBean(clazz); 34 | } 35 | 36 | // 通过name,以及Clazz返回指定的Bean 37 | public static T getBean(String name, Class clazz) { 38 | return getApplicationContext().getBean(name, clazz); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/enums/MsgActionEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * 5 | * @Description: 发送消息的动作 枚举 6 | */ 7 | public enum MsgActionEnum { 8 | 9 | CONNECT(1, "第一次(或重连)初始化连接"), 10 | CHAT(2, "聊天消息"), 11 | SIGNED(3, "消息签收"), 12 | KEEPALIVE(4, "客户端保持心跳"), 13 | PULL_FRIEND(5, "拉取好友"); 14 | 15 | public final Integer type; 16 | public final String content; 17 | 18 | MsgActionEnum(Integer type, String content){ 19 | this.type = type; 20 | this.content = content; 21 | } 22 | 23 | public Integer getType() { 24 | return type; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/enums/MsgSignFlagEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * 5 | * @Description: 消息签收状态 枚举 6 | */ 7 | public enum MsgSignFlagEnum { 8 | 9 | unsign(0, "未签收"), 10 | signed(1, "已签收"); 11 | 12 | public final Integer type; 13 | public final String content; 14 | 15 | MsgSignFlagEnum(Integer type, String content){ 16 | this.type = type; 17 | this.content = content; 18 | } 19 | 20 | public Integer getType() { 21 | return type; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/enums/OperatorFriendRequestTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * 5 | * @Description: 忽略或者通过 好友请求的枚举 6 | */ 7 | public enum OperatorFriendRequestTypeEnum { 8 | 9 | IGNORE(0, "忽略"), 10 | PASS(1, "通过"); 11 | 12 | public final Integer type; 13 | public final String msg; 14 | 15 | OperatorFriendRequestTypeEnum(Integer type, String msg){ 16 | this.type = type; 17 | this.msg = msg; 18 | } 19 | 20 | public Integer getType() { 21 | return type; 22 | } 23 | 24 | public static String getMsgByType(Integer type) { 25 | for (OperatorFriendRequestTypeEnum operType : OperatorFriendRequestTypeEnum.values()) { 26 | if (operType.getType() == type) { 27 | return operType.msg; 28 | } 29 | } 30 | return null; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/enums/SearchFriendsStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.enums; 2 | 3 | /** 4 | * 5 | * @Description: 添加好友前置状态 枚举 6 | */ 7 | public enum SearchFriendsStatusEnum { 8 | 9 | SUCCESS(0, "OK"), 10 | USER_NOT_EXIST(1, "无此用户..."), 11 | NOT_YOURSELF(2, "不能添加你自己..."), 12 | ALREADY_FRIENDS(3, "该用户已经是你的好友..."); 13 | 14 | public final Integer status; 15 | public final String msg; 16 | 17 | SearchFriendsStatusEnum(Integer status, String msg){ 18 | this.status = status; 19 | this.msg = msg; 20 | } 21 | 22 | public Integer getStatus() { 23 | return status; 24 | } 25 | 26 | public static String getMsgByKey(Integer status) { 27 | for (SearchFriendsStatusEnum type : SearchFriendsStatusEnum.values()) { 28 | if (type.getStatus() == status) { 29 | return type.msg; 30 | } 31 | } 32 | return null; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/mapper/ChatMsgMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.pojo.ChatMsg; 4 | import com.imooc.utils.MyMapper; 5 | 6 | public interface ChatMsgMapper extends MyMapper { 7 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/mapper/FriendsRequestMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.pojo.FriendsRequest; 4 | import com.imooc.utils.MyMapper; 5 | 6 | public interface FriendsRequestMapper extends MyMapper { 7 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/mapper/MyFriendsMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.pojo.MyFriends; 4 | import com.imooc.utils.MyMapper; 5 | 6 | public interface MyFriendsMapper extends MyMapper { 7 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/mapper/UsersMapper.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import com.imooc.pojo.Users; 4 | import com.imooc.utils.MyMapper; 5 | 6 | public interface UsersMapper extends MyMapper { 7 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/mapper/UsersMapperCustom.java: -------------------------------------------------------------------------------- 1 | package com.imooc.mapper; 2 | 3 | import java.util.List; 4 | 5 | import com.imooc.pojo.Users; 6 | import com.imooc.pojo.vo.FriendRequestVO; 7 | import com.imooc.pojo.vo.MyFriendsVO; 8 | import com.imooc.utils.MyMapper; 9 | 10 | public interface UsersMapperCustom extends MyMapper { 11 | 12 | public List queryFriendRequestList(String acceptUserId); 13 | 14 | public List queryMyFriends(String userId); 15 | 16 | public void batchUpdateMsgSigned(List msgIdList); 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/netty/ChatMsg.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ChatMsg implements Serializable { 6 | 7 | private static final long serialVersionUID = 3611169682695799175L; 8 | 9 | private String senderId; // 发送者的用户id 10 | private String receiverId; // 接受者的用户id 11 | private String msg; // 聊天内容 12 | private String msgId; // 用于消息的签收 13 | 14 | public String getSenderId() { 15 | return senderId; 16 | } 17 | public void setSenderId(String senderId) { 18 | this.senderId = senderId; 19 | } 20 | public String getReceiverId() { 21 | return receiverId; 22 | } 23 | public void setReceiverId(String receiverId) { 24 | this.receiverId = receiverId; 25 | } 26 | public String getMsg() { 27 | return msg; 28 | } 29 | public void setMsg(String msg) { 30 | this.msg = msg; 31 | } 32 | public String getMsgId() { 33 | return msgId; 34 | } 35 | public void setMsgId(String msgId) { 36 | this.msgId = msgId; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/netty/DataContent.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import java.io.Serializable; 4 | 5 | public class DataContent implements Serializable { 6 | 7 | private static final long serialVersionUID = 8021381444738260454L; 8 | 9 | private Integer action; // 动作类型 10 | private ChatMsg chatMsg; // 用户的聊天内容entity 11 | private String extand; // 扩展字段 12 | 13 | public Integer getAction() { 14 | return action; 15 | } 16 | public void setAction(Integer action) { 17 | this.action = action; 18 | } 19 | public ChatMsg getChatMsg() { 20 | return chatMsg; 21 | } 22 | public void setChatMsg(ChatMsg chatMsg) { 23 | this.chatMsg = chatMsg; 24 | } 25 | public String getExtand() { 26 | return extand; 27 | } 28 | public void setExtand(String extand) { 29 | this.extand = extand; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/netty/HeartBeatHandler.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.handler.timeout.IdleState; 7 | import io.netty.handler.timeout.IdleStateEvent; 8 | 9 | /** 10 | * @Description: 用于检测channel的心跳handler 11 | * 继承ChannelInboundHandlerAdapter,从而不需要实现channelRead0方法 12 | */ 13 | public class HeartBeatHandler extends ChannelInboundHandlerAdapter { 14 | 15 | @Override 16 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 17 | 18 | // 判断evt是否是IdleStateEvent(用于触发用户事件,包含 读空闲/写空闲/读写空闲 ) 19 | if (evt instanceof IdleStateEvent) { 20 | IdleStateEvent event = (IdleStateEvent)evt; // 强制类型转换 21 | 22 | if (event.state() == IdleState.READER_IDLE) { 23 | System.out.println("进入读空闲..."); 24 | } else if (event.state() == IdleState.WRITER_IDLE) { 25 | System.out.println("进入写空闲..."); 26 | } else if (event.state() == IdleState.ALL_IDLE) { 27 | 28 | System.out.println("channel关闭前,users的数量为:" + ChatHandler.users.size()); 29 | 30 | Channel channel = ctx.channel(); 31 | // 关闭无用的channel,以防资源浪费 32 | channel.close(); 33 | 34 | System.out.println("channel关闭后,users的数量为:" + ChatHandler.users.size()); 35 | } 36 | } 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/netty/UserChannelRel.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import java.util.HashMap; 4 | 5 | import io.netty.channel.Channel; 6 | 7 | /** 8 | * @Description: 用户id和channel的关联关系处理 9 | */ 10 | public class UserChannelRel { 11 | 12 | private static HashMap manager = new HashMap<>(); 13 | 14 | public static void put(String senderId, Channel channel) { 15 | manager.put(senderId, channel); 16 | } 17 | 18 | public static Channel get(String senderId) { 19 | return manager.get(senderId); 20 | } 21 | 22 | public static void output() { 23 | for (HashMap.Entry entry : manager.entrySet()) { 24 | System.out.println("UserId: " + entry.getKey() 25 | + ", ChannelId: " + entry.getValue().id().asLongText()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/netty/WSServer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import io.netty.bootstrap.ServerBootstrap; 6 | import io.netty.channel.ChannelFuture; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.nio.NioServerSocketChannel; 10 | 11 | @Component 12 | public class WSServer { 13 | 14 | private static class SingletionWSServer { 15 | static final WSServer instance = new WSServer(); 16 | } 17 | 18 | public static WSServer getInstance() { 19 | return SingletionWSServer.instance; 20 | } 21 | 22 | private EventLoopGroup mainGroup; 23 | private EventLoopGroup subGroup; 24 | private ServerBootstrap server; 25 | private ChannelFuture future; 26 | 27 | public WSServer() { 28 | mainGroup = new NioEventLoopGroup(); 29 | subGroup = new NioEventLoopGroup(); 30 | server = new ServerBootstrap(); 31 | server.group(mainGroup, subGroup) 32 | .channel(NioServerSocketChannel.class) 33 | .childHandler(new WSServerInitialzer()); 34 | } 35 | 36 | public void start() { 37 | this.future = server.bind(8088); 38 | System.err.println("netty websocket server 启动完毕..."); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/netty/WSServerInitialzer.java: -------------------------------------------------------------------------------- 1 | package com.imooc.netty; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.http.HttpServerCodec; 8 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 9 | import io.netty.handler.stream.ChunkedWriteHandler; 10 | import io.netty.handler.timeout.IdleStateHandler; 11 | 12 | public class WSServerInitialzer extends ChannelInitializer { 13 | 14 | @Override 15 | protected void initChannel(SocketChannel ch) throws Exception { 16 | ChannelPipeline pipeline = ch.pipeline(); 17 | 18 | // websocket 基于http协议,所以要有http编解码器 19 | pipeline.addLast(new HttpServerCodec()); 20 | // 对写大数据流的支持 21 | pipeline.addLast(new ChunkedWriteHandler()); 22 | // 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse 23 | // 几乎在netty中的编程,都会使用到此hanler 24 | pipeline.addLast(new HttpObjectAggregator(1024*64)); 25 | 26 | // ====================== 以上是用于支持http协议 ====================== 27 | 28 | 29 | 30 | // ====================== 增加心跳支持 start ====================== 31 | // 针对客户端,如果在1分钟时没有向服务端发送读写心跳(ALL),则主动断开 32 | // 如果是读空闲或者写空闲,不处理 33 | pipeline.addLast(new IdleStateHandler(8, 10, 12)); 34 | // 自定义的空闲状态检测 35 | pipeline.addLast(new HeartBeatHandler()); 36 | // ====================== 增加心跳支持 end ====================== 37 | 38 | 39 | 40 | 41 | // ====================== 以下是支持httpWebsocket ====================== 42 | 43 | /** 44 | * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws 45 | * 本handler会帮你处理一些繁重的复杂的事 46 | * 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳 47 | * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同 48 | */ 49 | pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); 50 | 51 | // 自定义的handler 52 | pipeline.addLast(new ChatHandler()); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/ChatMsg.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import java.util.Date; 4 | import javax.persistence.*; 5 | 6 | @Table(name = "chat_msg") 7 | public class ChatMsg { 8 | @Id 9 | private String id; 10 | 11 | @Column(name = "send_user_id") 12 | private String sendUserId; 13 | 14 | @Column(name = "accept_user_id") 15 | private String acceptUserId; 16 | 17 | private String msg; 18 | 19 | /** 20 | * 消息是否签收状态 21 | 1:签收 22 | 0:未签收 23 | 24 | */ 25 | @Column(name = "sign_flag") 26 | private Integer signFlag; 27 | 28 | /** 29 | * 发送请求的事件 30 | */ 31 | @Column(name = "create_time") 32 | private Date createTime; 33 | 34 | /** 35 | * @return id 36 | */ 37 | public String getId() { 38 | return id; 39 | } 40 | 41 | /** 42 | * @param id 43 | */ 44 | public void setId(String id) { 45 | this.id = id; 46 | } 47 | 48 | /** 49 | * @return send_user_id 50 | */ 51 | public String getSendUserId() { 52 | return sendUserId; 53 | } 54 | 55 | /** 56 | * @param sendUserId 57 | */ 58 | public void setSendUserId(String sendUserId) { 59 | this.sendUserId = sendUserId; 60 | } 61 | 62 | /** 63 | * @return accept_user_id 64 | */ 65 | public String getAcceptUserId() { 66 | return acceptUserId; 67 | } 68 | 69 | /** 70 | * @param acceptUserId 71 | */ 72 | public void setAcceptUserId(String acceptUserId) { 73 | this.acceptUserId = acceptUserId; 74 | } 75 | 76 | /** 77 | * @return msg 78 | */ 79 | public String getMsg() { 80 | return msg; 81 | } 82 | 83 | /** 84 | * @param msg 85 | */ 86 | public void setMsg(String msg) { 87 | this.msg = msg; 88 | } 89 | 90 | /** 91 | * 获取消息是否签收状态 92 | 1:签收 93 | 0:未签收 94 | 95 | * 96 | * @return sign_flag - 消息是否签收状态 97 | 1:签收 98 | 0:未签收 99 | 100 | */ 101 | public Integer getSignFlag() { 102 | return signFlag; 103 | } 104 | 105 | /** 106 | * 设置消息是否签收状态 107 | 1:签收 108 | 0:未签收 109 | 110 | * 111 | * @param signFlag 消息是否签收状态 112 | 1:签收 113 | 0:未签收 114 | 115 | */ 116 | public void setSignFlag(Integer signFlag) { 117 | this.signFlag = signFlag; 118 | } 119 | 120 | /** 121 | * 获取发送请求的事件 122 | * 123 | * @return create_time - 发送请求的事件 124 | */ 125 | public Date getCreateTime() { 126 | return createTime; 127 | } 128 | 129 | /** 130 | * 设置发送请求的事件 131 | * 132 | * @param createTime 发送请求的事件 133 | */ 134 | public void setCreateTime(Date createTime) { 135 | this.createTime = createTime; 136 | } 137 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/FriendsRequest.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import java.util.Date; 4 | import javax.persistence.*; 5 | 6 | @Table(name = "friends_request") 7 | public class FriendsRequest { 8 | @Id 9 | private String id; 10 | 11 | @Column(name = "send_user_id") 12 | private String sendUserId; 13 | 14 | @Column(name = "accept_user_id") 15 | private String acceptUserId; 16 | 17 | /** 18 | * 发送请求的事件 19 | */ 20 | @Column(name = "request_date_time") 21 | private Date requestDateTime; 22 | 23 | /** 24 | * @return id 25 | */ 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | /** 31 | * @param id 32 | */ 33 | public void setId(String id) { 34 | this.id = id; 35 | } 36 | 37 | /** 38 | * @return send_user_id 39 | */ 40 | public String getSendUserId() { 41 | return sendUserId; 42 | } 43 | 44 | /** 45 | * @param sendUserId 46 | */ 47 | public void setSendUserId(String sendUserId) { 48 | this.sendUserId = sendUserId; 49 | } 50 | 51 | /** 52 | * @return accept_user_id 53 | */ 54 | public String getAcceptUserId() { 55 | return acceptUserId; 56 | } 57 | 58 | /** 59 | * @param acceptUserId 60 | */ 61 | public void setAcceptUserId(String acceptUserId) { 62 | this.acceptUserId = acceptUserId; 63 | } 64 | 65 | /** 66 | * 获取发送请求的事件 67 | * 68 | * @return request_date_time - 发送请求的事件 69 | */ 70 | public Date getRequestDateTime() { 71 | return requestDateTime; 72 | } 73 | 74 | /** 75 | * 设置发送请求的事件 76 | * 77 | * @param requestDateTime 发送请求的事件 78 | */ 79 | public void setRequestDateTime(Date requestDateTime) { 80 | this.requestDateTime = requestDateTime; 81 | } 82 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/MyFriends.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import javax.persistence.*; 4 | 5 | @Table(name = "my_friends") 6 | public class MyFriends { 7 | @Id 8 | private String id; 9 | 10 | /** 11 | * 用户id 12 | */ 13 | @Column(name = "my_user_id") 14 | private String myUserId; 15 | 16 | /** 17 | * 用户的好友id 18 | */ 19 | @Column(name = "my_friend_user_id") 20 | private String myFriendUserId; 21 | 22 | /** 23 | * @return id 24 | */ 25 | public String getId() { 26 | return id; 27 | } 28 | 29 | /** 30 | * @param id 31 | */ 32 | public void setId(String id) { 33 | this.id = id; 34 | } 35 | 36 | /** 37 | * 获取用户id 38 | * 39 | * @return my_user_id - 用户id 40 | */ 41 | public String getMyUserId() { 42 | return myUserId; 43 | } 44 | 45 | /** 46 | * 设置用户id 47 | * 48 | * @param myUserId 用户id 49 | */ 50 | public void setMyUserId(String myUserId) { 51 | this.myUserId = myUserId; 52 | } 53 | 54 | /** 55 | * 获取用户的好友id 56 | * 57 | * @return my_friend_user_id - 用户的好友id 58 | */ 59 | public String getMyFriendUserId() { 60 | return myFriendUserId; 61 | } 62 | 63 | /** 64 | * 设置用户的好友id 65 | * 66 | * @param myFriendUserId 用户的好友id 67 | */ 68 | public void setMyFriendUserId(String myFriendUserId) { 69 | this.myFriendUserId = myFriendUserId; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/Users.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo; 2 | 3 | import javax.persistence.*; 4 | 5 | public class Users { 6 | @Id 7 | private String id; 8 | 9 | /** 10 | * 用户名,账号,慕信号 11 | */ 12 | private String username; 13 | 14 | /** 15 | * 密码 16 | */ 17 | private String password; 18 | 19 | /** 20 | * 我的头像,如果没有默认给一张 21 | */ 22 | @Column(name = "face_image") 23 | private String faceImage; 24 | 25 | @Column(name = "face_image_big") 26 | private String faceImageBig; 27 | 28 | /** 29 | * 昵称 30 | */ 31 | private String nickname; 32 | 33 | /** 34 | * 新用户注册后默认后台生成二维码,并且上传到fastdfs 35 | */ 36 | private String qrcode; 37 | 38 | private String cid; 39 | 40 | /** 41 | * @return id 42 | */ 43 | public String getId() { 44 | return id; 45 | } 46 | 47 | /** 48 | * @param id 49 | */ 50 | public void setId(String id) { 51 | this.id = id; 52 | } 53 | 54 | /** 55 | * 获取用户名,账号,慕信号 56 | * 57 | * @return username - 用户名,账号,慕信号 58 | */ 59 | public String getUsername() { 60 | return username; 61 | } 62 | 63 | /** 64 | * 设置用户名,账号,慕信号 65 | * 66 | * @param username 用户名,账号,慕信号 67 | */ 68 | public void setUsername(String username) { 69 | this.username = username; 70 | } 71 | 72 | /** 73 | * 获取密码 74 | * 75 | * @return password - 密码 76 | */ 77 | public String getPassword() { 78 | return password; 79 | } 80 | 81 | /** 82 | * 设置密码 83 | * 84 | * @param password 密码 85 | */ 86 | public void setPassword(String password) { 87 | this.password = password; 88 | } 89 | 90 | /** 91 | * 获取我的头像,如果没有默认给一张 92 | * 93 | * @return face_image - 我的头像,如果没有默认给一张 94 | */ 95 | public String getFaceImage() { 96 | return faceImage; 97 | } 98 | 99 | /** 100 | * 设置我的头像,如果没有默认给一张 101 | * 102 | * @param faceImage 我的头像,如果没有默认给一张 103 | */ 104 | public void setFaceImage(String faceImage) { 105 | this.faceImage = faceImage; 106 | } 107 | 108 | /** 109 | * @return face_image_big 110 | */ 111 | public String getFaceImageBig() { 112 | return faceImageBig; 113 | } 114 | 115 | /** 116 | * @param faceImageBig 117 | */ 118 | public void setFaceImageBig(String faceImageBig) { 119 | this.faceImageBig = faceImageBig; 120 | } 121 | 122 | /** 123 | * 获取昵称 124 | * 125 | * @return nickname - 昵称 126 | */ 127 | public String getNickname() { 128 | return nickname; 129 | } 130 | 131 | /** 132 | * 设置昵称 133 | * 134 | * @param nickname 昵称 135 | */ 136 | public void setNickname(String nickname) { 137 | this.nickname = nickname; 138 | } 139 | 140 | /** 141 | * 获取新用户注册后默认后台生成二维码,并且上传到fastdfs 142 | * 143 | * @return qrcode - 新用户注册后默认后台生成二维码,并且上传到fastdfs 144 | */ 145 | public String getQrcode() { 146 | return qrcode; 147 | } 148 | 149 | /** 150 | * 设置新用户注册后默认后台生成二维码,并且上传到fastdfs 151 | * 152 | * @param qrcode 新用户注册后默认后台生成二维码,并且上传到fastdfs 153 | */ 154 | public void setQrcode(String qrcode) { 155 | this.qrcode = qrcode; 156 | } 157 | 158 | /** 159 | * @return cid 160 | */ 161 | public String getCid() { 162 | return cid; 163 | } 164 | 165 | /** 166 | * @param cid 167 | */ 168 | public void setCid(String cid) { 169 | this.cid = cid; 170 | } 171 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/bo/UsersBO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo.bo; 2 | 3 | public class UsersBO { 4 | private String userId; 5 | private String faceData; 6 | private String nickname; 7 | 8 | public String getUserId() { 9 | return userId; 10 | } 11 | public void setUserId(String userId) { 12 | this.userId = userId; 13 | } 14 | public String getFaceData() { 15 | return faceData; 16 | } 17 | public void setFaceData(String faceData) { 18 | this.faceData = faceData; 19 | } 20 | public String getNickname() { 21 | return nickname; 22 | } 23 | public void setNickname(String nickname) { 24 | this.nickname = nickname; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/vo/FriendRequestVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo.vo; 2 | 3 | /** 4 | * @Description: 好友请求发送方的信息 5 | */ 6 | public class FriendRequestVO { 7 | 8 | private String sendUserId; 9 | private String sendUsername; 10 | private String sendFaceImage; 11 | private String sendNickname; 12 | 13 | public String getSendUserId() { 14 | return sendUserId; 15 | } 16 | public void setSendUserId(String sendUserId) { 17 | this.sendUserId = sendUserId; 18 | } 19 | public String getSendUsername() { 20 | return sendUsername; 21 | } 22 | public void setSendUsername(String sendUsername) { 23 | this.sendUsername = sendUsername; 24 | } 25 | public String getSendFaceImage() { 26 | return sendFaceImage; 27 | } 28 | public void setSendFaceImage(String sendFaceImage) { 29 | this.sendFaceImage = sendFaceImage; 30 | } 31 | public String getSendNickname() { 32 | return sendNickname; 33 | } 34 | public void setSendNickname(String sendNickname) { 35 | this.sendNickname = sendNickname; 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/vo/MyFriendsVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo.vo; 2 | 3 | public class MyFriendsVO { 4 | private String friendUserId; 5 | private String friendUsername; 6 | private String friendFaceImage; 7 | private String friendNickname; 8 | 9 | public String getFriendUserId() { 10 | return friendUserId; 11 | } 12 | public void setFriendUserId(String friendUserId) { 13 | this.friendUserId = friendUserId; 14 | } 15 | public String getFriendUsername() { 16 | return friendUsername; 17 | } 18 | public void setFriendUsername(String friendUsername) { 19 | this.friendUsername = friendUsername; 20 | } 21 | public String getFriendFaceImage() { 22 | return friendFaceImage; 23 | } 24 | public void setFriendFaceImage(String friendFaceImage) { 25 | this.friendFaceImage = friendFaceImage; 26 | } 27 | public String getFriendNickname() { 28 | return friendNickname; 29 | } 30 | public void setFriendNickname(String friendNickname) { 31 | this.friendNickname = friendNickname; 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/pojo/vo/UsersVO.java: -------------------------------------------------------------------------------- 1 | package com.imooc.pojo.vo; 2 | 3 | import java.util.List; 4 | 5 | public class UsersVO { 6 | private String id; 7 | private String username; 8 | private String faceImage; 9 | private String faceImageBig; 10 | private String nickname; 11 | private String qrcode; 12 | 13 | public String getId() { 14 | return id; 15 | } 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | public String getUsername() { 20 | return username; 21 | } 22 | public void setUsername(String username) { 23 | this.username = username; 24 | } 25 | public String getFaceImage() { 26 | return faceImage; 27 | } 28 | public void setFaceImage(String faceImage) { 29 | this.faceImage = faceImage; 30 | } 31 | public String getFaceImageBig() { 32 | return faceImageBig; 33 | } 34 | public void setFaceImageBig(String faceImageBig) { 35 | this.faceImageBig = faceImageBig; 36 | } 37 | public String getNickname() { 38 | return nickname; 39 | } 40 | public void setNickname(String nickname) { 41 | this.nickname = nickname; 42 | } 43 | public String getQrcode() { 44 | return qrcode; 45 | } 46 | public void setQrcode(String qrcode) { 47 | this.qrcode = qrcode; 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.service; 2 | 3 | import java.util.List; 4 | 5 | import com.imooc.netty.ChatMsg; 6 | import com.imooc.pojo.Users; 7 | import com.imooc.pojo.vo.FriendRequestVO; 8 | import com.imooc.pojo.vo.MyFriendsVO; 9 | 10 | public interface UserService { 11 | 12 | /** 13 | * @Description: 判断用户名是否存在 14 | */ 15 | public boolean queryUsernameIsExist(String username); 16 | 17 | /** 18 | * @Description: 查询用户是否存在 19 | */ 20 | public Users queryUserForLogin(String username, String pwd); 21 | 22 | /** 23 | * @Description: 用户注册 24 | */ 25 | public Users saveUser(Users user); 26 | 27 | /** 28 | * @Description: 修改用户记录 29 | */ 30 | public Users updateUserInfo(Users user); 31 | 32 | /** 33 | * @Description: 搜索朋友的前置条件 34 | */ 35 | public Integer preconditionSearchFriends(String myUserId, String friendUsername); 36 | 37 | /** 38 | * @Description: 根据用户名查询用户对象 39 | */ 40 | public Users queryUserInfoByUsername(String username); 41 | 42 | /** 43 | * @Description: 添加好友请求记录,保存到数据库 44 | */ 45 | public void sendFriendRequest(String myUserId, String friendUsername); 46 | 47 | /** 48 | * @Description: 查询好友请求 49 | */ 50 | public List queryFriendRequestList(String acceptUserId); 51 | 52 | /** 53 | * @Description: 删除好友请求记录 54 | */ 55 | public void deleteFriendRequest(String sendUserId, String acceptUserId); 56 | 57 | /** 58 | * @Description: 通过好友请求 59 | * 1. 保存好友 60 | * 2. 逆向保存好友 61 | * 3. 删除好友请求记录 62 | */ 63 | public void passFriendRequest(String sendUserId, String acceptUserId); 64 | 65 | /** 66 | * @Description: 查询好友列表 67 | */ 68 | public List queryMyFriends(String userId); 69 | 70 | /** 71 | * @Description: 保存聊天消息到数据库 72 | */ 73 | public String saveMsg(ChatMsg chatMsg); 74 | 75 | /** 76 | * @Description: 批量签收消息 77 | */ 78 | public void updateMsgSigned(List msgIdList); 79 | 80 | /** 81 | * @Description: 获取未签收消息列表 82 | */ 83 | public List getUnReadMsgList(String acceptUserId); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/utils/FastDFSClient.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.IOException; 5 | import java.nio.charset.Charset; 6 | 7 | import org.apache.commons.io.FilenameUtils; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.multipart.MultipartFile; 12 | 13 | import com.github.tobato.fastdfs.domain.StorePath; 14 | import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException; 15 | import com.github.tobato.fastdfs.service.FastFileStorageClient; 16 | 17 | @Component 18 | public class FastDFSClient { 19 | 20 | @Autowired 21 | private FastFileStorageClient storageClient; 22 | 23 | // @Autowired 24 | // private AppConfig appConfig; // 项目参数配置 25 | 26 | /** 27 | * 上传文件 28 | * 29 | * @param file 30 | * 文件对象 31 | * @return 文件访问地址 32 | * @throws IOException 33 | */ 34 | public String uploadFile(MultipartFile file) throws IOException { 35 | StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), 36 | FilenameUtils.getExtension(file.getOriginalFilename()), null); 37 | 38 | return storePath.getPath(); 39 | } 40 | 41 | public String uploadFile2(MultipartFile file) throws IOException { 42 | StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(), 43 | FilenameUtils.getExtension(file.getOriginalFilename()), null); 44 | 45 | return storePath.getPath(); 46 | } 47 | 48 | public String uploadQRCode(MultipartFile file) throws IOException { 49 | StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), 50 | "png", null); 51 | 52 | return storePath.getPath(); 53 | } 54 | 55 | public String uploadFace(MultipartFile file) throws IOException { 56 | StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(), 57 | "png", null); 58 | 59 | return storePath.getPath(); 60 | } 61 | 62 | public String uploadBase64(MultipartFile file) throws IOException { 63 | StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(), 64 | "png", null); 65 | 66 | return storePath.getPath(); 67 | } 68 | 69 | /** 70 | * 将一段字符串生成一个文件上传 71 | * 72 | * @param content 73 | * 文件内容 74 | * @param fileExtension 75 | * @return 76 | */ 77 | public String uploadFile(String content, String fileExtension) { 78 | byte[] buff = content.getBytes(Charset.forName("UTF-8")); 79 | ByteArrayInputStream stream = new ByteArrayInputStream(buff); 80 | StorePath storePath = storageClient.uploadFile(stream, buff.length, fileExtension, null); 81 | return storePath.getPath(); 82 | } 83 | 84 | // 封装图片完整URL地址 85 | // private String getResAccessUrl(StorePath storePath) { 86 | // String fileUrl = AppConstants.HTTP_PRODOCOL + appConfig.getResHost() + ":" + appConfig.getFdfsStoragePort() 87 | // + "/" + storePath.getFullPath(); 88 | // return fileUrl; 89 | // } 90 | 91 | /** 92 | * 删除文件 93 | * 94 | * @param fileUrl 95 | * 文件访问地址 96 | * @return 97 | */ 98 | public void deleteFile(String fileUrl) { 99 | if (StringUtils.isEmpty(fileUrl)) { 100 | return; 101 | } 102 | try { 103 | StorePath storePath = StorePath.praseFromUrl(fileUrl); 104 | storageClient.deleteFile(storePath.getGroup(), storePath.getPath()); 105 | } catch (FdfsUnsupportStorePathException e) { 106 | e.getMessage(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/utils/IMoocJSONResult.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | /** 4 | * @Description: 自定义响应数据结构 5 | * 这个类是提供给门户,ios,安卓,微信商城用的 6 | * 门户接受此类数据后需要使用本类的方法转换成对于的数据类型格式(类,或者list) 7 | * 其他自行处理 8 | * 200:表示成功 9 | * 500:表示错误,错误信息在msg字段中 10 | * 501:bean验证错误,不管多少个错误都以map形式返回 11 | * 502:拦截器拦截到用户token出错 12 | * 555:异常抛出信息 13 | */ 14 | public class IMoocJSONResult { 15 | 16 | // 响应业务状态 17 | private Integer status; 18 | 19 | // 响应消息 20 | private String msg; 21 | 22 | // 响应中的数据 23 | private Object data; 24 | 25 | private String ok; // 不使用 26 | 27 | public static IMoocJSONResult build(Integer status, String msg, Object data) { 28 | return new IMoocJSONResult(status, msg, data); 29 | } 30 | 31 | public static IMoocJSONResult ok(Object data) { 32 | return new IMoocJSONResult(data); 33 | } 34 | 35 | public static IMoocJSONResult ok() { 36 | return new IMoocJSONResult(null); 37 | } 38 | 39 | public static IMoocJSONResult errorMsg(String msg) { 40 | return new IMoocJSONResult(500, msg, null); 41 | } 42 | 43 | public static IMoocJSONResult errorMap(Object data) { 44 | return new IMoocJSONResult(501, "error", data); 45 | } 46 | 47 | public static IMoocJSONResult errorTokenMsg(String msg) { 48 | return new IMoocJSONResult(502, msg, null); 49 | } 50 | 51 | public static IMoocJSONResult errorException(String msg) { 52 | return new IMoocJSONResult(555, msg, null); 53 | } 54 | 55 | public IMoocJSONResult() { 56 | 57 | } 58 | 59 | // public static LeeJSONResult build(Integer status, String msg) { 60 | // return new LeeJSONResult(status, msg, null); 61 | // } 62 | 63 | public IMoocJSONResult(Integer status, String msg, Object data) { 64 | this.status = status; 65 | this.msg = msg; 66 | this.data = data; 67 | } 68 | 69 | public IMoocJSONResult(Object data) { 70 | this.status = 200; 71 | this.msg = "OK"; 72 | this.data = data; 73 | } 74 | 75 | public Boolean isOK() { 76 | return this.status == 200; 77 | } 78 | 79 | public Integer getStatus() { 80 | return status; 81 | } 82 | 83 | public void setStatus(Integer status) { 84 | this.status = status; 85 | } 86 | 87 | public String getMsg() { 88 | return msg; 89 | } 90 | 91 | public void setMsg(String msg) { 92 | this.msg = msg; 93 | } 94 | 95 | public Object getData() { 96 | return data; 97 | } 98 | 99 | public void setData(Object data) { 100 | this.data = data; 101 | } 102 | 103 | public String getOk() { 104 | return ok; 105 | } 106 | 107 | public void setOk(String ok) { 108 | this.ok = ok; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import java.util.List; 4 | 5 | import com.fasterxml.jackson.core.JsonProcessingException; 6 | import com.fasterxml.jackson.databind.JavaType; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | 9 | /** 10 | * @Description: 自定义响应结构, 转换类 11 | */ 12 | public class JsonUtils { 13 | 14 | // 定义jackson对象 15 | private static final ObjectMapper MAPPER = new ObjectMapper(); 16 | 17 | /** 18 | * 将对象转换成json字符串。 19 | *

Title: pojoToJson

20 | *

Description:

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

Title: jsonToList

54 | *

Description:

55 | * @param jsonData 56 | * @param beanType 57 | * @return 58 | */ 59 | public static List jsonToList(String jsonData, Class beanType) { 60 | JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); 61 | try { 62 | List list = MAPPER.readValue(jsonData, javaType); 63 | return list; 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | 68 | return null; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/utils/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import java.security.MessageDigest; 4 | import java.security.NoSuchAlgorithmException; 5 | 6 | import org.apache.commons.codec.binary.Base64; 7 | import org.apache.commons.codec.digest.Md5Crypt; 8 | 9 | public class MD5Utils { 10 | 11 | /** 12 | * @Description: 对字符串进行md5加密 13 | */ 14 | public static String getMD5Str(String strValue) throws Exception { 15 | MessageDigest md5 = MessageDigest.getInstance("MD5"); 16 | String newstr = Base64.encodeBase64String(md5.digest(strValue.getBytes())); 17 | return newstr; 18 | } 19 | 20 | public static void main(String[] args) { 21 | try { 22 | String md5 = getMD5Str("imooc"); 23 | System.out.println(md5); 24 | } catch (Exception e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/utils/MyMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2016 abel533@gmail.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.imooc.utils; 26 | 27 | import tk.mybatis.mapper.common.Mapper; 28 | import tk.mybatis.mapper.common.MySqlMapper; 29 | 30 | /** 31 | * 继承自己的MyMapper 32 | * 33 | * @author liuzh 34 | * @since 2015-09-06 21:53 35 | */ 36 | public interface MyMapper extends Mapper, MySqlMapper { 37 | //TODO 38 | //FIXME 特别注意,该接口不能被扫描到,否则会出错 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/utils/QRCodeUtils.java: -------------------------------------------------------------------------------- 1 | package com.imooc.utils; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.File; 5 | import java.nio.file.Path; 6 | import java.util.HashMap; 7 | 8 | import javax.imageio.ImageIO; 9 | 10 | import org.springframework.stereotype.Component; 11 | 12 | import com.google.zxing.BarcodeFormat; 13 | import com.google.zxing.BinaryBitmap; 14 | import com.google.zxing.EncodeHintType; 15 | import com.google.zxing.MultiFormatReader; 16 | import com.google.zxing.MultiFormatWriter; 17 | import com.google.zxing.Result; 18 | import com.google.zxing.client.j2se.BufferedImageLuminanceSource; 19 | import com.google.zxing.client.j2se.MatrixToImageWriter; 20 | import com.google.zxing.common.BitMatrix; 21 | import com.google.zxing.common.HybridBinarizer; 22 | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 23 | 24 | @Component 25 | public class QRCodeUtils { 26 | 27 | public void createQRCode(String filePath, String content) { 28 | int width=300; //图片的宽度 29 | int height=300; //图片的高度 30 | String format="png"; //图片的格式 31 | // String content="风间影月"; //内容 32 | 33 | /** 34 | * 定义二维码的参数 35 | */ 36 | HashMap hints=new HashMap(); 37 | hints.put(EncodeHintType.CHARACTER_SET,"utf-8"); //指定字符编码为“utf-8” 38 | hints.put(EncodeHintType.ERROR_CORRECTION,ErrorCorrectionLevel.M); //指定二维码的纠错等级为中级 39 | hints.put(EncodeHintType.MARGIN, 2); //设置图片的边距 40 | 41 | /** 42 | * 生成二维码 43 | */ 44 | try { 45 | BitMatrix bitMatrix=new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height,hints); 46 | Path file=new File(filePath).toPath(); 47 | MatrixToImageWriter.writeToPath(bitMatrix, format, file); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | 53 | public String getContentFromQRCode(String filePath) { 54 | MultiFormatReader formatReader=new MultiFormatReader(); 55 | File file=new File(filePath); 56 | BufferedImage image; 57 | try { 58 | image = ImageIO.read(file); 59 | BinaryBitmap binaryBitmap=new BinaryBitmap(new HybridBinarizer 60 | (new BufferedImageLuminanceSource(image))); 61 | HashMap hints=new HashMap(); 62 | hints.put(EncodeHintType.CHARACTER_SET,"utf-8"); //指定字符编码为“utf-8” 63 | Result result=formatReader.decode(binaryBitmap,hints); 64 | return result.toString(); 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | return null; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/Code.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DefaultRandomCodeStrategy; 4 | 5 | public class Code { 6 | private static RandomCodeStrategy strategy; 7 | 8 | static { 9 | RandomCodeStrategy strategy = new DefaultRandomCodeStrategy(); 10 | strategy.init(); 11 | configure(strategy); 12 | } 13 | 14 | public static synchronized void configure(RandomCodeStrategy custom) { 15 | if (strategy == custom) return; 16 | if (strategy != null) strategy.release(); 17 | 18 | strategy = custom; 19 | } 20 | 21 | /** 22 | * Next Unique code. 23 | * The max length will be 1024-Integer.MAX-Integer.MAX(2147483647) which has 4+10+10+2*1=26 characters. 24 | * The min length will be 0-0. 25 | * 26 | * @return unique string code. 27 | */ 28 | public static synchronized String next() { 29 | long workerId = Id.getWorkerId(); 30 | int prefix = strategy.prefix(); 31 | int next = strategy.next(); 32 | 33 | return String.format("%d-%03d-%06d", workerId, prefix, next); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/DayCode.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DayPrefixRandomCodeStrategy; 4 | 5 | public class DayCode { 6 | static RandomCodeStrategy strategy; 7 | 8 | static { 9 | DayPrefixRandomCodeStrategy dayPrefixCodeStrategy = new DayPrefixRandomCodeStrategy("yyMM"); 10 | dayPrefixCodeStrategy.setMinRandomSize(7); 11 | dayPrefixCodeStrategy.setMaxRandomSize(7); 12 | strategy = dayPrefixCodeStrategy; 13 | strategy.init(); 14 | } 15 | 16 | public static synchronized String next() { 17 | return String.format("%d-%04d-%07d", Id.getWorkerId(), strategy.prefix(), strategy.next()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/Id.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DefaultWorkerIdStrategy; 4 | 5 | public class Id { 6 | private static WorkerIdStrategy workerIdStrategy; 7 | private static IdWorker idWorker; 8 | 9 | static { 10 | configure(DefaultWorkerIdStrategy.instance); 11 | } 12 | 13 | public static synchronized void configure(WorkerIdStrategy custom) { 14 | if (workerIdStrategy == custom) return; 15 | 16 | if (workerIdStrategy != null) workerIdStrategy.release(); 17 | workerIdStrategy = custom; 18 | workerIdStrategy.initialize(); 19 | idWorker = new IdWorker(workerIdStrategy.availableWorkerId()); 20 | } 21 | 22 | public static long next() { 23 | return idWorker.nextId(); 24 | } 25 | 26 | public static long getWorkerId() { 27 | return idWorker.getWorkerId(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/IdWorker.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import java.security.SecureRandom; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class IdWorker { 9 | protected long epoch = 1288834974657L; 10 | // protected long epoch = 1387886498127L; // 2013-12-24 20:01:38.127 11 | 12 | 13 | protected long workerIdBits = 10L; 14 | protected long maxWorkerId = -1L ^ (-1L << workerIdBits); 15 | protected long sequenceBits = 11L; 16 | 17 | protected long workerIdShift = sequenceBits; 18 | protected long timestampLeftShift = sequenceBits + workerIdBits; 19 | protected long sequenceMask = -1L ^ (-1L << sequenceBits); 20 | 21 | protected long lastMillis = -1L; 22 | 23 | protected final long workerId; 24 | protected long sequence = 0L; 25 | protected Logger logger = LoggerFactory.getLogger(IdWorker.class); 26 | 27 | public IdWorker(long workerId) { 28 | this.workerId = checkWorkerId(workerId); 29 | 30 | logger.debug("worker starting. timestamp left shift {}, worker id {}", timestampLeftShift, workerId); 31 | } 32 | 33 | public long getEpoch() { 34 | return epoch; 35 | } 36 | 37 | private long checkWorkerId(long workerId) { 38 | // sanity check for workerId 39 | if (workerId > maxWorkerId || workerId < 0) { 40 | int rand = new SecureRandom().nextInt((int) maxWorkerId + 1); 41 | logger.warn("worker Id can't be greater than {} or less than 0, use a random {}", maxWorkerId, rand); 42 | return rand; 43 | } 44 | 45 | return workerId; 46 | } 47 | 48 | public synchronized long nextId() { 49 | long timestamp = millisGen(); 50 | 51 | if (timestamp < lastMillis) { 52 | logger.error("clock is moving backwards. Rejecting requests until {}.", lastMillis); 53 | throw new InvalidSystemClock(String.format( 54 | "Clock moved backwards. Refusing to generate id for {} milliseconds", lastMillis - timestamp)); 55 | } 56 | 57 | if (lastMillis == timestamp) { 58 | sequence = (sequence + 1) & sequenceMask; 59 | if (sequence == 0) 60 | timestamp = tilNextMillis(lastMillis); 61 | } else { 62 | sequence = 0; 63 | } 64 | 65 | lastMillis = timestamp; 66 | long diff = timestamp - getEpoch(); 67 | return (diff << timestampLeftShift) | 68 | (workerId << workerIdShift) | 69 | sequence; 70 | } 71 | 72 | protected long tilNextMillis(long lastMillis) { 73 | long millis = millisGen(); 74 | while (millis <= lastMillis) 75 | millis = millisGen(); 76 | 77 | return millis; 78 | } 79 | 80 | protected long millisGen() { 81 | return System.currentTimeMillis(); 82 | } 83 | 84 | public long getLastMillis() { 85 | return lastMillis; 86 | } 87 | 88 | public long getWorkerId() { 89 | return workerId; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/InvalidSystemClock.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public class InvalidSystemClock extends RuntimeException { 4 | public InvalidSystemClock(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/RandomCodeStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public interface RandomCodeStrategy { 4 | void init(); 5 | 6 | int prefix(); 7 | 8 | int next(); 9 | 10 | void release(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/Sid.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | import org.n3r.idworker.strategy.DefaultWorkerIdStrategy; 4 | import org.n3r.idworker.utils.Utils; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | @Component 11 | public class Sid { 12 | private static WorkerIdStrategy workerIdStrategy; 13 | private static IdWorker idWorker; 14 | 15 | static { 16 | configure(DefaultWorkerIdStrategy.instance); 17 | } 18 | 19 | 20 | public static synchronized void configure(WorkerIdStrategy custom) { 21 | if (workerIdStrategy != null) workerIdStrategy.release(); 22 | workerIdStrategy = custom; 23 | idWorker = new IdWorker(workerIdStrategy.availableWorkerId()) { 24 | @Override 25 | public long getEpoch() { 26 | return Utils.midnightMillis(); 27 | } 28 | }; 29 | } 30 | 31 | /** 32 | * 一天最大毫秒86400000,最大占用27比特 33 | * 27+10+11=48位 最大值281474976710655(15字),YK0XXHZ827(10字) 34 | * 6位(YYMMDD)+15位,共21位 35 | * 36 | * @return 固定21位数字字符串 37 | */ 38 | 39 | public static String next() { 40 | long id = idWorker.nextId(); 41 | String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); 42 | return yyMMdd + String.format("%014d", id); 43 | } 44 | 45 | 46 | /** 47 | * 返回固定16位的字母数字混编的字符串。 48 | */ 49 | public String nextShort() { 50 | long id = idWorker.nextId(); 51 | String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date()); 52 | return yyMMdd + Utils.padLeft(Utils.encode(id), 10, '0'); 53 | } 54 | 55 | // public static void main(String[] args) { 56 | // String aa = new Sid().nextShort(); 57 | // String bb = new Sid().next(); 58 | // 59 | // System.out.println(aa); 60 | // System.out.println(bb); 61 | // } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/Test.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public class Test { 4 | 5 | public static void main(String[] args) { 6 | 7 | for (int i = 0 ; i < 1000 ; i ++) { 8 | // System.out.println(Sid.nextShort()); 9 | } 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/WorkerIdStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker; 2 | 3 | public interface WorkerIdStrategy { 4 | void initialize(); 5 | 6 | long availableWorkerId(); 7 | 8 | void release(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/strategy/DayPrefixRandomCodeStrategy.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.strategy; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class DayPrefixRandomCodeStrategy extends DefaultRandomCodeStrategy { 7 | private final String dayFormat; 8 | private String lastDay; 9 | 10 | public DayPrefixRandomCodeStrategy(String dayFormat) { 11 | this.dayFormat = dayFormat; 12 | } 13 | 14 | @Override 15 | public void init() { 16 | String day = createDate(); 17 | if (day.equals(lastDay)) 18 | throw new RuntimeException("init failed for day unrolled"); 19 | 20 | lastDay = day; 21 | 22 | availableCodes.clear(); 23 | release(); 24 | 25 | prefixIndex = Integer.parseInt(lastDay); 26 | if (tryUsePrefix()) return; 27 | 28 | throw new RuntimeException("prefix is not available " + prefixIndex); 29 | } 30 | 31 | private String createDate() { 32 | return new SimpleDateFormat(dayFormat).format(new Date()); 33 | } 34 | 35 | @Override 36 | public int next() { 37 | if (!lastDay.equals(createDate())) init(); 38 | 39 | return super.next(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/strategy/FileLock.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.strategy; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.*; 8 | import java.nio.channels.Channels; 9 | import java.nio.channels.ClosedChannelException; 10 | import java.nio.channels.FileChannel; 11 | import java.nio.channels.OverlappingFileLockException; 12 | 13 | /** 14 | * A file lock a la flock/funlock 15 | *

16 | * The given path will be created and opened if it doesn't exist. 17 | */ 18 | public class FileLock { 19 | private final File file; 20 | private FileChannel channel; 21 | private java.nio.channels.FileLock flock = null; 22 | Logger logger = LoggerFactory.getLogger(FileLock.class); 23 | 24 | public FileLock(File file) { 25 | this.file = file; 26 | 27 | try { 28 | file.createNewFile(); // create the file if it doesn't exist 29 | channel = new RandomAccessFile(file, "rw").getChannel(); 30 | } catch (IOException e) { 31 | throw new RuntimeException(e); 32 | } 33 | } 34 | 35 | 36 | /** 37 | * Lock the file or throw an exception if the lock is already held 38 | */ 39 | public void lock() { 40 | try { 41 | synchronized (this) { 42 | logger.trace("Acquiring lock on {}", file.getAbsolutePath()); 43 | flock = channel.lock(); 44 | } 45 | } catch (IOException e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | 50 | /** 51 | * Try to lock the file and return true if the locking succeeds 52 | */ 53 | public boolean tryLock() { 54 | synchronized (this) { 55 | logger.trace("Acquiring lock on {}", file.getAbsolutePath()); 56 | try { 57 | // weirdly this method will return null if the lock is held by another 58 | // process, but will throw an exception if the lock is held by this process 59 | // so we have to handle both cases 60 | flock = channel.tryLock(); 61 | return flock != null; 62 | } catch (OverlappingFileLockException e) { 63 | return false; 64 | } catch (IOException e) { 65 | throw new RuntimeException(e); 66 | } 67 | } 68 | } 69 | 70 | /** 71 | * Unlock the lock if it is held 72 | */ 73 | public void unlock() { 74 | synchronized (this) { 75 | logger.trace("Releasing lock on {}", file.getAbsolutePath()); 76 | if (flock == null) return; 77 | try { 78 | flock.release(); 79 | } catch (ClosedChannelException e) { 80 | // Ignore 81 | } catch (IOException e) { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | } 86 | 87 | /** 88 | * Destroy this lock, closing the associated FileChannel 89 | */ 90 | public void destroy() { 91 | synchronized (this) { 92 | unlock(); 93 | if (!channel.isOpen()) return; 94 | 95 | try { 96 | channel.close(); 97 | } catch (IOException e) { 98 | throw new RuntimeException(e); 99 | } 100 | } 101 | } 102 | 103 | 104 | @SuppressWarnings("unchecked") 105 | public T readObject() { 106 | try { 107 | InputStream is = Channels.newInputStream(channel); 108 | ObjectInputStream objectReader = new ObjectInputStream(is); 109 | return (T) objectReader.readObject(); 110 | } catch (EOFException e) { 111 | } catch (Exception e) { 112 | throw new RuntimeException(e); 113 | } 114 | 115 | return null; 116 | } 117 | 118 | 119 | public synchronized boolean writeObject(Object object) { 120 | if (!channel.isOpen()) return false; 121 | 122 | try { 123 | channel.position(0); 124 | OutputStream out = Channels.newOutputStream(channel); 125 | ObjectOutputStream objectOutput = new ObjectOutputStream(out); 126 | objectOutput.writeObject(object); 127 | return true; 128 | } catch (Exception e) { 129 | throw new RuntimeException(e); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/utils/HttpReq.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.UnsupportedEncodingException; 10 | import java.net.*; 11 | 12 | public class HttpReq { 13 | private final String baseUrl; 14 | private String req; 15 | private StringBuilder params = new StringBuilder(); 16 | Logger logger = LoggerFactory.getLogger(HttpReq.class); 17 | 18 | public HttpReq(String baseUrl) { 19 | this.baseUrl = baseUrl; 20 | } 21 | 22 | public static HttpReq get(String baseUrl) { 23 | return new HttpReq(baseUrl); 24 | } 25 | 26 | public HttpReq req(String req) { 27 | this.req = req; 28 | return this; 29 | } 30 | 31 | public HttpReq param(String name, String value) { 32 | if (params.length() > 0) params.append('&'); 33 | try { 34 | params.append(name).append('=').append(URLEncoder.encode(value, "UTF-8")); 35 | } catch (UnsupportedEncodingException e) { 36 | throw new RuntimeException(e); 37 | } 38 | 39 | return this; 40 | } 41 | 42 | public String exec() { 43 | HttpURLConnection http = null; 44 | try { 45 | http = (HttpURLConnection) new URL(baseUrl 46 | + (req == null ? "" : req) 47 | + (params.length() > 0 ? ("?" + params) : "")).openConnection(); 48 | http.setRequestProperty("Accept-Charset", "UTF-8"); 49 | HttpURLConnection.setFollowRedirects(false); 50 | http.setConnectTimeout(5 * 1000); 51 | http.setReadTimeout(5 * 1000); 52 | http.connect(); 53 | 54 | int status = http.getResponseCode(); 55 | String charset = getCharset(http.getHeaderField("Content-Type")); 56 | 57 | if (status == 200) { 58 | return readResponseBody(http, charset); 59 | } else { 60 | logger.warn("non 200 respoonse :" + readErrorResponseBody(http, status, charset)); 61 | return null; 62 | } 63 | } catch (Exception e) { 64 | logger.error("exec error {}", e.getMessage()); 65 | return null; 66 | } finally { 67 | if (http != null) http.disconnect(); 68 | } 69 | 70 | } 71 | 72 | private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) throws IOException { 73 | InputStream errorStream = http.getErrorStream(); 74 | if (errorStream != null) { 75 | String error = toString(charset, errorStream); 76 | return ("STATUS CODE =" + status + "\n\n" + error); 77 | } else { 78 | return ("STATUS CODE =" + status); 79 | } 80 | } 81 | 82 | private static String readResponseBody(HttpURLConnection http, String charset) throws IOException { 83 | InputStream inputStream = http.getInputStream(); 84 | 85 | return toString(charset, inputStream); 86 | } 87 | 88 | private static String toString(String charset, InputStream inputStream) throws IOException { 89 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 90 | byte[] buffer = new byte[1024]; 91 | 92 | int length; 93 | while ((length = inputStream.read(buffer)) != -1) { 94 | baos.write(buffer, 0, length); 95 | } 96 | 97 | return new String(baos.toByteArray(), charset); 98 | } 99 | 100 | private static String getCharset(String contentType) { 101 | if (contentType == null) return "UTF-8"; 102 | 103 | String charset = null; 104 | for (String param : contentType.replace(" ", "").split(";")) { 105 | if (param.startsWith("charset=")) { 106 | charset = param.split("=", 2)[1]; 107 | break; 108 | } 109 | } 110 | 111 | return charset == null ? "UTF-8" : charset; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/utils/IPv4Utils.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | /** 4 | * This utility provides methods to either convert an IPv4 address to its long format or a 32bit dotted format. 5 | * 6 | * @author Aion 7 | * Created on 22/11/12 8 | */ 9 | public class IPv4Utils { 10 | 11 | /** 12 | * Returns the long format of the provided IP address. 13 | * 14 | * @param ipAddress the IP address 15 | * @return the long format of ipAddress 16 | * @throws IllegalArgumentException if ipAddress is invalid 17 | */ 18 | public static long toLong(String ipAddress) { 19 | if (ipAddress == null || ipAddress.isEmpty()) { 20 | throw new IllegalArgumentException("ip address cannot be null or empty"); 21 | } 22 | String[] octets = ipAddress.split(java.util.regex.Pattern.quote(".")); 23 | if (octets.length != 4) { 24 | throw new IllegalArgumentException("invalid ip address"); 25 | } 26 | long ip = 0; 27 | for (int i = 3; i >= 0; i--) { 28 | long octet = Long.parseLong(octets[3 - i]); 29 | if (octet > 255 || octet < 0) { 30 | throw new IllegalArgumentException("invalid ip address"); 31 | } 32 | ip |= octet << (i * 8); 33 | } 34 | return ip; 35 | } 36 | 37 | /** 38 | * Returns the 32bit dotted format of the provided long ip. 39 | * 40 | * @param ip the long ip 41 | * @return the 32bit dotted format of ip 42 | * @throws IllegalArgumentException if ip is invalid 43 | */ 44 | public static String toString(long ip) { 45 | // if ip is bigger than 255.255.255.255 or smaller than 0.0.0.0 46 | if (ip > 4294967295l || ip < 0) { 47 | throw new IllegalArgumentException("invalid ip"); 48 | } 49 | StringBuilder ipAddress = new StringBuilder(); 50 | for (int i = 3; i >= 0; i--) { 51 | int shift = i * 8; 52 | ipAddress.append((ip & (0xff << shift)) >> shift); 53 | if (i > 0) { 54 | ipAddress.append("."); 55 | } 56 | } 57 | return ipAddress.toString(); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/utils/Ip.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.net.Inet4Address; 8 | import java.net.InetAddress; 9 | import java.net.NetworkInterface; 10 | import java.net.SocketException; 11 | import java.util.Enumeration; 12 | 13 | public class Ip { 14 | static Logger logger = LoggerFactory.getLogger(Ip.class); 15 | 16 | public static String ip; 17 | public static long lip; 18 | 19 | static { 20 | try { 21 | InetAddress localHostLANAddress = getFirstNonLoopbackAddress(); 22 | ip = localHostLANAddress.getHostAddress(); 23 | 24 | byte[] address = localHostLANAddress.getAddress(); 25 | lip = ((address [0] & 0xFFL) << (3*8)) + 26 | ((address [1] & 0xFFL) << (2*8)) + 27 | ((address [2] & 0xFFL) << (1*8)) + 28 | (address [3] & 0xFFL); 29 | } catch (Exception e) { 30 | logger.error("get ipv4 failed ", e); 31 | } 32 | } 33 | 34 | private static InetAddress getFirstNonLoopbackAddress() throws SocketException { 35 | Enumeration en = NetworkInterface.getNetworkInterfaces(); 36 | while (en.hasMoreElements()) { 37 | NetworkInterface i = (NetworkInterface) en.nextElement(); 38 | for (Enumeration en2 = i.getInetAddresses(); en2.hasMoreElements(); ) { 39 | InetAddress addr = (InetAddress) en2.nextElement(); 40 | if (addr.isLoopbackAddress()) continue; 41 | 42 | if (addr instanceof Inet4Address) { 43 | return addr; 44 | } 45 | } 46 | } 47 | return null; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/utils/Props.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.*; 7 | import java.util.Properties; 8 | 9 | import static java.io.File.separator; 10 | import static org.n3r.idworker.utils.Serializes.closeQuietly; 11 | 12 | public class Props { 13 | static Logger log = LoggerFactory.getLogger(Props.class); 14 | 15 | public static Properties tryProperties(String propertiesFileName, String userHomeBasePath) { 16 | Properties properties = new Properties(); 17 | InputStream is = null; 18 | try { 19 | is = Props.tryResource(propertiesFileName, userHomeBasePath, Silent.ON); 20 | if (is != null) properties.load(is); 21 | } catch (IOException e) { 22 | log.error("load properties error: {}", e.getMessage()); 23 | } finally { 24 | closeQuietly(is); 25 | } 26 | 27 | return properties; 28 | } 29 | 30 | 31 | enum Silent {ON, OFF} 32 | 33 | public static InputStream tryResource(String propertiesFileName, String userHomeBasePath, Silent silent) { 34 | InputStream is = currentDirResource(new File(propertiesFileName)); 35 | if (is != null) return is; 36 | 37 | is = userHomeResource(propertiesFileName, userHomeBasePath); 38 | if (is != null) return is; 39 | 40 | is = classpathResource(propertiesFileName); 41 | if (is != null || silent == Silent.ON) return is; 42 | 43 | throw new RuntimeException("fail to find " + propertiesFileName + " in current dir or classpath"); 44 | } 45 | 46 | private static InputStream userHomeResource(String pathname, String appHome) { 47 | String filePath = System.getProperty("user.home") + separator + appHome; 48 | File dir = new File(filePath); 49 | if (!dir.exists()) return null; 50 | 51 | return currentDirResource(new File(dir, pathname)); 52 | } 53 | 54 | private static InputStream currentDirResource(File file) { 55 | if (!file.exists()) return null; 56 | 57 | try { 58 | return new FileInputStream(file); 59 | } catch (FileNotFoundException e) { 60 | // This should not happened 61 | log.error("read file {} error", file, e); 62 | return null; 63 | } 64 | } 65 | 66 | public static InputStream classpathResource(String resourceName) { 67 | return Props.class.getClassLoader().getResourceAsStream(resourceName); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/utils/Serializes.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import java.io.*; 4 | import java.nio.channels.FileChannel; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class Serializes { 9 | 10 | @SuppressWarnings("unchecked") 11 | public static List readObjects(File file) { 12 | ArrayList objects = new ArrayList(); 13 | ObjectInputStream objectReader = null; 14 | FileInputStream fis = null; 15 | try { 16 | fis = new FileInputStream(file); 17 | objectReader = new ObjectInputStream(fis); 18 | while (true) 19 | objects.add((T) objectReader.readObject()); 20 | 21 | } catch (EOFException e) { 22 | } catch (Exception e) { 23 | throw new RuntimeException(e); 24 | } finally { 25 | closeQuietly(objectReader); 26 | closeQuietly(fis); 27 | } 28 | 29 | return objects; 30 | } 31 | 32 | 33 | @SuppressWarnings("unchecked") 34 | public static T readObject(File file) { 35 | ObjectInputStream objectReader = null; 36 | FileInputStream fis = null; 37 | try { 38 | fis = new FileInputStream(file); 39 | objectReader = new ObjectInputStream(fis); 40 | return (T) objectReader.readObject(); 41 | 42 | } catch (EOFException e) { 43 | } catch (Exception e) { 44 | throw new RuntimeException(e); 45 | } finally { 46 | closeQuietly(objectReader); 47 | closeQuietly(fis); 48 | } 49 | 50 | return null; 51 | } 52 | 53 | public static void writeObject(File file, Object object) { 54 | ObjectOutputStream objectOutput = null; 55 | FileOutputStream fos = null; 56 | try { 57 | fos = new FileOutputStream(file); 58 | objectOutput = new ObjectOutputStream(fos); 59 | objectOutput.writeObject(object); 60 | } catch (Exception e) { 61 | throw new RuntimeException(e); 62 | } finally { 63 | closeQuietly(objectOutput); 64 | closeQuietly(fos); 65 | } 66 | } 67 | 68 | public static void writeObject(FileOutputStream fos, Object object) { 69 | FileChannel channel = fos.getChannel(); 70 | if (!channel.isOpen()) throw new RuntimeException("channel is closed"); 71 | 72 | try { 73 | channel.position(0); 74 | ObjectOutputStream objectOutput = new ObjectOutputStream(fos); 75 | objectOutput.writeObject(object); 76 | fos.flush(); 77 | } catch (Exception e) { 78 | throw new RuntimeException(e); 79 | } finally { 80 | } 81 | } 82 | 83 | public static void writeObjects(File file, Object... objects) { 84 | ObjectOutputStream objectOutput = null; 85 | FileOutputStream fos = null; 86 | try { 87 | fos = new FileOutputStream(file); 88 | objectOutput = new ObjectOutputStream(fos); 89 | 90 | for (Object object : objects) 91 | objectOutput.writeObject(object); 92 | } catch (Exception e) { 93 | throw new RuntimeException(e); 94 | } finally { 95 | closeQuietly(objectOutput); 96 | closeQuietly(fos); 97 | } 98 | 99 | } 100 | 101 | public static void closeQuietly(OutputStream os) { 102 | if (os != null) try { 103 | os.close(); 104 | } catch (IOException e) { 105 | // ignore 106 | } 107 | } 108 | 109 | 110 | public static void closeQuietly(InputStream is) { 111 | if (is != null) try { 112 | is.close(); 113 | } catch (IOException e) { 114 | // ignore 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/org/n3r/idworker/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package org.n3r.idworker.utils; 2 | 3 | import java.io.*; 4 | import java.sql.Timestamp; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Calendar; 7 | 8 | public class Utils { 9 | 10 | public static final String DOT_IDWORKERS = ".idworkers"; 11 | 12 | public static ClassLoader getClassLoader() { 13 | ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 14 | return contextClassLoader != null ? contextClassLoader : Utils.class.getClassLoader(); 15 | } 16 | 17 | 18 | public static InputStream classResourceToStream(String resourceName) { 19 | return getClassLoader().getResourceAsStream(resourceName); 20 | } 21 | 22 | 23 | public static String firstLine(String classResourceName) { 24 | InputStream inputStream = null; 25 | try { 26 | inputStream = classResourceToStream(classResourceName); 27 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 28 | 29 | return bufferedReader.readLine(); 30 | } catch (IOException e) { 31 | return null; 32 | } finally { 33 | if (inputStream != null) try { 34 | inputStream.close(); 35 | } catch (IOException e) { 36 | // ignore 37 | } 38 | } 39 | } 40 | 41 | public static String checkNotEmpty(String param, String name) { 42 | if (param == null || param.isEmpty()) 43 | throw new IllegalArgumentException(name + " is empty"); 44 | 45 | return param; 46 | } 47 | 48 | 49 | public static long midnightMillis() { 50 | // today 51 | Calendar date = Calendar.getInstance(); 52 | // reset hour, minutes, seconds and millis 53 | date.set(Calendar.HOUR_OF_DAY, 0); 54 | date.set(Calendar.MINUTE, 0); 55 | date.set(Calendar.SECOND, 0); 56 | date.set(Calendar.MILLISECOND, 0); 57 | 58 | return date.getTimeInMillis(); 59 | } 60 | 61 | public static void main(String[] args) { 62 | // 2013-12-25 00:00:00.000 63 | System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Timestamp(midnightMillis()))); 64 | System.out.println(encode(281474976710655L)); 65 | } 66 | 67 | public static long decode(String s, String symbols) { 68 | final int B = symbols.length(); 69 | long num = 0; 70 | for (char ch : s.toCharArray()) { 71 | num *= B; 72 | num += symbols.indexOf(ch); 73 | } 74 | return num; 75 | } 76 | 77 | public static String encode(long num) { 78 | return encode(num, defaultRange); 79 | } 80 | 81 | public static String encode(long num, String symbols) { 82 | final int B = symbols.length(); 83 | StringBuilder sb = new StringBuilder(); 84 | while (num != 0) { 85 | sb.append(symbols.charAt((int) (num % B))); 86 | num /= B; 87 | } 88 | return sb.reverse().toString(); 89 | } 90 | 91 | // all un-clearly-recognized letters are skiped. 92 | static String defaultRange = "0123456789ABCDFGHKMNPRSTWXYZ"; 93 | 94 | public static String padLeft(String str, int size, char padChar) { 95 | if (str.length() >= size) return str; 96 | 97 | StringBuilder s = new StringBuilder(); 98 | for (int i = size - str.length(); i > 0; --i) { 99 | s.append(padChar); 100 | } 101 | s.append(str); 102 | 103 | return s.toString(); 104 | } 105 | 106 | public static File createIdWorkerHome() { 107 | String userHome = System.getProperty("user.home"); 108 | File idWorkerHome = new File(userHome + File.separator + DOT_IDWORKERS); 109 | idWorkerHome.mkdirs(); 110 | if (idWorkerHome.isDirectory()) return idWorkerHome; 111 | 112 | throw new RuntimeException("failed to create .idworkers at user home"); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | fdfs.soTimeout=1501 2 | fdfs.connectTimeout=601 3 | fdfs.thumbImage.width=80 4 | fdfs.thumbImage.height=80 5 | fdfs.trackerList[0]=192.168.0.110:22122 6 | 7 | ############################################################ 8 | # 9 | # \u914d\u7f6e\u6570\u636e\u6e90\u76f8\u5173 \u4f7f\u7528 HikariCP \u6570\u636e\u6e90 10 | # 11 | ############################################################ 12 | # jdbc_config datasource 13 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 14 | spring.datasource.url=jdbc:mysql://localhost:3306/zhuxin-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true 15 | spring.datasource.username=root 16 | spring.datasource.password=zhu1998 17 | # Hikari will use the above plus the following to setup connection pooling 18 | spring.datasource.type=com.zaxxer.hikari.HikariDataSource 19 | # # \u7b49\u5f85\u8fde\u63a5\u6c60\u5206\u914d\u8fde\u63a5\u7684\u6700\u5927\u65f6\u957f\uff08\u6beb\u79d2\uff09\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u65f6\u957f\u8fd8\u6ca1\u53ef\u7528\u7684\u8fde\u63a5\u5219\u53d1\u751fSQLException\uff0c \u9ed8\u8ba4:30\u79d2 20 | spring.datasource.hikari.connection-timeout=30000 21 | # \u6700\u5c0f\u8fde\u63a5\u6570 22 | spring.datasource.hikari.minimum-idle=5 23 | # \u6700\u5927\u8fde\u63a5\u6570 24 | spring.datasource.hikari.maximum-pool-size=15 25 | # \u81ea\u52a8\u63d0\u4ea4 26 | spring.datasource.hikari.auto-commit=true 27 | # \u4e00\u4e2a\u8fde\u63a5idle\u72b6\u6001\u7684\u6700\u5927\u65f6\u957f\uff08\u6beb\u79d2\uff09\uff0c\u8d85\u65f6\u5219\u88ab\u91ca\u653e\uff08retired\uff09\uff0c\u9ed8\u8ba4:10\u5206\u949f 28 | spring.datasource.hikari.idle-timeout=600000 29 | # \u8fde\u63a5\u6c60\u540d\u5b57 30 | spring.datasource.hikari.pool-name=DatebookHikariCP 31 | # \u4e00\u4e2a\u8fde\u63a5\u7684\u751f\u547d\u65f6\u957f\uff08\u6beb\u79d2\uff09\uff0c\u8d85\u65f6\u800c\u4e14\u6ca1\u88ab\u4f7f\u7528\u5219\u88ab\u91ca\u653e\uff08retired\uff09\uff0c\u9ed8\u8ba4:30\u5206\u949f 1800000ms\uff0c\u5efa\u8bae\u8bbe\u7f6e\u6bd4\u6570\u636e\u5e93\u8d85\u65f6\u65f6\u957f\u5c1160\u79d2\uff0c\u53c2\u8003MySQL wait_timeout\u53c2\u6570\uff08show variables like '%timeout%';\uff09 --> 32 | spring.datasource.hikari.max-lifetime=28740000 33 | spring.datasource.hikari.connection-test-query=SELECT 1 34 | 35 | spring.devtools.restart.enabled=true 36 | spring.devtools.restart.exclude: WEB-INF/** 37 | 38 | ############################################################ 39 | # 40 | # mybatis \u914d\u7f6e 41 | # 42 | ############################################################ 43 | # mybatis \u914d\u7f6e 44 | mybatis.type-aliases-package=com.imooc.pojo 45 | mybatis.mapper-locations=classpath:mapper/*.xml 46 | # \u901a\u7528 Mapper \u914d\u7f6e 47 | mapper.mappers=com.imooc.utils.MyMapper 48 | mapper.not-empty=false 49 | mapper.identity=MYSQL 50 | # \u5206\u9875\u63d2\u4ef6\u914d\u7f6e 51 | pagehelper.helperDialect=mysql 52 | #pagehelper.reasonable=true 53 | pagehelper.supportMethodsArguments=true 54 | pagehelper.params=count=countSql 55 | 56 | ############################################################ 57 | # 58 | # Server \u670d\u52a1\u7aef\u76f8\u5173\u914d\u7f6e 59 | # 60 | ############################################################ 61 | # \u914d\u7f6eapi\u7aef\u53e3\u53f7 62 | server.port=8080 63 | 64 | 65 | ############################################################ 66 | # Server - tomcat \u76f8\u5173\u5e38\u7528\u914d\u7f6e 67 | ############################################################ 68 | server.tomcat.uri-encoding=UTF-8 -------------------------------------------------------------------------------- /src/main/resources/mapper/ChatMsgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/mapper/FriendsRequestMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/mapper/MyFriendsMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/mapper/UsersMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/mapper/UsersMapperCustom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 40 | 41 | 42 | 43 | 44 | update chat_msg set sign_flag = 1 where id in 45 | 46 | #{item} 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /target/classes/application.properties: -------------------------------------------------------------------------------- 1 | fdfs.soTimeout=1501 2 | fdfs.connectTimeout=601 3 | fdfs.thumbImage.width=80 4 | fdfs.thumbImage.height=80 5 | fdfs.trackerList[0]=192.168.0.110:22122 6 | 7 | ############################################################ 8 | # 9 | # \u914d\u7f6e\u6570\u636e\u6e90\u76f8\u5173 \u4f7f\u7528 HikariCP \u6570\u636e\u6e90 10 | # 11 | ############################################################ 12 | # jdbc_config datasource 13 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 14 | spring.datasource.url=jdbc:mysql://localhost:3306/zhuxin-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true 15 | spring.datasource.username=root 16 | spring.datasource.password=zhu1998 17 | # Hikari will use the above plus the following to setup connection pooling 18 | spring.datasource.type=com.zaxxer.hikari.HikariDataSource 19 | # # \u7b49\u5f85\u8fde\u63a5\u6c60\u5206\u914d\u8fde\u63a5\u7684\u6700\u5927\u65f6\u957f\uff08\u6beb\u79d2\uff09\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u65f6\u957f\u8fd8\u6ca1\u53ef\u7528\u7684\u8fde\u63a5\u5219\u53d1\u751fSQLException\uff0c \u9ed8\u8ba4:30\u79d2 20 | spring.datasource.hikari.connection-timeout=30000 21 | # \u6700\u5c0f\u8fde\u63a5\u6570 22 | spring.datasource.hikari.minimum-idle=5 23 | # \u6700\u5927\u8fde\u63a5\u6570 24 | spring.datasource.hikari.maximum-pool-size=15 25 | # \u81ea\u52a8\u63d0\u4ea4 26 | spring.datasource.hikari.auto-commit=true 27 | # \u4e00\u4e2a\u8fde\u63a5idle\u72b6\u6001\u7684\u6700\u5927\u65f6\u957f\uff08\u6beb\u79d2\uff09\uff0c\u8d85\u65f6\u5219\u88ab\u91ca\u653e\uff08retired\uff09\uff0c\u9ed8\u8ba4:10\u5206\u949f 28 | spring.datasource.hikari.idle-timeout=600000 29 | # \u8fde\u63a5\u6c60\u540d\u5b57 30 | spring.datasource.hikari.pool-name=DatebookHikariCP 31 | # \u4e00\u4e2a\u8fde\u63a5\u7684\u751f\u547d\u65f6\u957f\uff08\u6beb\u79d2\uff09\uff0c\u8d85\u65f6\u800c\u4e14\u6ca1\u88ab\u4f7f\u7528\u5219\u88ab\u91ca\u653e\uff08retired\uff09\uff0c\u9ed8\u8ba4:30\u5206\u949f 1800000ms\uff0c\u5efa\u8bae\u8bbe\u7f6e\u6bd4\u6570\u636e\u5e93\u8d85\u65f6\u65f6\u957f\u5c1160\u79d2\uff0c\u53c2\u8003MySQL wait_timeout\u53c2\u6570\uff08show variables like '%timeout%';\uff09 --> 32 | spring.datasource.hikari.max-lifetime=28740000 33 | spring.datasource.hikari.connection-test-query=SELECT 1 34 | 35 | spring.devtools.restart.enabled=true 36 | spring.devtools.restart.exclude: WEB-INF/** 37 | 38 | ############################################################ 39 | # 40 | # mybatis \u914d\u7f6e 41 | # 42 | ############################################################ 43 | # mybatis \u914d\u7f6e 44 | mybatis.type-aliases-package=com.imooc.pojo 45 | mybatis.mapper-locations=classpath:mapper/*.xml 46 | # \u901a\u7528 Mapper \u914d\u7f6e 47 | mapper.mappers=com.imooc.utils.MyMapper 48 | mapper.not-empty=false 49 | mapper.identity=MYSQL 50 | # \u5206\u9875\u63d2\u4ef6\u914d\u7f6e 51 | pagehelper.helperDialect=mysql 52 | #pagehelper.reasonable=true 53 | pagehelper.supportMethodsArguments=true 54 | pagehelper.params=count=countSql 55 | 56 | ############################################################ 57 | # 58 | # Server \u670d\u52a1\u7aef\u76f8\u5173\u914d\u7f6e 59 | # 60 | ############################################################ 61 | # \u914d\u7f6eapi\u7aef\u53e3\u53f7 62 | server.port=8080 63 | 64 | 65 | ############################################################ 66 | # Server - tomcat \u76f8\u5173\u5e38\u7528\u914d\u7f6e 67 | ############################################################ 68 | server.tomcat.uri-encoding=UTF-8 -------------------------------------------------------------------------------- /target/classes/com/imooc/Application.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/Application.class -------------------------------------------------------------------------------- /target/classes/com/imooc/FastdfsImporter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/FastdfsImporter.class -------------------------------------------------------------------------------- /target/classes/com/imooc/NettyBooter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/NettyBooter.class -------------------------------------------------------------------------------- /target/classes/com/imooc/SpringUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/SpringUtil.class -------------------------------------------------------------------------------- /target/classes/com/imooc/controller/UserController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/controller/UserController.class -------------------------------------------------------------------------------- /target/classes/com/imooc/enums/MsgActionEnum.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/enums/MsgActionEnum.class -------------------------------------------------------------------------------- /target/classes/com/imooc/enums/MsgSignFlagEnum.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/enums/MsgSignFlagEnum.class -------------------------------------------------------------------------------- /target/classes/com/imooc/enums/OperatorFriendRequestTypeEnum.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/enums/OperatorFriendRequestTypeEnum.class -------------------------------------------------------------------------------- /target/classes/com/imooc/enums/SearchFriendsStatusEnum.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/enums/SearchFriendsStatusEnum.class -------------------------------------------------------------------------------- /target/classes/com/imooc/mapper/ChatMsgMapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/mapper/ChatMsgMapper.class -------------------------------------------------------------------------------- /target/classes/com/imooc/mapper/FriendsRequestMapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/mapper/FriendsRequestMapper.class -------------------------------------------------------------------------------- /target/classes/com/imooc/mapper/MyFriendsMapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/mapper/MyFriendsMapper.class -------------------------------------------------------------------------------- /target/classes/com/imooc/mapper/UsersMapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/mapper/UsersMapper.class -------------------------------------------------------------------------------- /target/classes/com/imooc/mapper/UsersMapperCustom.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/mapper/UsersMapperCustom.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/ChatHandler.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/ChatHandler.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/ChatMsg.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/ChatMsg.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/DataContent.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/DataContent.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/HeartBeatHandler.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/HeartBeatHandler.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/UserChannelRel.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/UserChannelRel.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/WSServer$SingletionWSServer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/WSServer$SingletionWSServer.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/WSServer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/WSServer.class -------------------------------------------------------------------------------- /target/classes/com/imooc/netty/WSServerInitialzer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/netty/WSServerInitialzer.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/ChatMsg.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/ChatMsg.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/FriendsRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/FriendsRequest.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/MyFriends.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/MyFriends.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/Users.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/Users.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/bo/UsersBO.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/bo/UsersBO.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/vo/FriendRequestVO.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/vo/FriendRequestVO.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/vo/MyFriendsVO.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/vo/MyFriendsVO.class -------------------------------------------------------------------------------- /target/classes/com/imooc/pojo/vo/UsersVO.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/pojo/vo/UsersVO.class -------------------------------------------------------------------------------- /target/classes/com/imooc/service/UserService.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/service/UserService.class -------------------------------------------------------------------------------- /target/classes/com/imooc/service/impl/UserServiceImpl.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/service/impl/UserServiceImpl.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/FastDFSClient.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/FastDFSClient.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/FileUtils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/FileUtils.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/IMoocJSONResult.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/IMoocJSONResult.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/JsonUtils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/JsonUtils.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/MD5Utils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/MD5Utils.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/MyMapper.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/MyMapper.class -------------------------------------------------------------------------------- /target/classes/com/imooc/utils/QRCodeUtils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/com/imooc/utils/QRCodeUtils.class -------------------------------------------------------------------------------- /target/classes/mapper/ChatMsgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /target/classes/mapper/FriendsRequestMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /target/classes/mapper/MyFriendsMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /target/classes/mapper/UsersMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /target/classes/mapper/UsersMapperCustom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 40 | 41 | 42 | 43 | 44 | update chat_msg set sign_flag = 1 where id in 45 | 46 | #{item} 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/Code.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/Code.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/DayCode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/DayCode.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/Id.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/Id.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/IdWorker.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/IdWorker.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/InvalidSystemClock.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/InvalidSystemClock.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/RandomCodeStrategy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/RandomCodeStrategy.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/Sid$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/Sid$1.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/Sid.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/Sid.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/Test.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/Test.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/WorkerIdStrategy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/WorkerIdStrategy.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/DayPrefixRandomCodeStrategy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/DayPrefixRandomCodeStrategy.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/DefaultRandomCodeStrategy$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/DefaultRandomCodeStrategy$1.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/DefaultRandomCodeStrategy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/DefaultRandomCodeStrategy.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/DefaultWorkerIdStrategy$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/DefaultWorkerIdStrategy$1.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/DefaultWorkerIdStrategy$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/DefaultWorkerIdStrategy$2.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/DefaultWorkerIdStrategy.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/DefaultWorkerIdStrategy.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/strategy/FileLock.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/strategy/FileLock.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/HttpReq.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/HttpReq.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/IPv4Utils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/IPv4Utils.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/Ip.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/Ip.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/Props$Silent.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/Props$Silent.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/Props.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/Props.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/Serializes.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/Serializes.class -------------------------------------------------------------------------------- /target/classes/org/n3r/idworker/utils/Utils.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/target/classes/org/n3r/idworker/utils/Utils.class -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | imooc-muxin 4 | Create By HBuilder 5 | 6 | 7 | 8 | 9 | com.pandora.projects.ui.MKeyBuilder 10 | 11 | 12 | 13 | 14 | com.aptana.ide.core.unifiedBuilder 15 | 16 | 17 | 18 | 19 | 20 | com.pandora.projects.ui.MKeyNature 21 | com.aptana.projects.webnature 22 | 23 | 24 | 25 | 1530889416413 26 | 27 | 10 28 | 29 | org.eclipse.ui.ide.orFilterMatcher 30 | 31 | 32 | org.eclipse.ui.ide.multiFilter 33 | 1.0-projectRelativePath-matches-false-false-bin 34 | 35 | 36 | org.eclipse.ui.ide.multiFilter 37 | 1.0-projectRelativePath-matches-false-false-setting 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/css/chat.css: -------------------------------------------------------------------------------- 1 | /*图片气泡*/ 2 | .friend_lists { 3 | margin: 0 50px 0px 10px; 4 | position: relative; 5 | } 6 | 7 | .friend_lists .header_img { 8 | position: absolute; 9 | top: 5px; 10 | } 11 | 12 | .me_lists { 13 | position: relative; 14 | margin: 0 10px 0px 50px; 15 | } 16 | 17 | .me_lists .msg { 18 | float: right; 19 | margin-right: 73px; 20 | } 21 | 22 | .me_lists .header_img { 23 | position: absolute; 24 | top: 5px; 25 | right: 0px; 26 | } 27 | 28 | 29 | /*背景气泡*/ 30 | .msg-left-white { 31 | background-color: #FFFFFF; 32 | font-size: 16px; 33 | } 34 | 35 | .msg-right-green { 36 | background-color: #a0e759; 37 | font-size: 16px; 38 | } 39 | 40 | .msg-wrapper p { 41 | color: black; 42 | display: inline-block; 43 | padding: 12px; 44 | margin: 10px; 45 | position: relative; 46 | border-radius: 5px; 47 | } 48 | 49 | .msg-wrapper.right p { 50 | margin-left: 60px; 51 | } 52 | 53 | .msg-wrapper.right p:before { 54 | width: 0; 55 | position: absolute; 56 | top: 15px; 57 | border-style: solid; 58 | content: ""; 59 | } 60 | 61 | .msg-wrapper.right p:before { 62 | left: -12px; 63 | border-color: transparent #FFFFFF; 64 | border-width: 0 12px 12px 0; 65 | } 66 | 67 | .msg-wrapper.left p:before { 68 | width: 0; 69 | position: absolute; 70 | top: 15px; 71 | border-style: solid; 72 | content: ""; 73 | } 74 | 75 | .msg-wrapper.left p { 76 | margin-right: 60px; 77 | } 78 | 79 | .msg-wrapper.left { 80 | text-align: right; 81 | } 82 | 83 | .text-left { 84 | text-align: left; 85 | } 86 | 87 | .msg-wrapper.left p:before { 88 | right: -12px; 89 | border-color: transparent #a0e759; 90 | border-width: 0 0 12px 12px; 91 | } 92 | 93 | .cur_time { 94 | text-align: center; 95 | width: 100%; 96 | margin-top: 10px; 97 | } 98 | 99 | .cur_time span { 100 | width: auto; 101 | display: inline-block; 102 | padding: 2px 10px; 103 | font-size: 14px; 104 | border-radius: 3px; 105 | background: #CECECE; 106 | color: white; 107 | } 108 | 109 | footer { 110 | position: fixed; 111 | width: 100%; 112 | height: 50px; 113 | min-height: 50px; 114 | border-top: solid 1px #bbb; 115 | left: 0px; 116 | bottom: 0px; 117 | overflow: hidden; 118 | padding: 0px 65px 0 10px; 119 | background-color: #fafafa; 120 | } 121 | 122 | .footer-left { 123 | position: absolute; 124 | width: 50px; 125 | height: 50px; 126 | left: 0px; 127 | bottom: 0px; 128 | text-align: center; 129 | vertical-align: middle; 130 | line-height: 100%; 131 | padding: 12px 4px; 132 | } 133 | 134 | .footer-right { 135 | position: absolute; 136 | width: 60px; 137 | height: 50px; 138 | right: 0px; 139 | bottom: 0px; 140 | text-align: center; 141 | vertical-align: middle; 142 | line-height: 100%; 143 | padding: 8px 15px 0 0; 144 | display: inline-block; 145 | } 146 | 147 | .footer-center { 148 | height: 100%; 149 | padding: 5px 0px; 150 | } 151 | 152 | .footer-center [class*=input] { 153 | width: 100%; 154 | height: 100%; 155 | border-radius: 5px; 156 | } 157 | 158 | .footer-center .input-text { 159 | background: #fff; 160 | border: solid 1px #ddd; 161 | padding: 10px !important; 162 | font-size: 16px !important; 163 | line-height: 18px !important; 164 | font-family: verdana !important; 165 | overflow: hidden; 166 | } 167 | 168 | .footer-center .input-sound { 169 | background-color: #eee; 170 | } 171 | 172 | .mui-content { 173 | height: 100%; 174 | padding: 0px 0px 50px 0px; 175 | overflow: auto; 176 | background-color: #eaeaea; 177 | } 178 | 179 | #msg { 180 | height: 100%; 181 | overflow: auto; 182 | -webkit-overflow-scrolling: touch; 183 | } -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/css/header.css: -------------------------------------------------------------------------------- 1 | .title { 2 | background-color: #c9394a; 3 | } 4 | 5 | .title-color { 6 | color: white; 7 | } 8 | 9 | .mui-bar-tab .mui-tab-item.mui-active { 10 | color: #c9394a; 11 | } 12 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/css/mui.indexedlist.css: -------------------------------------------------------------------------------- 1 | .mui-indexed-list { 2 | position: relative; 3 | border-top: solid 1px #e3e3e3; 4 | border-bottom: solid 1px #e3e3e3; 5 | overflow: hidden; 6 | background-color: #fafafa; 7 | height: 300px; 8 | cursor: default; 9 | } 10 | .mui-indexed-list-inner { 11 | margin: 0px; 12 | padding: 0px; 13 | overflow-y: auto; 14 | border: none; 15 | } 16 | .mui-indexed-list-inner::-webkit-scrollbar { 17 | width: 0px; 18 | height: 0px; 19 | visibility: hidden; 20 | } 21 | .mui-indexed-list-empty-alert, 22 | .mui-indexed-list-inner.empty ul { 23 | display: none; 24 | } 25 | .mui-indexed-list-inner.empty .mui-indexed-list-empty-alert { 26 | display: block; 27 | } 28 | .mui-indexed-list-empty-alert { 29 | padding: 30px 15px; 30 | text-align: center; 31 | color: #ccc; 32 | padding-right: 45px; 33 | } 34 | .mui-ios .mui-indexed-list-inner { 35 | width: calc(100% + 10px); 36 | } 37 | .mui-indexed-list-group, 38 | .mui-indexed-list-item { 39 | padding-right: 45px; 40 | } 41 | .mui-ios .mui-indexed-list-group, 42 | .mui-ios .mui-indexed-list-item, 43 | .mui-ios .mui-indexed-list-empty-alert { 44 | padding-right: 55px; 45 | } 46 | .mui-indexed-list-group { 47 | background-color: #f7f7f7; 48 | } 49 | .mui-indexed-list-group { 50 | padding-top: 3px; 51 | padding-bottom: 3px; 52 | } 53 | .mui-indexed-list-search { 54 | border-bottom: solid 1px #e3e3e3; 55 | z-index: 15; 56 | } 57 | .mui-indexed-list-search.mui-search:before { 58 | margin-top: -10px; 59 | } 60 | .mui-indexed-list-search input { 61 | border-radius: 0px; 62 | margin: 0px; 63 | background-color: #fafafa; 64 | } 65 | .mui-indexed-list-bar { 66 | width: 23px; 67 | background-color: lightgrey; 68 | position: absolute; 69 | height: 100%; 70 | z-index: 10; 71 | right: 0px; 72 | -webkit-transition: .2s; 73 | } 74 | .mui-indexed-list-bar a { 75 | display: block; 76 | text-align: center; 77 | font-size: 11px; 78 | padding: 0px; 79 | margin: 0px; 80 | line-height: 15px; 81 | color: #aaa; 82 | } 83 | .mui-indexed-list-bar.active { 84 | background-color: rgb(200,200,200); 85 | } 86 | .mui-indexed-list-bar.active a { 87 | color: #333; 88 | } 89 | .mui-indexed-list-bar.active a.active { 90 | color: #007aff; 91 | } 92 | .mui-indexed-list-alert { 93 | position: absolute; 94 | z-index: 20; 95 | background-color: rgba(0, 0, 0, 0.5); 96 | width: 80px; 97 | height: 80px; 98 | left: 50%; 99 | top: 50%; 100 | margin-left: -40px; 101 | margin-top: -40px; 102 | border-radius: 40px; 103 | text-align: center; 104 | line-height: 80px; 105 | font-size: 35px; 106 | color: #fff; 107 | display: none; 108 | -webkit-transition: .2s; 109 | } 110 | .mui-indexed-list-alert.active { 111 | display: block; 112 | } -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/css/registLogin/arrow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/css/registLogin/arrow.jpg -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/demo_fontclass.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IconFont 7 | 8 | 9 | 10 | 11 |

12 |

IconFont 图标

13 |
    14 | 15 |
  • 16 | 17 |
    fire
    18 |
    .icon-fire
    19 |
  • 20 | 21 |
  • 22 | 23 |
    朋友圈
    24 |
    .icon-pengyouquan
    25 |
  • 26 | 27 |
  • 28 | 29 |
    我的
    30 |
    .icon-wode-active
    31 |
  • 32 | 33 |
  • 34 | 35 |
    通讯录
    36 |
    .icon-tongxunlu
    37 |
  • 38 | 39 |
  • 40 | 41 |
    指南针 (1)
    42 |
    .icon-zhinanzhen
    43 |
  • 44 | 45 |
  • 46 | 47 |
    指南针
    48 |
    .icon-zhinanzhen1
    49 |
  • 50 | 51 |
52 | 53 |

font-class引用

54 |
55 | 56 |

font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。

57 |

与unicode使用方式相比,具有如下特点:

58 |
    59 |
  • 兼容性良好,支持ie8+,及所有现代浏览器。
  • 60 |
  • 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。
  • 61 |
  • 因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。
  • 62 |
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
  • 63 |
64 |

使用步骤如下:

65 |

第一步:引入项目下面生成的fontclass代码:

66 | 67 | 68 |
<link rel="stylesheet" type="text/css" href="./iconfont.css">
69 |

第二步:挑选相应图标并获取类名,应用于页面:

70 |
<i class="iconfont icon-xxx"></i>
71 |
72 |

"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。

73 |
74 |
75 | 76 | 77 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/demo_symbol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IconFont 7 | 8 | 9 | 10 | 24 | 25 | 26 |
27 |

IconFont 图标

28 |
    29 | 30 |
  • 31 | 34 |
    fire
    35 |
    #icon-fire
    36 |
  • 37 | 38 |
  • 39 | 42 |
    朋友圈
    43 |
    #icon-pengyouquan
    44 |
  • 45 | 46 |
  • 47 | 50 |
    我的
    51 |
    #icon-wode-active
    52 |
  • 53 | 54 |
  • 55 | 58 |
    通讯录
    59 |
    #icon-tongxunlu
    60 |
  • 61 | 62 |
  • 63 | 66 |
    指南针 (1)
    67 |
    #icon-zhinanzhen
    68 |
  • 69 | 70 |
  • 71 | 74 |
    指南针
    75 |
    #icon-zhinanzhen1
    76 |
  • 77 | 78 |
79 | 80 | 81 |

symbol引用

82 |
83 | 84 |

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 85 | 这种用法其实是做了一个svg的集合,与另外两种相比具有如下特点:

86 |
    87 |
  • 支持多色图标了,不再受单色限制。
  • 88 |
  • 通过一些技巧,支持像字体那样,通过font-size,color来调整样式。
  • 89 |
  • 兼容性较差,支持 ie9+,及现代浏览器。
  • 90 |
  • 浏览器渲染svg的性能一般,还不如png。
  • 91 |
92 |

使用步骤如下:

93 |

第一步:引入项目下面生成的symbol代码:

94 |
<script src="./iconfont.js"></script>
95 |

第二步:加入通用css代码(引入一次就行):

96 |
<style type="text/css">
 97 | .icon {
 98 |    width: 1em; height: 1em;
 99 |    vertical-align: -0.15em;
100 |    fill: currentColor;
101 |    overflow: hidden;
102 | }
103 | </style>
104 |

第三步:挑选相应图标并获取类名,应用于页面:

105 |
<svg class="icon" aria-hidden="true">
106 |   <use xlink:href="#icon-xxx"></use>
107 | </svg>
108 |         
109 |
110 | 111 | 112 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/demo_unicode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IconFont 7 | 8 | 9 | 29 | 30 | 31 |
32 |

IconFont 图标

33 |
    34 | 35 |
  • 36 | 37 |
    fire
    38 |
    &#xe729;
    39 |
  • 40 | 41 |
  • 42 | 43 |
    朋友圈
    44 |
    &#xe63f;
    45 |
  • 46 | 47 |
  • 48 | 49 |
    我的
    50 |
    &#xe67b;
    51 |
  • 52 | 53 |
  • 54 | 55 |
    通讯录
    56 |
    &#xe8fb;
    57 |
  • 58 | 59 |
  • 60 | 61 |
    指南针 (1)
    62 |
    &#xe649;
    63 |
  • 64 | 65 |
  • 66 | 67 |
    指南针
    68 |
    &#xe610;
    69 |
  • 70 | 71 |
72 |

unicode引用

73 |
74 | 75 |

unicode是字体在网页端最原始的应用方式,特点是:

76 |
    77 |
  • 兼容性最好,支持ie6+,及所有现代浏览器。
  • 78 |
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • 79 |
  • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
  • 80 |
81 |
82 |

注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式

83 |
84 |

unicode使用步骤如下:

85 |

第一步:拷贝项目下面生成的font-face

86 |
@font-face {
 87 |   font-family: 'iconfont';
 88 |   src: url('iconfont.eot');
 89 |   src: url('iconfont.eot?#iefix') format('embedded-opentype'),
 90 |   url('iconfont.woff') format('woff'),
 91 |   url('iconfont.ttf') format('truetype'),
 92 |   url('iconfont.svg#iconfont') format('svg');
 93 | }
 94 | 
95 |

第二步:定义使用iconfont的样式

96 |
.iconfont{
 97 |   font-family:"iconfont" !important;
 98 |   font-size:16px;font-style:normal;
 99 |   -webkit-font-smoothing: antialiased;
100 |   -webkit-text-stroke-width: 0.2px;
101 |   -moz-osx-font-smoothing: grayscale;
102 | }
103 | 
104 |

第三步:挑选相应图标并获取字体编码,应用于页面

105 |
<i class="iconfont">&#x33;</i>
106 | 107 |
108 |

"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。

109 |
110 |
111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1530941487034'); /* IE9*/ 4 | src: url('iconfont.eot?t=1530941487034#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAnYAAsAAAAADhQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7krqY21hcAAAAYAAAACNAAAB9Gw5Ql1nbHlmAAACEAAABYgAAAcwxzaXpWhlYWQAAAeYAAAALwAAADYR8SZbaGhlYQAAB8gAAAAeAAAAJAfkA4ZobXR4AAAH6AAAABgAAAAgH+oAAGxvY2EAAAgAAAAAEgAAABIIJAV2bWF4cAAACBQAAAAeAAAAIAEaAMluYW1lAAAINAAAAUUAAAJtPlT+fXBvc3QAAAl8AAAAWQAAAHVzd2sOeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/ss4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVLz4zdzwv4EhhrmBoQEozAiSAwA3xA1ueJzFkUEKhDAMRX+0Whhm0WsI3sG1l5iVhxC8wazmlNE7uHB+moIjzN4fXiGfNg0JgAZATXoSAPlAYHrTlezXeGQ/4MU8Mez+rEkHHXVZu20/jr/OryS/PMOcyEot61bWhbS4TXLf11c98zmVLJK5wBY1Oebr4NgudHQ4S+ji2C7XzuF8se0Omi+fjCgkAAAAeJx1VFuLHEUUrlPVXd093dNz6enLzGRmZ6az3bOXmc3cunU3zrjZ2WTdhGR3vWA0CsGQB4OKEY14wUVQfIggYgRBo4gg6oMIPq4SRH0UFNYYooI3EH+CuKOnZhPEB7ubOlVfna6qr853DpEJ+fsntsU8YpE6aZEhWSME+AzUTFqCatht0hmwq7Lt5kwW+mFV8WtNdhO4NZ5z2lE3cLnCU2BCGTrVdhQ2aQi9bp8uQNspAeSLhVuzk3uy7CVIeGH5udEqfRvsCX9Pqt8Y3TI7yLUrlnrOyGbz2ex5lcuySqmUMuEB19FkLcFH78ipgr01MUUnwMiHhSPHk5Vi9uQL3QdLk64GsLkJVrFivjvIFDL4PVVwrGxeSSdVr5D09+bg3K+6Zxml4BeCDyDXS+weNiRLhMhNCPsQ98GPHNdRTFCcKC6D63BlDIdBFAcccbsdhM3rQ+642G9CbIJbBnh7ssnoetCUGZ0vpLhcoWw+7VQYW+geP+cUgLMipStBxgTZcetJw5e0Lw73mExrpkFBvy/0n4iclcbG/b2NE3RwW6fVP05pY93ZX52/13Ufm19+ord6D9DpG0vzdLi4/9DszScpu+3Jh58GqFerc8AuvXzqWaIir8/Yp2yRKCRFXDJBQjJHYjJAynhapAZxE3wWR4EL1b4YMCSLHCcVZIwAoO1YyI6Zousi3TF1mb4K68sH1wHm3mkfBnYVZuLRVxBRG0P7G11p75uC0fpTsH5weR1GX6MPpeizAA5Qj0L7mHCpw4esjn9QD0bffLkvHN1xBVYeHW3D2nB5becyTO9rrVL6h1gT/2miB7yPHvAWrC0P1wBm/r7mcj2GL0oyewQZEjfoxsiDxtciJoLUZ+0yxdgo42CVYQKVKYYUwOjlGjPZ3ukphXVbpsK5Uh+sHl0d1EXXbHUYnzrdm7YauSgrn9Xq+TsDM52Q9KkOOzBcON27uzK52PK81mJYOdE7ORgekLpTmianzcYzBSLyaJt9wGbIDN78EjlGtgixcrwWhD08XRUPgSpQqhgPHIvcQETEIoNI1YQUdMqQE3kXdCO303b+21f8JnQjQE5CqTZ3nfFbBi5YizfujS8hjsaccRKzUsgZX4QRGV+EQHkTBoCe4q85qCHgj1eJowFEc4CYWJBfMrIGwEKDDhsLwu5sCSvAWpEOizVAu7OF9vZNzTC0/2vgkKrpCVkBZuZXDq/aOV0z9Hx+Y+NoMSOBruleYk9OtVI8nZIpL4KVLbtc8jU7wUulZKkgabmSqeaYmkymqWbYNZ8zOitxPbvHv0EDLFJAzRTWCgnT6hWx677ZeYD52Z3Hd21DYI1CFaBaoC/s2tcED/wu/Gt2qS3LCT3Jc6pUrB86ctRF1VhZoGrh9o2jrZpklhMpT8nprFwxarWEo9XlvFXWGS1wKlHD4MmMmql7hqLaiq7bjCta2qRQYqCZ/o0lxmYpkytl3coqEqqZoWY+x9q7HzM4RzwUtwm7RfVaGu6mqmxNUmIXi9PFov3Jn7L85yfj9sTowntwBj4CMTFdhPPXJ7Dd+R2n3hP5InS5KRG2SXTSIXeRU+SMqO9EcYgbkTggrNekXLFRhZ12HyPv46a2OEXcwxP44kRuxwTWh56ogopoTGrjHKoS27Yomp121ItElRSKjYWQ3XExDSi7OvpJ08Hf3oYal0c/fwxepSC9+a21lPYgmz5gffdGvuLBmz8IIJM+kPrhJFBYamvawbNVnlQldb1PgS61BFCTjSQw9dhHpcmwWN4bTKWVUjM1wzb56Mer26MfOYfa1ctQ+Wvt2urm9xfF6heveEuWnRG7vS72l9+6As9LCam9BCDdfEylLJHke88OEWotUYaIachy9aFcGAcAQRyWDKO64PmE/AP2dx17eJxjYGRgYADiv98FguP5bb4ycLMwgMD1tEJ9BP2/gYWVuQHI5WBgAokCACgdCdcAeJxjYGRgYG7438AQwwJk/f/DwsoApFEABwByHARyAAB4nGNhYGBgfsnAwMIAxYxIbCAGABrmAQoAAAAAAHYA4gFYAaQCvgLwA5gAAHicY2BkYGDgYNgLxCDABMRcQMjA8B/MZwAAHE8B5AAAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicbcY9EkAwEAbQ/QgiOYvCkTIsMmM2mMTf6RUKjVc9yuhl6J9GhhwKBUpU0KgJpxr8xnZhGa+Q1uTEHqHnxnXR71zHIOOZZE7mnrw4uScW+7UlegA+vhhTAAAA') format('woff'), 6 | url('iconfont.ttf?t=1530941487034') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1530941487034#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-fire:before { content: "\e729"; } 19 | 20 | .icon-pengyouquan:before { content: "\e63f"; } 21 | 22 | .icon-wode-active:before { content: "\e67b"; } 23 | 24 | .icon-tongxunlu:before { content: "\e8fb"; } 25 | 26 | .icon-zhinanzhen:before { content: "\e649"; } 27 | 28 | .icon-zhinanzhen1:before { content: "\e610"; } 29 | 30 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/fontico/iconfont.eot -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/fontico/iconfont.ttf -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fontico/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/fontico/iconfont.woff -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/fonts/mui.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/fonts/mui.ttf -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/addfriends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/addfriends.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/bg.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/download.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/error.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/face-default-cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/face-default-cat.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/friends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/friends.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/givememoney.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/givememoney.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/good.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/good.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/qrcode.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/scanscan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/scanscan.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/success.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/image/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/image/upload.png -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/imooc-discover.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
    16 |
  • 17 | 19 |

    21 | 朋友圈 22 |

    23 |
  • 24 |
25 | 26 |
27 | 28 |
    29 |
  • 30 | 32 |

    34 | 添加好友 35 |

    36 |
  • 37 |
  • 38 | 40 |

    42 | 扫一扫 43 |

    44 |
  • 45 |
46 | 47 |
48 | 49 | 50 | 51 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 |
23 |

慕信

24 |
25 | 26 | 44 | 45 | 143 | 144 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |
53 | 54 |
Netty 实战
55 |
56 | 57 | 风间影月 58 | 59 | 60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 |
69 |
70 | 73 |
74 |
75 | 76 |
77 |
78 |
79 | 80 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/mp3/di_didi.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/mp3/di_didi.mp3 -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/mp3/msn.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/mp3/msn.mp3 -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/mp3/send.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/mp3/send.mp3 -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/myQRCode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 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 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/myface.html: -------------------------------------------------------------------------------- 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 | 35 | 36 | 41 |
42 | 43 | 44 | 45 | 46 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/mynickname.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 完成 19 |

设置昵称

20 |
21 | 22 |
23 |
24 | 26 |
27 |
28 | 29 | 30 | 31 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/plugin/cropper/css/main.css: -------------------------------------------------------------------------------- 1 | .btn { 2 | padding-left: .75rem; 3 | padding-right: .75rem; 4 | } 5 | 6 | label.btn { 7 | margin-bottom: 0; 8 | } 9 | 10 | .d-flex > .btn { 11 | flex: 1; 12 | } 13 | 14 | .carbonads { 15 | border-radius: .25rem; 16 | border: 1px solid #ccc; 17 | font-size: .875rem; 18 | overflow: hidden; 19 | padding: 1rem; 20 | } 21 | 22 | .carbon-wrap { 23 | overflow: hidden; 24 | } 25 | 26 | .carbon-img { 27 | clear: left; 28 | display: block; 29 | float: left; 30 | } 31 | 32 | .carbon-text, 33 | .carbon-poweredby { 34 | display: block; 35 | margin-left: 140px; 36 | } 37 | 38 | .carbon-text, 39 | .carbon-text:hover, 40 | .carbon-text:focus { 41 | color: #fff; 42 | text-decoration: none; 43 | } 44 | 45 | .carbon-poweredby, 46 | .carbon-poweredby:hover, 47 | .carbon-poweredby:focus { 48 | color: #ddd; 49 | text-decoration: none; 50 | } 51 | 52 | @media (min-width: 768px) { 53 | .carbonads { 54 | float: right; 55 | margin-bottom: -1rem; 56 | margin-top: -1rem; 57 | max-width: 360px; 58 | } 59 | } 60 | 61 | .footer { 62 | font-size: .875rem; 63 | overflow: hidden; 64 | } 65 | 66 | .heart { 67 | color: #ddd; 68 | display: block; 69 | height: 2rem; 70 | line-height: 2rem; 71 | margin-bottom: 0; 72 | margin-top: 1rem; 73 | position: relative; 74 | text-align: center; 75 | width: 100%; 76 | } 77 | 78 | .heart:hover { 79 | color: #ff4136; 80 | } 81 | 82 | .heart::before { 83 | border-top: 1px solid #eee; 84 | content: " "; 85 | display: block; 86 | height: 0; 87 | left: 0; 88 | position: absolute; 89 | right: 0; 90 | top: 50%; 91 | } 92 | 93 | .heart::after { 94 | background-color: #fff; 95 | content: "♥"; 96 | padding-left: .5rem; 97 | padding-right: .5rem; 98 | position: relative; 99 | z-index: 1; 100 | } 101 | 102 | .img-container, 103 | .img-preview { 104 | background-color: #f7f7f7; 105 | text-align: center; 106 | width: 100%; 107 | } 108 | 109 | .img-container { 110 | margin-bottom: 1rem; 111 | max-height: 497px; 112 | min-height: 200px; 113 | } 114 | 115 | @media (min-width: 768px) { 116 | .img-container { 117 | min-height: 497px; 118 | } 119 | } 120 | 121 | .img-container > img { 122 | max-width: 100%; 123 | } 124 | 125 | .docs-preview { 126 | margin-right: -1rem; 127 | } 128 | 129 | .img-preview { 130 | float: left; 131 | margin-bottom: .5rem; 132 | margin-right: .5rem; 133 | overflow: hidden; 134 | } 135 | 136 | .img-preview > img { 137 | max-width: 100%; 138 | } 139 | 140 | .preview-lg { 141 | height: 9rem; 142 | width: 16rem; 143 | } 144 | 145 | .preview-md { 146 | height: 4.5rem; 147 | width: 8rem; 148 | } 149 | 150 | .preview-sm { 151 | height: 2.25rem; 152 | width: 4rem; 153 | } 154 | 155 | .preview-xs { 156 | height: 1.125rem; 157 | margin-right: 0; 158 | width: 2rem; 159 | } 160 | 161 | .docs-data > .input-group { 162 | margin-bottom: .5rem; 163 | } 164 | 165 | .docs-data .input-group-prepend .input-group-text { 166 | min-width: 4rem; 167 | } 168 | 169 | .docs-data .input-group-append .input-group-text { 170 | min-width: 3rem; 171 | } 172 | 173 | .docs-buttons > .btn, 174 | .docs-buttons > .btn-group, 175 | .docs-buttons > .form-control { 176 | margin-bottom: .5rem; 177 | margin-right: .25rem; 178 | } 179 | 180 | .docs-toggles > .btn, 181 | .docs-toggles > .btn-group, 182 | .docs-toggles > .dropdown { 183 | margin-bottom: .5rem; 184 | } 185 | 186 | .docs-tooltip { 187 | display: block; 188 | margin: -.5rem -.75rem; 189 | padding: .5rem .75rem; 190 | } 191 | 192 | .docs-tooltip > .icon { 193 | margin: 0 -.25rem; 194 | vertical-align: top; 195 | } 196 | 197 | .tooltip-inner { 198 | white-space: normal; 199 | } 200 | 201 | .btn-upload .tooltip-inner, 202 | .btn-toggle .tooltip-inner { 203 | white-space: nowrap; 204 | } 205 | 206 | .btn-toggle { 207 | padding: .5rem; 208 | } 209 | 210 | .btn-toggle > .docs-tooltip { 211 | margin: -.5rem; 212 | padding: .5rem; 213 | } 214 | 215 | @media (max-width: 400px) { 216 | .btn-group-crop { 217 | margin-right: -1rem!important; 218 | } 219 | 220 | .btn-group-crop > .btn { 221 | padding-left: .5rem; 222 | padding-right: .5rem; 223 | } 224 | 225 | .btn-group-crop .docs-tooltip { 226 | margin-left: -.5rem; 227 | margin-right: -.5rem; 228 | padding-left: .5rem; 229 | padding-right: .5rem; 230 | } 231 | } 232 | 233 | .docs-options .dropdown-menu { 234 | width: 100%; 235 | } 236 | 237 | .docs-options .dropdown-menu > li { 238 | font-size: .875rem; 239 | padding: .125rem 1rem; 240 | } 241 | 242 | .docs-options .dropdown-menu .form-check-label { 243 | display: block; 244 | } 245 | 246 | .docs-cropped .modal-body { 247 | text-align: center; 248 | } 249 | 250 | .docs-cropped .modal-body > img, 251 | .docs-cropped .modal-body > canvas { 252 | max-width: 100%; 253 | } 254 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/plugin/cropper/images/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/plugin/cropper/images/picture.jpg -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/plugin/v3.1.6/images/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShimmerPig/PigChat/d93c860853ec8ff66b56bb528bf9eac753814392/前端UI代码/imooc-zhuxin/plugin/v3.1.6/images/picture.jpg -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/plugin/v3.1.6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Cropper 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 | 26 |
27 | Picture 28 |
29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/plugin/v3.1.6/js/main.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | var $image = $('#image'); 4 | var options = { 5 | aspectRatio: 1 / 1, 6 | preview: '.img-preview', 7 | crop: function(e) {} 8 | }; 9 | 10 | // Cropper 11 | $image.cropper(options); 12 | 13 | // Methods 14 | $('.docs-buttons').on('click', '[data-method]', function() { 15 | var cropper = $image.data('cropper'); 16 | var result; 17 | 18 | result = $image.cropper("getCroppedCanvas"); 19 | 20 | if(result) { 21 | // Bootstrap's Modal 22 | $('#getCroppedCanvasModal').modal().find('.modal-body').html(result); 23 | var base64Url = result.toDataURL(); 24 | console.log(base64Url); 25 | } 26 | 27 | }); 28 | 29 | }); -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/scanme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |

扫一扫

31 |
32 | 33 |
34 | 35 | 36 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/searchFriends.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 搜索 19 |

添加朋友

20 |
21 | 22 |
23 |
24 | 27 |
28 |
29 | 30 | 31 | 32 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/searchFriendsResult.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 | 21 | 22 | 23 | 24 |
25 | 26 |

详细资料

27 |
28 | 29 |
30 | 31 | 43 | 44 |
45 |
46 | 48 | 50 |
51 | 52 |
53 | 54 | 55 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/unpackage/.confirmed_dependencies: -------------------------------------------------------------------------------- 1 | { 2 | "index.html": { 3 | "resources": [ 4 | "imooc-chatlist.html" 5 | ], 6 | "refer": [ 7 | "imooc-me.html", 8 | "imooc-discover.html", 9 | "imooc-contact.html", 10 | "imooc-chatlist.html" 11 | ] 12 | }, 13 | "login.html": { 14 | "refer": [ 15 | "index.html", 16 | "login.html" 17 | ], 18 | "resources": [ 19 | "js/app.js", 20 | "js/mui.min.js", 21 | "css/registLogin/util.css", 22 | "css/registLogin/main.css", 23 | "css/registLogin/arrow.jpg" 24 | ] 25 | }, 26 | "imooc-me.html": { 27 | "refer": [ 28 | "myface.html", 29 | "mynickname.html", 30 | "myQRCode.html", 31 | "login.html" 32 | ] 33 | }, 34 | "myface.html": { 35 | "refer": [ 36 | "plugin/v3.1.6/myface-uploader.html" 37 | ] 38 | }, 39 | "imooc-discover.html": { 40 | "refer": [ 41 | "searchFriends.html", 42 | "scanme.html" 43 | ] 44 | }, 45 | "searchFriends.html": { 46 | "refer": [ 47 | "searchFriendsResult.html" 48 | ] 49 | }, 50 | "imooc-contact.html": { 51 | "refer": [ 52 | "chatting.html" 53 | ] 54 | }, 55 | "imooc-chatlist.html": { 56 | "refer": [ 57 | "chatting.html" 58 | ] 59 | }, 60 | "scanme.html": { 61 | "refer": [ 62 | "searchFriendsResult.html" 63 | ] 64 | } 65 | } -------------------------------------------------------------------------------- /前端UI代码/imooc-zhuxin/unpackage/.dependencies: -------------------------------------------------------------------------------- 1 | null --------------------------------------------------------------------------------