Combining Spring with Websocket to Push Messages

Keywords: Session Java xml Spring

There are three main steps in this paper.

1. Build a websocket connection after the user logs in, and choose the websocket connection by default. If the browser does not support it, use sockjs to simulate the connection.
2. After establishing the connection, the server returns the unread message of the user.
3. After relevant operation, the server pushes Spring 4.0.6 (to choose 4.0+), Tomcat 7.0.55 to a user or all users'new message-related environment.

Web ocet server implementation

WebSocketConfig.java

@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new    WebSocketHandshakeInterceptor());
        registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
.withSockJS();
    }
    @Bean
    public WebSocketHandler systemWebSocketHandler(){
        return new SystemWebSocketHandler();
    }
}

Don't forget to configure automatic scanning of this type in the configuration file of spring MVC

<context:component-scan base-package="com.ldl.origami.websocket" />

@Configuration
@EnableWebMvc
@EnableWebSocket

These three basically mean that this class supports loading beans in the way of @bean, and spring MVC and websocket. It's not very accurate. Just try @Enable WebMvc without adding it. Configuration already supports automatic scanning of spring mvc.

registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())

To register the websocket server implementation class, the second parameter is to access the address of the websocket

registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
.withSockJS();
}

This is the registration method using Sockjs

First, SystemWebSocketHandler.java

public class SystemWebSocketHandler implements WebSocketHandler {
private static final Logger logger;
private static final ArrayList<WebSocketSession> users;
static {
users = new ArrayList<>();
logger = LoggerFactory.getLogger(SystemWebSocketHandler.class);
}
@Autowired
private WebSocketService webSocketService;
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.debug("connect to the websocket success......");
users.add(session);
String userName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
if(userName!= null){
//Query unread messages
int count = webSocketService.getUnReadNews((String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
session.sendMessage(new TextMessage(count + ""));
}
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
//sendMessageToUsers();
}
@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;
}
/**
* Send messages to all online users
*
* @param message
*/
public void sendMessageToUsers(TextMessage message) {
for (WebSocketSession user : users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Send a message to a user
*
* @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;
}
}
}
}

As soon as you look at the relevant content, you will understand it, but you will not explain it much.

Then WebSocketHandshakeInterceptor.java

public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {
private static Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.class);
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object
> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
if (session != null) {
//Use userName to differentiate WebSocketHandler for directional messaging
String userName = (String) session.getAttribute(Constants.SESSION_USERNAME);
attributes.put(Constants.WEBSOCKET_USERNAME,userName);
}
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
}
}

The main function of this is to get the user name in the current request and save it in the current WebSocket Handler to determine the corresponding user of WebSocket Handler, referring specifically to HttpSession Handshake Interceptor.

User login to establish websocket connection

index.jsp

<script type="text/javascript" src="http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"></script>
<script>
var websocket;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/Origami/webSocketServer");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost:8080/Origami/webSocketServer");
} else {
websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");
}
websocket.onopen = function (evnt) {
};
websocket.onmessage = function (evnt) {
$("#msgcount").html("(<font color='red'>"+evnt.data+"</font>)")
};
websocket.onerror = function (evnt) {
};
websocket.onclose = function (evnt) {
}
</script>

Note when using sockjs

1. Writing of the two

<script type="text/javascript" src="http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"></script>
websocket = new SockJS(<a href="http://localhost:8080/Origami/sockjs/webSocketServer">http://localhost:8080/Origami/sockjs/webSocketServer</a>);

2. In web.xml

<web-app version="3.0" 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_1.xsd">

version

web-app_3_1.xsd

Both versions are 3.0+

Then add it to the servlet

<async-supported>true</async-supported>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>

Then all filter s are added.

<async-supported>true</async-supported>

3. Adding Relevant Dependencies

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>

Okay, now websocket can be set up properly

Returns unread messages for users

When the connection is established, it enters the system WebSocketHandler's after Connection Established method. The code looks up and takes out the user name saved in the WebSocketHandshake Interceptor.

Use session.sendMessage(new TextMessage(count + "") after querying information; return to the user, from where to where

Server pushes messages to users

@Controller
public class AdminController {
static Logger logger = LoggerFactory.getLogger(AdminController.class);
@Autowired(required = false)
private AdminService adminService;
@Bean
public SystemWebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
@RequestMapping("/auditing")
@ResponseBody
public String auditing(HttpServletRequest request){
//Irrelevant code is omitted
int unReadNewsCount = adminService.getUnReadNews(username);
systemWebSocketHandler().sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
return result;
}
}

Here you can use sendMessageToUser to push information to a user or sendMessageToUsers to push information to all users.

Posted by funkyres on Sun, 07 Jul 2019 11:14:51 -0700