Train of thought / interface description
The back end is developed using the Springboot framework;
Since cross platform and multi language development is involved, in order to avoid frequent deployment caused by frequent changes to the back-end in the future, the back-end is designed to be simpler, and the data processing is handed over to the terminal and equipment.
The back-end code refers to the article of the big blogger:
Spring boot + websocket to build an online chat room (group chat + single chat)
Interface to send data to the back end
URL: /websocket/{device}
The path parameter device is the name of the device connecting to the server
Parameters:
{ "type": 1, "toPlatform":["MacBook", "WM7"], "msgType": "MasterControl", "msg": "ABBA ABBA" }
type: the mode of data transmission. It is a parameter I reserve. It doesn't need to be ignored. I set it to 1;
toPlatform: an array of String class, which is the array of device names to which the information needs to be sent;
msg: json string converted from a data class;
msgType: the name of the original class of msg. The device receiving data uses this name to resolve msg through factory mode.
Back end sending data format
Parameters:
{ "fromPlatform": "Raspberry Pi", "msgType": "MasterControl", "msg": "ABBA ABBA" }
From platfrom: indicates that the data is sent by the device with this name;
msgType and msg are the same as above.
realization
Project creation and other configurations
I use IDEA for development.
Select the Spring Initializr project;
Depending on your own needs, you must choose WebSocket;
I use application.properties for configuration;
Modify the parameters such as server.port, application.name, url and password as needed;
Here, I select the dependency of Mysql Server. A database connection must be configured, otherwise it cannot be deployed; It is also convenient to expand database related functions later.
Import pom.xml into fastjason: (it can be replaced with another JSON parsing library)
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency>
Config file
Because I use websocket dependency and FastJson Library (which can be replaced by other JSON parsing libraries), and these two libraries have painful bug s, two config files need to be configured:
WebSocketConfig.java
// package com.wmiii.wmsocket.config; Change to your own package path import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
FJsonConfig.java
// package com.wmiii.wmsocket.config; Change to your own package path import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @Configuration public class FJsonConfig { @Bean public HttpMessageConverter configureMessageConverters() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures( // Leave empty fields SerializerFeature.WriteMapNullValue, // Convert null of String type to '' SerializerFeature.WriteNullStringAsEmpty, // Convert null of type Number to 0 SerializerFeature.WriteNullNumberAsZero, // Convert null of List type to [] SerializerFeature.WriteNullListAsEmpty, // Convert null of Boolean type to false SerializerFeature.WriteNullBooleanAsFalse, // Avoid circular references SerializerFeature.DisableCircularReferenceDetect); converter.setFastJsonConfig(config); converter.setDefaultCharset(Charset.forName("UTF-8")); List<MediaType> mediaTypeList = new ArrayList<>(); // To solve the problem of Chinese garbled code is equivalent to adding an attribute products = "application / JSON" to @ RequestMapping on the Controller mediaTypeList.add(MediaType.APPLICATION_JSON); converter.setSupportedMediaTypes(mediaTypeList); return converter; } }
Parameter class code
(I took the class name randomly
Back end receive information parameter class
BaseMsg.java
// package com.wmiii.wmsocket.msg; Change to your own package path import lombok.Data; // Remember to import lombok dependencies import java.util.ArrayList; @Data public class BaseMsg { Integer type; // 1 is the designated sending object, and the rest are tentatively broadcast test ArrayList<String> toPlatform; String msgType; String msg; // For msg in json format, the back end does not need to care about the specific content }
Back end sending information parameter class
ToMsgParam.java
// package com.wmiii.wmsocket.param; Change to your own package path import lombok.Data; @Data public class ToMsgParam { String fromPlatform; String msgType; String msg; // JSON formatted data }
WebSocket business processing code
// Omit import @ServerEndpoint(value = "/websocket/{device}") @Component public class WmWebSocket { @OnOpen public void onOpen(Session session, @PathParam("device") String device) { } /** * Method called for connection closure */ @OnClose public void onClose() { } /** * Method of calling after receiving client message * * @param message Messages sent by the client*/ @OnMessage public void onMessage(String message, Session session, @PathParam("device") String device) { } /** * Called when an error occurs *te */ @OnError public void onError(Session session, Throwable error) { } }
For a class with @ ServerEndpoint annotation, it will be regarded as a component to handle the websocket business of the corresponding url; four annotation methods need to be implemented:
Methods with @ OnOpen annotation: called when a new websocket connection is created;
Methods with @ OnClose annotation: called when the websocket connection is disconnected;
Methods with @ OnMessage annotation: called when a message is received;
Methods with @ OnError annotation: called when an error occurs;
finished product
(just look at the notes. I'm too lazy to type otherwise
// Omit import @ServerEndpoint(value = "/websocket/{device}") @Component public class WmWebSocket { //It is used to store the WmWebSocket object corresponding to each client. private static CopyOnWriteArraySet<WmWebSocket> webSocketSet = new CopyOnWriteArraySet<WmWebSocket>(); //The connection session with a client needs to send data to the client through it private Session session; private String device; //It is used to record the platform name and bind the session private static Map<String,Session> deviceMap = new HashMap<String, Session>(); @OnOpen public void onOpen(Session session, @PathParam("device") String device) { this.session = session; this.device = device; deviceMap.put(device, session); webSocketSet.add(this); // Add to set System.out.println("equipment" + device +"join, The current number of devices is" + webSocketSet.size()); this.session.getAsyncRemote().sendText(device+"Successfully connected to WebSocket(sessionId: "+session.getId()+")-->Current number of online devices: "+webSocketSet.size()); } /** * Method called for connection closure */ @OnClose public void onClose() { webSocketSet.remove(this); // Delete from set deviceMap.remove(device); System.out.println("equipment" + this.device +"Connection closed! Number of devices currently online: " + webSocketSet.size()); } /** * Method of calling after receiving client message * * @param message Messages sent by the client*/ @OnMessage public void onMessage(String message, Session session, @PathParam("device") String device) { System.out.println(device + ": " + message); BaseMsg baseMsg; try { baseMsg = JSON.parseObject(message, BaseMsg.class); switch (baseMsg.getType()) { case 1: ToMsgParam toMsgParam = new ToMsgParam(); toMsgParam.setFromPlatform(device); toMsgParam.setMsgType(baseMsg.getMsgType()); toMsgParam.setMsg(baseMsg.getMsg()); String toMsg = JSON.toJSONString(toMsgParam); Session fromSession = deviceMap.get(device); Session toSession; // Get data target device list ArrayList<String> toList = baseMsg.getToPlatform(); // The target device used to store data transmission failure is temporarily useless; ArrayList<String> failed = new ArrayList<>(); // Query the session map one by one to send data for(String toPlatform: toList) { toSession = deviceMap.get(toPlatform); try { toSession.getAsyncRemote().sendText(toMsg); } catch (Exception e) { // If the data transmission of the target platform fails, it will be added to the transmission failure list, which is temporarily useless; failed.add(toPlatform); } } break; default: System.out.println("default"); } } catch (Exception e){ e.printStackTrace(); } } /** * Called when an error occurs */ @OnError public void onError(Session session, Throwable error) { System.out.println("An error occurred"); error.printStackTrace(); } }
deploy
Use pagoda panel deployment and jar package deployment.
Select Maven on the right side of IDEA and run package under Lifecycle:
Then find a generated. jar file in the target folder under the project root directory and upload it to the ECS;
Remember to open the set project port on the server (mine is 8880).
Run under the path of uploading jar package:
nohup java -jar xxx.jar &
xxx here is the name of your jar package, and the deployment is completed.
test
Recently (when writing this article), postman updated the test of WebSocket interface; click New on the right side of Workspace and select WebSocket Request.
(finally, you don't have to write your own HTML test)