websocket 步骤 消息推送_WebSocket 学习教程(二):Spring websocket实现消息推送

===============================================

环境介绍:

Jdk 1.7 (1.6不支持)

Tomcat7.0.52 (支持Websocket协议)

Spring4.0.26 (支持Websocket)

web.xml(配置了前端自动优化HtmlCompressor和Druid监控),自动优化会影响Websocket js脚本,后面会讲

=================================================

配置步骤:

1. 引入Spring相关Jar,特别需要下面这两个

org.springframework

spring-websocket

4.0.6.RELEASE

org.springframework

spring-messaging

4.0.6.RELEASE

2. 编写WebSocketConfig implements WebSocketConfigurer

WebSocketConfig.java

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import org.springframework.web.socket.config.annotation.EnableWebSocket;

import org.springframework.web.socket.config.annotation.WebSocketConfigurer;

import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import org.springframework.web.socket.handler.TextWebSocketHandler;

import cn.com.ship.message.handler.ChatMessageHandler;

import cn.com.ship.message.handler.TextMessageHandler;

@Configuration

//@EnableWebMvc//这个标注可以不加,如果有加,要extends WebMvcConfigurerAdapter

@EnableWebSocket

public class WebSocketConfig implements WebSocketConfigurer {

@Override

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(chatMessageHandler(),"/websocket/chatMessageServer.do").addInterceptors(new ChatHandshakeInterceptor());

registry.addHandler(chatMessageHandler(), "/sockjs/chatMessageServer.do").addInterceptors(new ChatHandshakeInterceptor()).withSockJS();

}

@Bean

public TextWebSocketHandler chatMessageHandler(){

return new ChatMessageHandler();

}

}

3. 编写ChatMessageHandler extends TextWebSocketHandler

ChatMessageHandler.java

import java.io.IOException;

import java.util.ArrayList;

import org.apache.log4j.Logger;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

import cn.com.ship.message.common.Constants;

import cn.com.ship.message.common.MessageCriteria;

public class ChatMessageHandler extends TextWebSocketHandler{

private static final ArrayList users;//这个会出现性能问题,最好用Map来存储,key用userid

private static Logger logger = Logger.getLogger(ChatMessageHandler.class);

static {

users = new ArrayList();

}

public ChatMessageHandler() {

// TODO Auto-generated constructor stub

}

/**

* 连接成功时候,会触发UI上onopen方法

*/

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

System.out.println("connect to the websocket success......");

users.add(session);

//这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户

//TextMessage returnMessage = new TextMessage("你将收到的离线");

//session.sendMessage(returnMessage);

}

/**

* 在UI在用js调用websocket.send()时候,会调用该方法

*/

@Override

protected void handleTextMessage(WebSocketSession session,

TextMessage message) throws Exception {

super.handleTextMessage(session, message);

}

/**

* 给某个用户发送消息

*

* @param userName

* @param message

*/

