第一步: 添加Spring WebSocket的依赖jar包
<!-- 使用spring websocket依赖的jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring-framework.version}</version>
</dependency>
第二步:建立一个类实现WebSocketConfigurer接口
package com.my.spring.context;
import com.my.business.spring.SpringWebSocketHandler;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
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 org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.HashMap;
/**
* Spring Context - web socket配置
* @author my Team
* @version 2.0
* @see com.my.business.spring.SpringWebSocketHandler
*/
@AllArgsConstructor(onConstructor = @__({@Autowired}))
@EnableWebMvc
@EnableWebSocket
public class SpringWebSocketConfig extends WebMvcConfigurationSupport implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//HttpSessionHandshakeInterceptor拦截器,可以自定义,由于系统实现了session登录,这里就不需要再实现session与用户的绑定。
registry.addHandler(webSocketHandler(), "/websocket").addInterceptors(new HttpSessionHandshakeInterceptor());
registry.addHandler(webSocketHandler(), "/sockjs").addInterceptors(new HttpSessionHandshakeInterceptor()).withSockJS();
}
@Bean
public TextWebSocketHandler webSocketHandler(){
SpringWebSocketHandler springWebSocketHandler = new SpringWebSocketHandler();
return springWebSocketHandler;
}
}
第三步:继承WebSocketHandler对象。
实现websocket的登录、关闭、异常、发送消息等方法。
package com.my.business.spring;
import com.my.business.entity.Person;
import com.my.business.model.Principal;
import com.my.business.service.PersonService;
import com.my.spring.context.ApplicationUtils;
import com.my.spring.core.Assert;
import lombok.Setter;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.standard.StandardWebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* websocket 发送消息
*/
public class SpringWebSocketHandler extends TextWebSocketHandler {
@Setter
private static Map<Long, WebSocketSession> sessionMap = new HashMap<>();
/**
* 连接成功的时候,触发页面上onopen方法
* @param session session
* @throws Exception 异常
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Person person = getLoginer(session);
Assert.notNull(person);
sessionMap.put(person.getId(), session);
//TODO 发送离线消息
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
Person person = getLoginer(session);
Assert.notNull(person);
sessionMap.remove(person.getId());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
}
Person person = getLoginer(session);
if (person != null) {
sessionMap.remove(person.getId());
}
}
/**
* 获取当前登录人。这里直接获取用户登录拦截器所存入的用户session
* @param session session
* @return 登录人
*/
private Person getLoginer(WebSocketSession session) {
Assert.notNull(session);
SimplePrincipalCollection simplePrincipalCollection = (SimplePrincipalCollection) session.getAttributes().get(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (simplePrincipalCollection == null) {
return null;
}
Set<Object> objectSet = simplePrincipalCollection.asSet();
for (Object object : objectSet) {
if (object instanceof Principal) {
Principal principal = (Principal) object;
return ApplicationUtils.getBean(PersonService.class).findByUser(principal.getSn());
}
}
return null;
}
/**
* 发送消息
* @param session session
* @param message 消息内容
*/
private boolean sendMessage(WebSocketSession session, TextMessage message) throws IOException {
Assert.notNull(session);
Assert.notNull(message);
if (session.isOpen()) {
session.sendMessage(message);
return true;
} else {
return false;
}
}
/**
* 向用户发送消息
* @param personId 用户id
* @param message message
* @return
*/
public boolean sendMessageToUser(Long personId, String message) {
Assert.notNull(personId);
Assert.notEmpty(message);
WebSocketSession session = sessionMap.get(personId);
if (session == null) {
return false;
}
TextMessage textMessage = new TextMessage(message);
try {
return sendMessage(session, textMessage);
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
第四部 测试代码
HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="./resources/js/jquery-1.11.3.min.js"></script>
<script src="./resources/js/sockjs.js"></script>
<script>
var websocket = null;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8801/websocket");
}
else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost:8801/websocket");
}
else {
websocket = new SockJS("http://localhost:8801/sockjs");
}
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("连接失败!");
}
}
window.close=function()
{
websocket.onclose();
}
</script>
</body>
</html>
java代码
package com.my.business.controller;
import com.my.business.model.Pageable;
import com.my.business.service.PersonService;
import com.my.business.spring.SpringWebSocketHandler;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@AllArgsConstructor(onConstructor = @__({@Autowired}))
@Controller
@RequestMapping("/test")
public class TestController {
private PersonService personService;
private SpringWebSocketHandler webSocketHandler;
@RequestMapping(method = RequestMethod.GET)
public String test(String name, ModelMap model) {
model.addAttribute("name", name);
model.addAttribute("persons", personService.findPage(new Pageable()).getContent());
return "/test";
}
@ResponseBody
@RequestMapping(value = "/name", method = RequestMethod.GET)
public boolean name(String name) {
return webSocketHandler.sendMessageToUser(personService.findLoginer().getId(), "你好socket");
}
}
先访问http://localhost:8801/test返回页面,创建WebSocket连接,再访问http://localhost:8801/test/name向当前用户发送消息。