From 9ad8ef92cf2273536d94913850452b61cc13a7c9 Mon Sep 17 00:00:00 2001 From: lance Date: Wed, 21 Jun 2017 12:06:45 +0800 Subject: [PATCH] add websocket server --- spring-boot-websocket-netty-server/pom.xml | 16 +++ .../net/server/SimplePushApplication.java | 43 ++++++++ .../net/server/common/ChatConstants.java | 45 ++++++++ .../server/common/ChatHeartbeatHandler.java | 27 +++++ .../lance/net/server/common/ChatServer.java | 62 +++++++++++ .../server/common/ChatServerInitializer.java | 41 +++++++ .../net/server/common/HttpRequestHandler.java | 102 ++++++++++++++++++ .../common/TextWebSocketFrameHandler.java | 82 ++++++++++++++ .../lance/net/server/module/ChatMessage.java | 65 +++++++++++ .../com/lance/net/server/module/UserInfo.java | 73 +++++++++++++ .../lance/net/server/web/ChatController.java | 38 +++++++ .../lance/net/server/web/LoginController.java | 31 ++++++ 12 files changed, 625 insertions(+) create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/SimplePushApplication.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatConstants.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatHeartbeatHandler.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServer.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServerInitializer.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/HttpRequestHandler.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/TextWebSocketFrameHandler.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/ChatMessage.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/UserInfo.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/ChatController.java create mode 100644 spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/LoginController.java diff --git a/spring-boot-websocket-netty-server/pom.xml b/spring-boot-websocket-netty-server/pom.xml index 1043cc5..143db70 100644 --- a/spring-boot-websocket-netty-server/pom.xml +++ b/spring-boot-websocket-netty-server/pom.xml @@ -21,9 +21,25 @@ netty-all 4.1.12.Final + + com.alibaba + fastjson + 1.2.31 + + + org.apache.commons + commons-lang3 + 3.5 + spring-boot-websocket-netty-server + + + + maven-resources-plugin + + diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/SimplePushApplication.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/SimplePushApplication.java new file mode 100644 index 0000000..c7436c4 --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/SimplePushApplication.java @@ -0,0 +1,43 @@ +package com.lance.net.server; + +import java.net.InetSocketAddress; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import com.lance.net.server.common.ChatServer; + +import io.netty.channel.ChannelFuture; + +@SpringBootApplication +public class SimplePushApplication implements CommandLineRunner{ + @Autowired + private ChatServer chatServer; + + public static void main(String[] args) { + SpringApplication.run(SimplePushApplication.class, args); + } + + @Bean + public ChatServer chatServer() { + return new ChatServer(); + } + + @Override + public void run(String... args) throws Exception { + InetSocketAddress address = new InetSocketAddress("127.0.0.1", 9090); + ChannelFuture future = chatServer.start(address); + + Runtime.getRuntime().addShutdownHook(new Thread(){ + @Override + public void run() { + chatServer.destroy(); + } + }); + + future.channel().closeFuture().syncUninterruptibly(); + } +} \ No newline at end of file diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatConstants.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatConstants.java new file mode 100644 index 0000000..e1496cc --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatConstants.java @@ -0,0 +1,45 @@ +package com.lance.net.server.common; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.lang3.RandomUtils; +import org.apache.commons.lang3.StringUtils; + +import com.lance.net.server.module.UserInfo; + +import io.netty.util.AttributeKey; + +public class ChatConstants { + public static final AttributeKey CHANNEL_TOKEN_KEY = AttributeKey.valueOf("netty.channel.token"); + /**用来保存当前在线人员*/ + public static Map onlines = new ConcurrentHashMap<>(); + + public static void addOnlines(String sessionId, UserInfo val) { + onlines.putIfAbsent(sessionId, val); + } + + public static void removeOnlines(String sessionId) { + if(StringUtils.isNotBlank(sessionId) && onlines.containsKey(sessionId)){ + onlines.remove(sessionId); + } + } + + private static char[]prefix = {'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y'}; + private static int[]imgPrefix = {1,2,3,4,5,6,7,8,9,10,11}; + + public static String headImg() { + int index = RandomUtils.nextInt(0, imgPrefix.length); + return "/resources/img/head/"+imgPrefix[index]+".jpg"; + } + + public static String code() { + int index = RandomUtils.nextInt(0, prefix.length); + char prf = prefix[index]; + String len = (onlines.size()+1)+""; + if(len.length() < 4) { + len = StringUtils.leftPad(len, 4, '0'); + } + return prf+len; + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatHeartbeatHandler.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatHeartbeatHandler.java new file mode 100644 index 0000000..9ccd05e --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatHeartbeatHandler.java @@ -0,0 +1,27 @@ +package com.lance.net.server.common; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.timeout.IdleStateEvent; +import io.netty.util.CharsetUtil; + +public class ChatHeartbeatHandler extends ChannelInboundHandlerAdapter{ + private Logger logger = LogManager.getLogger(); + private final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("HB",CharsetUtil.UTF_8)); + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if(evt instanceof IdleStateEvent) { + logger.info("====>Heartbeat: greater than {}", 180); + ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); + }else { + super.userEventTriggered(ctx, evt); + } + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServer.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServer.java new file mode 100644 index 0000000..2de7e2b --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServer.java @@ -0,0 +1,62 @@ +package com.lance.net.server.common; + +import java.net.InetSocketAddress; + +import org.springframework.stereotype.Component; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.util.concurrent.ImmediateEventExecutor; + +@Component +public class ChatServer { + private final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final EventLoopGroup workGroup = new NioEventLoopGroup(); + private Channel channel; + + public ChannelFuture start(InetSocketAddress address) { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChatServerInitializer(channelGroup)) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, true); + + ChannelFuture future = bootstrap.bind(address).syncUninterruptibly(); + channel = future.channel(); + return future; + } + + public void destroy() { + if(channel != null) { + channel.close(); + } + + channelGroup.close(); + workGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + } + + public static void main(String[] args) { + ChatServer server = new ChatServer(); + InetSocketAddress address = new InetSocketAddress("127.0.0.1", 9090); + ChannelFuture future = server.start(address); + + Runtime.getRuntime().addShutdownHook(new Thread(){ + @Override + public void run() { + server.destroy(); + } + }); + + future.channel().closeFuture().syncUninterruptibly(); + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServerInitializer.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServerInitializer.java new file mode 100644 index 0000000..b396ac4 --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/ChatServerInitializer.java @@ -0,0 +1,41 @@ +package com.lance.net.server.common; + +import java.util.concurrent.TimeUnit; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.handler.timeout.IdleStateHandler; + +public class ChatServerInitializer extends ChannelInitializer{ + private final ChannelGroup group; + + public ChatServerInitializer(ChannelGroup group) { + this.group = group; + } + + @Override + protected void initChannel(Channel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + //处理日志 + pipeline.addLast(new LoggingHandler(LogLevel.INFO)); + + //处理心跳 + pipeline.addLast(new IdleStateHandler(0, 0, 1800, TimeUnit.SECONDS)); + pipeline.addLast(new ChatHeartbeatHandler()); + + pipeline.addLast(new HttpServerCodec()); + pipeline.addLast(new ChunkedWriteHandler()); + pipeline.addLast(new HttpObjectAggregator(64 * 1024)); + pipeline.addLast(new HttpRequestHandler("/ws")); + pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); + pipeline.addLast(new TextWebSocketFrameHandler(group)); + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/HttpRequestHandler.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/HttpRequestHandler.java new file mode 100644 index 0000000..0ec6cfe --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/HttpRequestHandler.java @@ -0,0 +1,102 @@ +package com.lance.net.server.common; + +import java.io.RandomAccessFile; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.lance.net.server.module.UserInfo; + +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.DefaultFileRegion; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.DefaultHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpUtil; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.QueryStringDecoder; +import io.netty.handler.ssl.SslHandler; +import io.netty.handler.stream.ChunkedNioFile; + +public class HttpRequestHandler extends SimpleChannelInboundHandler { + private Logger loger = LogManager.getLogger(); + private final String webUri; + private final String INDEX = "E:\\oworkspace\\test\\src\\main\\webapp\\index.html"; + + public HttpRequestHandler(String webUri) { + this.webUri = webUri; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { + loger.info("===========> {}, {}", webUri, request.uri()); + + String uri = StringUtils.substringBefore(request.uri(), "?"); + if(webUri.equalsIgnoreCase(uri)) {//获取webSocket参数 + QueryStringDecoder query = new QueryStringDecoder(request.uri()); + Map> map = query.parameters(); + List tokens = map.get("token"); + + //根据参数保存当前登录对象, 并把该token加入到channel中 + if(tokens != null && !tokens.isEmpty()) { + String token = tokens.get(0); + ChatConstants.addOnlines(token, new UserInfo(token)); + ctx.channel().attr(ChatConstants.CHANNEL_TOKEN_KEY).getAndSet(token); + } + + request.setUri(uri); + ctx.fireChannelRead(request.retain()); + }else { + if(HttpUtil.is100ContinueExpected(request)) { + send100ContinueExpected(ctx); + } + + RandomAccessFile file = new RandomAccessFile(INDEX, "r"); + HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); + + boolean keepAlive = HttpUtil.isKeepAlive(request); + if(keepAlive) { + response.headers().set(HttpHeaderNames.CONTENT_LENGTH, file.length()); + response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); + } + ctx.write(response); + + if(ctx.pipeline().get(SslHandler.class) == null) { + ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length())); + }else { + ctx.write(new ChunkedNioFile(file.getChannel())); + } + + ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); + if(!keepAlive) { + future.addListener(ChannelFutureListener.CLOSE); + } + + file.close(); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } + + private void send100ContinueExpected(ChannelHandlerContext ctx) { + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONFLICT); + ctx.writeAndFlush(response); + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/TextWebSocketFrameHandler.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/TextWebSocketFrameHandler.java new file mode 100644 index 0000000..a8509fd --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/common/TextWebSocketFrameHandler.java @@ -0,0 +1,82 @@ +package com.lance.net.server.common; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.lance.net.server.module.ChatMessage; +import com.lance.net.server.module.UserInfo; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.group.ChannelGroup; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; + +public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler{ + private Logger loger = LogManager.getLogger(); + private final ChannelGroup group; + + public TextWebSocketFrameHandler(ChannelGroup group) { + this.group = group; + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + loger.info("Event====>{}", evt); + + if(evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) { + ctx.pipeline().remove(HttpRequestHandler.class); + + //加入当前, 上线人员推送前端,显示用户列表中去 + Channel channel = ctx.channel(); + ChatMessage message = new ChatMessage(null, ""); + group.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(message,SerializerFeature.DisableCircularReferenceDetect))); + group.add(channel); + }else { + super.userEventTriggered(ctx, evt); + } + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { + Channel channel = ctx.channel(); + String token = channel.attr(ChatConstants.CHANNEL_TOKEN_KEY).get(); + UserInfo from = ChatConstants.onlines.get(token); + if(from == null) { + group.writeAndFlush("OK"); + }else { + ChatMessage message = new ChatMessage(from, msg.text()); + group.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(message,SerializerFeature.DisableCircularReferenceDetect))); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + loger.info("Current channel channelInactive"); + offlines(ctx); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { + loger.info("Current channel handlerRemoved"); + offlines(ctx); + } + + private void offlines(ChannelHandlerContext ctx) { + Channel channel = ctx.channel(); + String token = channel.attr(ChatConstants.CHANNEL_TOKEN_KEY).get(); + ChatConstants.removeOnlines(token); + + group.remove(channel); + ctx.close(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + loger.error("=====> {}", cause.getMessage()); + offlines(ctx); + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/ChatMessage.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/ChatMessage.java new file mode 100644 index 0000000..f276677 --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/ChatMessage.java @@ -0,0 +1,65 @@ +package com.lance.net.server.module; + +import java.util.Date; +import java.util.Map; + +import com.alibaba.fastjson.annotation.JSONField; +import com.lance.net.server.common.ChatConstants; + +public class ChatMessage { + //发送消息则 + private UserInfo from; + + //发送内容 + private String message; + + //接收者列表 + private Map to; + + //发送时间 + @JSONField(format="yyyy-MM-dd HH:mm:ss") + private Date createTime; + + public ChatMessage() { + + } + + public ChatMessage(UserInfo from,String message) { + this.from = from; + this.message = message; + this.to = ChatConstants.onlines; + this.createTime = new Date(); + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public UserInfo getFrom() { + return from; + } + + public void setFrom(UserInfo from) { + this.from = from; + } + + public Map getTo() { + return to; + } + + public void setTo(Map to) { + this.to = to; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/UserInfo.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/UserInfo.java new file mode 100644 index 0000000..9080681 --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/module/UserInfo.java @@ -0,0 +1,73 @@ +package com.lance.net.server.module; + +import java.io.Serializable; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.lance.net.server.common.ChatConstants; + +public class UserInfo implements Serializable{ + private static final long serialVersionUID = 3562768188264006800L; + public static Map map = new ConcurrentHashMap<>(); + + private Long id; + + private String phone; + + private String password; + + private String code; + + private String headImg; + + public UserInfo() { + + } + + public UserInfo(String phone) { + this.phone = phone; + this.headImg = ChatConstants.headImg(); + this.code = ChatConstants.code(); + this.id = System.currentTimeMillis(); + } + + public String getHeadImg() { + return headImg; + } + + public void setHeadImg(String headImg) { + this.headImg = headImg; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/ChatController.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/ChatController.java new file mode 100644 index 0000000..db3303d --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/ChatController.java @@ -0,0 +1,38 @@ +package com.lance.net.server.web; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.alibaba.fastjson.JSON; +import com.lance.net.server.common.ChatConstants; +import com.lance.net.server.module.UserInfo; + +@Controller +@RequestMapping("/chat") +public class ChatController { + + // 跳转到交谈聊天页面 + @RequestMapping(value = "list", method = RequestMethod.GET) + public String talk(String token, Model model) { + model.addAttribute("token", token); + return "chat.jsp"; + } + + @ResponseBody + @RequestMapping(value = "users", method = RequestMethod.GET, produces={"application/json; charset=UTF-8", "text/plain"}) + public String users(String token) { + Map onlines = ChatConstants.onlines; + UserInfo cur = onlines.get(token); + + Map map = new HashMap<>(2); + map.put("curName", cur!=null?cur.getCode():""); + map.put("users", onlines); + return JSON.toJSONString(map); + } +} diff --git a/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/LoginController.java b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/LoginController.java new file mode 100644 index 0000000..1e0c0f3 --- /dev/null +++ b/spring-boot-websocket-netty-server/src/main/java/com/lance/net/server/web/LoginController.java @@ -0,0 +1,31 @@ +package com.lance.net.server.web; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.lance.net.server.module.UserInfo; + +@Controller +public class LoginController { + /** + * 跳转登录页面 + * @return + */ + @RequestMapping(value = {"","/","index"}, method = RequestMethod.GET) + public String index(){ + return "index.jsp"; + } + + /** + * 用户登录 + * @param user + * @return + */ + @RequestMapping(value = "login", method = RequestMethod.POST) + public String doLogin(UserInfo user) { + UserInfo.map.put(user.getPhone(), user); + //return "redirect:/msg/list?token="+user.getPhone(); + return "redirect:/chat/list?token="+user.getPhone(); + } +} \ No newline at end of file