WebSocket — это сетевая технология, предоставляемая HTML5 для полнодуплексной связи между браузерами и серверами. Протокол связи WebSocket был установлен IETF в качестве стандарта RFC 6455 в 2011 году, а API WebSocket был установлен W3C в качестве стандарта. В WebSocket API браузеру и серверу достаточно сделать рукопожатие, после чего между браузером и сервером формируется быстрый канал. Данные могут передаваться напрямую между ними.
Взято из вышеперечисленногоWikipedia.
В этой статье будут описаныIntellij IDEA
использовать подGradle
ПостроитьSpringMVC
+WebSocket
Реализовать push-уведомление. Чтобы удобнее было читать, нажмитечитать оригинал😉.
Создать проект
Подробные описания есть в предыдущих статьях, и в этой статье они повторяться не будут.IDEA+Gradle создает проект MyBatis+SpringMVC
импортировать зависимости
существуетbuild.gradle
импорт зависит от
// ------------------------ Spring SpringMVC start -------------------------
compile group: 'org.springframework', name: 'spring-webmvc', version: '4.2.4.RELEASE'
compile group: 'org.springframework', name: 'spring-context-support', version: '4.2.4.RELEASE'
// ------------------------ Spring SpringMVC end -------------------------
// ------------------------ WebSocket start -------------------------
compile group: 'org.springframework', name: 'spring-websocket', version: '4.2.4.RELEASE'
compile group: 'org.springframework', name: 'spring-messaging', version: '4.2.4.RELEASE'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
// ------------------------ WebSocket end -------------------------
compile group: 'log4j', name: 'log4j', version: '1.2.17'
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.2'
Здесь следует отметить, чтоSpring
от4.0+
версия стала поддерживать WebSocket, аservlet-api
должно быть3.0+
Версияконфигурационный файл
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 初始化spring 容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/spring/applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>index-dispather</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>index-dispather</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决post乱码问题 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Здесь нужно датьservlet
иfilter
добавить асинхронный<async-supported>true</async-supported>
.
spring-mvc.xml
<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"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描控制器,webSocket -->
<context:component-scan base-package="com.lhalcyon.king.controller,com.lhalcyon.king.socket"/>
<!-- 视图渲染 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 控制器映射器和控制器适配器 -->
<mvc:annotation-driven>
</mvc:annotation-driven>
<!-- 静态资源映射器 -->
<mvc:resources mapping="/statics/**" location="/WEB-INF/statics/" />
</beans>
Здесь вам нужно настроить пакет, в котором находится контроллер сканирования и веб-сокет.
есть еще одинapplicationContext-websocket.xml
Файл конфигурации объясняется в реализации кода
Код
перехватчик рукопожатия
HandshakeInterceptor
Описание перехватчика
Перехватчик для копирования информации из HTTP-сессии в «рукопожатие».
атрибуты», чтобы сделать его доступным черезWebSocketSession.getAttributes()
Copies a subset or all HTTP session attributes and/or the HTTP session id
Перехватчик в основном используется для записи идентификатора входа пользователя, что удобно для последующего получения идентификатора сеанса указанного пользователя и отправки сообщений указанному пользователю.
Здесь мы наследуемHttpSessionHandshakeInterceptor
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
private Logger logger = Logger.getLogger(HandshakeInterceptor.class);
// 握手前
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
logger.info("++ HandshakeInterceptor: beforeHandshake ++"+attributes);
return super.beforeHandshake(request, response, wsHandler, attributes);
}
// 握手后
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
logger.info("++ HandshakeInterceptor: afterHandshake ++");
super.afterHandshake(request, response, wsHandler, ex);
}
}
beforeHandshake(..)
Invoked before the handshake is processed.
afterHandshake(..)
Invoked after the handshake is done. The response status and headers indicate the results of the handshake, i.e. whether it was successful or not.
Синхронизация двух вызовов методов описана буквально, и вызываются они до и после рукопожатия, главное что-то сделать до и после рукопожатия, например установить необходимые данные вattributes
в , то вWebSocketHandler
Получите эти данные из сеанса.
Класс обработки
WebSocketHandler
public class MyWebSocketHandler implements WebSocketHandler {
private static final Logger log = Logger.getLogger(MyWebSocketHandler.class);
// 保存所有的用户session
private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info("connect websocket success.......");
users.add(session);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
Gson gson = new Gson();
// 将消息JSON格式通过Gson转换成Map
// message.getPayload().toString() 获取消息具体内容
Map<String, Object> msg = gson.fromJson(message.getPayload().toString(),
new TypeToken<Map<String, Object>>() {}.getType());
log.info("handleMessage......."+message.getPayload()+"..........."+msg);
String content = message.getPayload().toString();
// 处理消息 msgContent消息内容
TextMessage textMessage = new TextMessage(content, true);
// 调用方法(发送消息给所有人)
sendMsgToAllUsers(textMessage);
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
log.warn("handleTransportError");
users.remove(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
log.info("connect websocket closed.......");
users.remove(session);
}
// 给所有用户发送 信息
public void sendMsgToAllUsers(WebSocketMessage<?> message) throws Exception{
for (WebSocketSession user : users) {
user.sendMessage(message);
}
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
Основные методы описаны ниже:
afterConnectionEstablished(..)
Вызывается после установления соединения, часто используется для записи идентификатора соединения пользователя, что удобно для последующей отправки информации.
handleTextMessage(..)
Обработайте сообщение.
handleTransportError(..)
Обработка исключений соединения. Необходимо закрыть соединение сеанса ошибки.
afterConnectionClosed(..)
Обработка закрытия соединения
Здесь наша обработка сообщения очень проста, то есть после принятия сообщения оно отправляется всем подключенным пользователям, аналогично анонимному групповому чату.
регистр
После завершения класса обработки WebSocket вам все равно нужно зарегистрировать его, чтобы он вступил в силу.Есть два способа, вы можете выбрать один.
Создайте класс конфигурации и зарегистрируйте его через аннотации
@Configuration
@EnableWebMvc
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//前台 可以使用websocket环境
registry.addHandler(myWebSocketHandler(),"/websocket").addInterceptors(new HandshakeInterceptor()).setAllowedOrigins("*");
//前台 不可以使用websocket环境,则使用sockjs进行模拟连接
registry.addHandler(myWebSocketHandler(), "/sockjs/websocket").addInterceptors(new HandshakeInterceptor())
.withSockJS();
}
// websocket 处理类
@Bean
public WebSocketHandler myWebSocketHandler(){
return new MyWebSocketHandler();
}
}
Вам также необходимо настроить класс конфигурации сканирования Spring, упомянутый выше.
<!-- 自动扫描控制器,webSocket -->
<context:component-scan base-package="com.lhalcyon.king.controller,com.lhalcyon.king.socket"/>
Зарегистрируйтесь через конфигурацию xml
applicationContext-websocket.xml
<?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:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd">
<!-- websocket处理类 -->
<bean id="myHandler" class="com.lhalcyon.king.socket.MyWebSocketHandler"/>
<!-- 握手接口/拦截器 -->
<bean id="myInterceptor" class="com.lhalcyon.king.socket.HandshakeInterceptor"/>
<websocket:handlers>
<websocket:mapping path="/websocket" handler="myHandler"/>
<websocket:handshake-interceptors>
<ref bean="myInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
<!-- 注册 sockJS -->
<websocket:handlers>
<websocket:mapping path="/websocket" handler="myHandler"/>
<websocket:handshake-interceptors>
<ref bean="myInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs />
</websocket:handlers>
</beans>
Приведенная выше реализация кода на стороне сервера в основном завершена, а затем выполняется простая реализация тестовой страницы на стороне клиента.
клиентская страница
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE HTML>
<html>
<head>
<title>首页</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="renderer" content="webkit">
<!-- 引入 JQuery -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<!-- 引入 sockJS -->
<script type="text/javascript" src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js" ></script>
<script type="text/javascript">
$(function() {
var websocket;
// 首先判断是否 支持 WebSocket
var url = 'ws://' + window.location.host + '/word-king/websocket';
if('WebSocket' in window) {
websocket = new WebSocket(url);
} else if('MozWebSocket' in window) {
websocket = new MozWebSocket(url);
} else {
url = "http://"+ window.location.host +"/word-king/sockjs/websocket";
websocket = new SockJS(url);
}
// 打开时
websocket.onopen = function(evnt) {
console.log(" websocket.onopen ");
};
// 处理消息时
websocket.onmessage = function(evnt) {
$("#msg").append("<p>(<font color='red'>" + evnt.data + "</font>)</p>");
console.log(" websocket.onmessage ");
};
websocket.onerror = function(evnt) {
alert("onerror");
console.log(" websocket.onerror ");
};
websocket.onclose = function(evnt) {
console.log(" websocket.onclose ");
alert("onclose");
};
// 点击了发送消息按钮的响应事件
$("#TXBTN").click(function(){
// 获取消息内容
var text = $("#tx").val();
// 判断
if(text == null || text == ""){
alert(" content can not empty!!");
return false;
}
var msg = {
msgContent: text,
postsId: 1
};
// 发送消息
websocket.send(JSON.stringify(msg));
});
});
</script>
</head>
<body>
<!-- 最外边框 -->
<div style="margin: 20px auto; border: 1px solid blue; width: 300px; height: 500px;">
<!-- 消息展示框 -->
<div id="msg" style="width: 100%; height: 70%; border: 1px solid yellow;overflow: auto;"></div>
<!-- 消息编辑框 -->
<textarea id="tx" style="width: 100%; height: 20%;"></textarea>
<!-- 消息发送按钮 -->
<button id="TXBTN" style="width: 100%; height: 8%;">发送数据</button>
</div>
</body>
</html>
Следует отметить, что введение здесьJQuery
, если это локальный файл, он может быть недействительным, вам нужно установить путь сопоставления статического ресурса, вы можете решить это самостоятельно.
В этой статье используется введение онлайн-адресов
<!-- 引入 JQuery -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.5/jquery.min.js"></script>
После того, как адрес написан, его нужно скачать
Код вступит в силу после того, как предупреждение не будет выделено.
Наконец, давайте посмотрим на эффект
- Ссылаться на:blog.CSDN.net/no book20131…