public void sendMessageToUser(String userName, TextMessage message) {

for (WebSocketSession user : users) {

if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {

try {

if (user.isOpen()) {

user.sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

break;

}

}

}

/**

* 给所有在线用户发送消息

*

* @param message

*/

public void sendMessageToUsers(TextMessage message) {

for (WebSocketSession user : users) {

try {

if (user.isOpen()) {

user.sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

@Override

public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

if(session.isOpen()){

session.close();

}

logger.debug("websocket connection closed......");

users.remove(session);

}

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {

logger.debug("websocket connection closed......");

users.remove(session);

}

@Override

public boolean supportsPartialMessages() {

return false;

}

}

4. 编写websocket握手拦截器ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor

ChatHandshakeInterceptor.java

package cn.com.ship.message.websocket;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.http.server.ServletServerHttpRequest;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import cn.com.ship.message.common.Constants;

public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {

@Override

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception {

System.out.println("Before Handshake");

if (request instanceof ServletServerHttpRequest) {

ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;

HttpSession session = servletRequest.getServletRequest().getSession(false);

if (session != null) {

//使用userName区分WebSocketHandler,以便定向发送消息

String userName = (String) session.getAttribute(Constants.SESSION_USERNAME);

if (userName==null) {

userName="default-system";

}

attributes.put(Constants.WEBSOCKET_USERNAME,userName);

}

}

return super.beforeHandshake(request, response, wsHandler, attributes);

}

@Override

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {

System.out.println("After Handshake");

super.afterHandshake(request, response, wsHandler, ex);

}

}

4. 重点在Spring mvc相关配置(经常出现问题就是:中文乱码,如果是用ajax交互)

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"

xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"

xmlns:tool="http://www.springframework.org/schema/tool" xmlns:context="http://www.springframework.org/schema/context"

xmlns:task="http://www.springframework.org/schema/task"

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/tx

http://www.springframework.org/schema/tx/spring-tx.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/jee

http://www.springframework.org/schema/jee/spring-jee.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/util

http://www.springframework.org/schema/util/spring-util.xsd

http://www.springframework.org/schema/tool

http://www.springframework.org/schema/tool/spring-tool.xsd

http://www.springframework.org/schema/task

http://www.springframework.org/schema/task/spring-task.xsd

http://www.springframework.org/schema/websocket

http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">

class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />

class="org.springframework.http.converter.StringHttpMessageConverter">

text/plain;charset=UTF-8

class="cn.com.ship.external.spring.converter.json.MappingJackson2HttpMessageConverter">

application/json

class="cn.com.ship.external.spring.converter.json.MappingJackson2HttpMessageConverter">

text/json

class="org.springframework.web.servlet.view.UrlBasedViewResolver">

value="org.springframework.web.servlet.view.JstlView" />

class="org.springframework.web.multipart.commons.CommonsMultipartResolver"

p:defaultEncoding="utf-8">

注意:MappingJackson2HttpMessageConverter.java,来自Spring代码,并且修改了一点点,这个找到附件位置下载

5. jsp相关Websocket脚本编写

ws.jsp

Java API for WebSocket (JSR-356)

var websocket = null;

if ('WebSocket' in window) {

websocket = new WebSocket("ws://localhost:8080/ship/webSocketServer.do");

}

else if ('MozWebSocket' in window) {

websocket = new MozWebSocket("ws://localhost:8080/ship/webSocketServer.do");

}

else {

websocket = new SockJS("http://localhost:8080/ship/sockjs/webSocketServer.do");

}

websocket.onopen = onOpen;

websocket.onmessage = onMessage;

websocket.onerror = onError;

websocket.onclose = onClose;

function onOpen(openEvt) {

//alert(openEvt.Data);

}

function onMessage(evt) {

alert(evt.data);

}

function onError() {}

function onClose() {}

function doSend() {

if (websocket.readyState == websocket.OPEN) {

var msg = document.getElementById("inputMsg").value;

websocket.send(msg);//调用后台handleTextMessage方法

alert("发送成功!");

} else {

alert("连接失败!");

}

}

请输入:

发送

login.jsp

pageEncoding="UTF-8"%>

Java API for WebSocket (JSR-356)

登录名:

5. 调用端Controller编写 WebsocketController.java

package cn.com.ship.websocket.controller;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

@Controller

public class WebsocketController {

@Bean//这个注解会从Spring容器拿出Bean

public InfoHandler infoHandler() {

return new InfoHandler();

}

@RequestMapping("/websocket/login")

public void login(HttpServletRequest request, HttpServletResponse response) throws Exception {

String username = request.getParameter("username");

HttpSession session = request.getSession(false);

session.setAttribute(Constants.SESSION_USERNAME, username);

response.sendRedirect("/ship/websocket/ws.jsp");

}

@RequestMapping("/websocket/send")

@ResponseBody

public String send(HttpServletRequest request) {

String username = request.getParameter("username");

infoHandler().sendMessageToUser(username, new TextMessage("你好,测试!!!!"));

return null;

}

}

6. 测试Websocket是否连接成功

先在login.jsp上随便输入用户名,然后WebsocketController处理完请求,会重定向到ws.jsp

如果后台打印出现消息,证明Websocket连接成功(前两名消息是在ChatHandshakeInterceptor.java,最后一句是在ChatMessageHandler.java)

Before Handshake

After Handshake

connect to the websocket success......

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现消息推送的关键是要使用 WebSocket 技术。WebSocket 是一种基于 TCP 的协议,它提供了双向通信的功能,使得服务器可以主动向客户端推送消息。 下面是使用 Spring Boot 整合 WebSocket 实现消息推送步骤: 1. 添加依赖 在 pom.xml 文件中添加 Spring WebSocket 的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 2. 创建 WebSocket 配置类 创建一个 WebSocketConfig 类,注入 ServerEndpointExporter 对象,使得 Spring Boot 自动配置 WebSocket 的相关类: ```java @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } ``` 3. 创建 WebSocket 处理类 创建一个 WebSocketHandler 类,使用 @ServerEndpoint 注解标识该类为 WebSocket 处理类,并实现 onOpen、onClose、onMessage 和 onError 四个方法: ```java @ServerEndpoint("/websocket") @Component public class WebSocketHandler { private static CopyOnWriteArraySet<WebSocketHandler> webSocketSet = new CopyOnWriteArraySet<>(); private Session session; @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); } @OnClose public void onClose() { webSocketSet.remove(this); } @OnMessage public void onMessage(String message) { // 处理客户端发来的消息 } @OnError public void onError(Throwable error) { error.printStackTrace(); } } ``` 其中,@ServerEndpoint("/websocket") 注解表示 WebSocket 的访问路径。 4. 客户端连接 在客户端页面中,使用 JavaScript 创建 WebSocket 对象,并指定连接地址: ```javascript let websocket = new WebSocket("ws://localhost:8080/websocket"); ``` 5. 服务端推送消息WebSocketHandler 类中,可以通过调用所有 WebSocketHandler 对象的 session 对象,向客户端推送消息: ```java webSocketSet.forEach(handler -> { try { handler.session.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } }); ``` 6. 配置 Nginx 如果需要使用 Nginx 进行反向代理,需要在 Nginx 的配置文件中添加如下配置: ```nginx location /websocket { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } ``` 7. 在 Vue 中接收消息 在 Vue 中,可以通过监听 WebSocket 的 onmessage 事件,来接收 WebSocket 服务器推送消息: ```javascript websocket.onmessage = function(event) { let message = event.data; // 处理推送消息 }; ``` 至此,Spring Boot 和 Vue 的 WebSocket 消息推送实现了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值