spring-boot-starter-websocket +netty
1、服务端
1)、
2)、pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
3)、MyWebSocketHandler
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private static Logger logger=LoggerFactory.getLogger(MyWebSocketHandler.class);
public static ChannelGroup channelGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public static ConcurrentHashMap<String,Channel> channelMap=new ConcurrentHashMap<>();
/由于@Autowired注解注入不进去,所以取巧了
static IServiceXfzhQz serviceXfzhQz;
static {
serviceXfzhQz = SpringUtil.getBean(IServiceXfzhQz.class);
}
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel incomming=ctx.channel();
channelGroup.add(ctx.channel());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
channelGroup.remove(ctx.channel());
Collection<Channel> col=channelMap.values();
while (true==col.contains(ctx.channel())){
col.remove(ctx.channel());
logger.info("netty客户端连接删除成功!");
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info("netty与客户端建立连接,通道开启!");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
TextWebSocketFrame msg2=(TextWebSocketFrame)msg;
logger.info("netty客户端收到服务器数据:{}",msg2.text());
String date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
message(ctx,msg2.text(),date);
}
public void message(ChannelHandlerContext ctx,String msg,String date){
try {
Map<String,Object> resultmap=new HashMap<>();
resultmap.put("MSGTYPE","DL");
resultmap.put("USERID","2021");
resultmap.put("CREATEDATE",date);
String msgtype=(String)resultmap.get("MSGTYPE");
if(msg.equals("DL")&&msgtype.equals("DL")){
Channel channel=ctx.channel();
channelMap.put((String)resultmap.get("USERID"),channel);
resultmap.put("sucess",true);
resultmap.put("message","用户链接绑定成功!");
channel.writeAndFlush(new TextWebSocketFrame(resultmap.toString()));
logger.info("netty用户:{}连接绑定成功!",(String)resultmap.get("USERID"));
}else if(msg.equals("DH")&&msgtype.equals("DL")){
List<Map<String,Object>> list=new ArrayList<>();
for(Map<String,Object> map:list){
String userid=(String)map.get("USERID");
if(channelMap.containsKey(userid)){
Channel channel=channelMap.get(userid);
channel.writeAndFlush(new TextWebSocketFrame(resultmap.toString()));
}
}
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throws Exception{
Channel incoming=ctx.channel();
System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"异常");
cause.printStackTrace();
ctx.close();
}
}
4)、NettyServer
public class NettyServer {
private static Logger logger=LoggerFactory.getLogger(NettyServer.class);
private final int port;
public NettyServer(int port){
this.port=port;
}
public void start() throws InterruptedException {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup group=new NioEventLoopGroup();
try {
ServerBootstrap sb=new ServerBootstrap();
sb.option(ChannelOption.SO_BACKLOG,1024);
sb.group(group,bossGroup).
channel(NioServerSocketChannel.class)
.localAddress(this.port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
logger.info("收到新的客户端连接:{}",ch.toString());
ch.pipeline().addLast(new HttpServerCodec());
ch.pipeline().addLast(new ChunkedWriteHandler());
ch.pipeline().addLast(new HttpObjectAggregator(8192));
ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws","WebSocket",true,65535*10));
ch.pipeline().addLast(new MyWebSocketHandler());
}
});
ChannelFuture cf=sb.bind().sync();
System.out.println(NettyServer.class+" 启动正在监听:"+cf.channel().localAddress());
cf.channel().closeFuture().sync();
}finally {
group.shutdownGracefully().sync();
bossGroup.shutdownGracefully().sync();
}
}
}
5)、
@SpringBootApplication
public class WsnettyApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WsnettyApplication.class, args);
try {
new NettyServer(8091).start();
}catch (Exception e){
System.out.println("NettyServerError"+e.getMessage());
}
}
}
2、客户端
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping("/wstest")
public String wstest(){
return "wstest";
}
}
wstest.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
var socket;
if(!window.WebSocket){
window.WebSocket=window.MozWebSocket;
}
if(window.WebSocket)
{
socket=new WebSocket("ws://127.0.0.1:8091/ws");
socket.onmessage=function (ev) {
var ta=document.getElementById("responseText");
ta.value+=ev.data+"\r\n";
}
socket.onopen=function (ev) {
var ta=document.getElementById("responseText");
ta.value+="Netty-WebSocket服务器 .....连接 \r\n";
};
socket.onclose=function (ev) {
var ta=document.getElementById("responseText");
ta.value+="Netty-WebSocket服务器 .....关闭 \r\n";
};
}
else{
alert("您的浏览器不支持WebSocket协议!");
}
function send(message) {
if(!window.WebSocket){return;}
if(socket.readyState==WebSocket.OPEN){
socket.send(message);
}else {
alert("WebSocket 连接没有建立成功!")
}
}
</script>
</head>
<body>
<div class="container">
<form onsubmit="return false;">
<div class="form-group">
<h2 class="col-sm-offset-5">ws test</h2>
</div>
<div class="form-group">
<label class="col-sm-offset-3 col-sm-2 control-label">TEXT</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="message"
name="message" placeholder="请输入用户名" value="这里输入信息"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-5 col-sm-4">
<button type="button" class="btn btn-default"
onclick="send(this.form.message.value)" >发送ws信息</button>
</div>
</div>
<div class="form-group">
<label class="col-sm-offset-3 col-sm-2 control-label">服务端返回的信息</label>
<div class="col-sm-3">
<textarea id="responseText" style="width: 1024px;height: 300px;"></textarea>
</div>
</div>
</form>
</div>
<script src="/js/jquery.js"></script>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>