spring 5.x 系列第17篇 —— 整合websocket (xml配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all
一、说明
1.1 项目结构说明
- 项目模拟一个简单的群聊功能,为区分不同的聊天客户端,登录时候将临时用户名存储在session当中;
- CustomHander为消息的自定义处理器;
- CustomHandershakerInterceptor为自定义的 websocket 的握手拦截器;
- 项目以web的方式构建。

1.2 依赖说明
除了基本的spring 依赖外,还需要导入webSocket的依赖包
<!--spring webSocket 的依赖包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
二、spring websocket
2.1 创建消息处理类,继承自TextWebSocketHandler
/**
* @author : heibaiying
* @description : 自定义消息处理类
*/
public class CustomHandler extends TextWebSocketHandler {
private Map<String, WebSocketSession> nameAndSession = new ConcurrentHashMap<>();
// 建立连接时候触发
@Override
public void afterConnectionEstablished(WebSocketSession session) {
String username = getNameFromSession(session);
nameAndSession.putIfAbsent(username, session);
}
// 关闭连接时候触发
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
String username = getNameFromSession(session);
nameAndSession.remove(username);
}
// 处理消息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 防止中文乱码
String msg = URLDecoder.decode(message.getPayload(), "utf-8");
String username = getNameFromSession(session);
// 简单模拟群发消息
TextMessage reply = new TextMessage(username + " : " + msg);
nameAndSession.forEach((s, webSocketSession)
-> {
try {
webSocketSession.sendMessage(reply);
} catch (IOException e) {
e.printStackTrace();
}
});
}
private String getNameFromSession(WebSocketSession session) {
Map<String, Object> attributes = session.getAttributes();
return (String) attributes.get(Constant.USER_NAME);
}
}
2.2 创建websocket 握手拦截器(如果没有权限拦截等需求,这一步不是必须的)
/**
* @author : heibaiying
* @description : 可以按照需求实现权限拦截等功能
*/
public class CustomHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
InetSocketAddress remoteAddress = request.getRemoteAddress();
InetAddress address = remoteAddress.getAddress();
System.out.println(address);
/*
* 最后需要要显示调用父类方法,父类的beforeHandshake方法
* 把ServerHttpRequest 中session中对应的值拷贝到WebSocketSession中。
* 如果我们没有实现这个方法,我们在最后的handler处理中 是拿不到 session中的值
* 作为测试 可以注释掉下面这一行 可以发现自定义处理器中session的username总是为空
*/
return super.beforeHandshake(request, response, wsHandler, attributes);
}
}
2.3 配置websocket
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<!-- 开启注解包扫描-->
<context:component-scan base-package="com.heibaiying.*"/>
<!--使用默认的Servlet来响应静态文件 -->
<mvc:default-servlet-handler/>
<!-- 开启注解驱动 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!--配置webSocket-->
<bean id="customHandler" class="com.heibaiying.websocket.CustomHandler"/>
<websocket:handlers>
<!--指定webSocket 地址-->
<websocket:mapping path="/socket" handler="customHandler"/>
<!--webSocket握手-->
<websocket:handshake-interceptors>
<bean class="com.heibaiying.websocket.CustomHandshakeInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
</beans>
2.4 前端 websocket 的实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>${sessionScope.get("username")}您好!欢迎进入群聊大厅!</title>
</head>
<body>
<input id="message" type="text">
<button id="btn">发送消息</button>
<div id="show">
</div>
<script>
let btn = document.getElementById("btn");
let message = document.getElementById("message");
let show = document.getElementById("show");
let ws = new WebSocket("ws://localhost:8080/socket");
ws.onmessage = function (evt) {
let node = document.createElement("div");
node.innerHTML = "<h5>" + evt.data + "</h5>";
show.appendChild(node);
};
btn.addEventListener("click", function () {
let data = message.value;
console.log(data);
if (data) {
ws.send(encodeURI(data));
} else {
alert("请输入消息后发送");
}
message.value = "";
});
// 关闭页面时候关闭ws
window.addEventListener("beforeunload", function(event) {
ws.close();
});
</script>
</body>
</html>
2.5 简单登录的实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="post">
<input name="username" type="text">
<button id="btn">输入临时用户名后登录!</button>
</form>
</body>
</html>
@Controller
public class LoginController {
@PostMapping("login")
public String login(String username, HttpSession session){
session.setAttribute(Constant.USER_NAME,username);
return "chat";
}
}
附:源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all
spring 5.x 系列第17篇 —— 整合websocket (xml配置方式)的更多相关文章
- spring 5.x 系列第18篇 —— 整合websocket (代码配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 项目模拟一个简单的群聊功能,为区分不同的聊 ...
- spring 5.x 系列第13篇 —— 整合RabbitMQ (xml配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...
- spring 5.x 系列第11篇 —— 整合memcached (xml配置方式)
文章目录 一.说明 1.1 XMemcached客户端说明 1.2 项目结构说明 1.3 依赖说明 二.spring 整合 memcached 2.1 单机配置 2.2 集群配置 2.3 存储基本类型 ...
- spring 5.x 系列第9篇 —— 整合mongodb (xml配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 配置文件位于resources下,项目以单 ...
- spring 5.x 系列第15篇 —— 整合dubbo (xml配置方式)
文章目录 一. 项目结构说明 二.项目依赖 三.公共模块(dubbo-common) 四. 服务提供者(dubbo-provider) 4.1 productService是服务的提供者( 商品数据用 ...
- spring 5.x 系列第1篇 —— springmvc基础 (xml配置方式)
文章目录 一.搭建hello spring工程 1.1 项目搭建 1.2 相关配置讲解 二.配置自定义拦截器 三.全局异常处理 四.参数绑定 4.1 参数绑定 4.2 关于日期格式转换的三种方法 五. ...
- spring 5.x 系列第14篇 —— 整合RabbitMQ (代码配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...
- spring 5.x 系列第12篇 —— 整合memcached (代码配置方式)
文章目录 一.说明 1.1 XMemcached客户端说明 1.2 项目结构说明 1.3 依赖说明 二.spring 整合 memcached 2.1 单机配置 2.2 集群配置 2.3 存储基本类型 ...
- spring 5.x 系列第10篇 —— 整合mongodb (代码配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 配置文件位于com.heibaiying. ...
随机推荐
- Delphi 快速获取文件大小(使用_lopen和FileSeek,此函数可以快速获取文件大小,即使文件已经被其它程序锁定)
function GetFileSize(const fName: AnsiString): Int64; var hFile: THandle; begin hFile := _lopen(PAns ...
- A熟知SP.NET---WebForms UnobtrusiveValidationMode 必须“jquery”ScriptResourceMapping。
我相信,有过ASP.NET人们学习经验RequiredFieldValidator控制(验证非空控制)一定不会陌生,禁止控制输入定义的内容的作用(该属性InitialValue的值.属性默认值为空字符 ...
- WPF 圆形Loading
原文:WPF 圆形Loading 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a771948524/article/details/9271933 ...
- python下载图片(2)
#-*- coding: UTF-8 -*- import urllib2, re,datetime,time, os,sys from PIL import Image, ImageDraw, Im ...
- cocos2dx 2.2.3 xcode5.0,新mac项目错误
cocos2dx 2.2.3 xcode5.0,新建mac项目报错 Undefined symbols for architecture x86_64: "cocos2d::extens ...
- 开源mvcpager分页控件分页实例
最近MVC需要用到分页,然后在网上找了一圈,发现一个很好用的分页控件,在此要感谢作者的辛勤劳动. 下载Pager 这个分页控件也有Asp.net的支持,需要的去看看作者的主页 webdiyer 先看看 ...
- Java异常处理错误
Java异常处理错误 研究发现,在编译阶段的最佳时机错误,序之前.然而,编译期间并不能找出全部的错误,余下的问题必须在执行阶段解决.这就须要错误源通过某种方式把适当的信息传给某个接收者,该接收者知道怎 ...
- 【LeetCode】LRU Cache 解决报告
插话:只写了几个连续的博客,博客排名不再是实际"远在千里之外"该.我们已经进入2一万内. 再接再厉.油! Design and implement a data structure ...
- matplotlib简单的新手教程和动画
做数据分析,首先是要熟悉和理解数据,所以掌握一个趁手的可视化工具是很重要的,否则对数据连个主要的感性认识都没有,怎样进行下一步的design 点击打开链接 还有一个非常棒的资料 Matplotlib ...
- WPF 4 目录树型显示
原文:WPF 4 目录树型显示 本篇将通过WPF4 制作简单的目录树型结构显示实例,完成本篇内容我们将作出下图所示的应用程序. 从图中我们可以看到程序主要分为两部分:左边显示本地驱 ...