基于websocket的跨平台通信——iPhone/iPad/Mac控制树莓派(一):Springboot后端搭建

编程入门 行业动态 更新时间:2024-10-09 20:30:01

基于websocket的跨平台通信——iPhone/iPad/Mac控制树莓派(一):Springboot<a href=https://www.elefans.com/category/jswz/34/1771414.html style=后端搭建"/>

基于websocket的跨平台通信——iPhone/iPad/Mac控制树莓派(一):Springboot后端搭建

基于websocket的跨平台通信——iPhone/iPad/Mac控制树莓派(一):后端搭建

  • 思路/接口说明
    • 后端代码参考了这位大佬博主的文章:
    • 发送数据到后端的接口
    • 后端发送数据格式
  • 实现
    • 工程创建等配置
    • Config文件
      • WebSocketConfig.java
      • FJsonConfig.java
    • 参数类代码
      • 后端接收信息参数类
      • 后端发送信息参数类
    • WebSocket业务处理代码
      • 成品
    • 部署
    • 测试

基于websocket的跨平台通信——iPhone/iPad/Mac控制树莓派

思路/接口说明

后端采用Springboot框架开发;

由于涉及到跨平台、多种语言的开发,为了避免今后对后端频繁的更改导致频繁的部署,以及保证我的1元包年拉跨1核2G服务器不会动不动就跑满CPU,后端我们就设计的简单一些,数据处理统统交给终端和设备来做。

后端代码参考了这位大佬博主的文章:

springboot+websocket构建在线聊天室(群聊+单聊)

发送数据到后端的接口

URL:/websocket/{device}
路径参数device为连接服务器的设备名称

参数:

{"type": 1,"toPlatform":["MacBook", "WM7"],"msgType": "MasterControl","msg": "阿巴阿巴"
}

type:数据发送的模式,我预留的一个参数,无需理会,我固定设置为1;
toPlatform:一个String类的数组,为该信息需要发送到的设备名称数组;
msg:某种数据类转换成的json字符串;
msgType:msg原本类的名称,接收到数据的设备用这个名称通过工厂模式来解析msg。

后端发送数据格式

参数:

{"fromPlatform": "Raspberry Pi","msgType": "MasterControl","msg": "阿巴阿巴"
}

fromPlatfrom:表示该数据由这个名称的设备发送;
msgType与msg同上。

实现

工程创建等配置

我使用IDEA进行开发。

选择Spring Initializr工程;

依赖根据自己的需求选取,不过一定要选上WebSocket;

我采用application.properties进行配置;

server.port、application.name、url、password等参数根据需要修改;
这里我选择了Mysql Server的依赖,必须要配置一个数据库连接,否则无法部署;也便于之后扩展数据库相关功能。

pom.xml导入FastJson:(可以换成别的JSON解析库)

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version>
</dependency>

Config文件

由于我采用了websocket依赖以及FastJson库(可以换成别的JSON解析库),而这两个库都有比较蛋疼的bug,需要配置两个config文件:

WebSocketConfig.java

// package com.wmiii.wmsocket.config;	改成自己的package路径import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

FJsonConfig.java

// package com.wmiii.wmsocket.config;	改成自己的package路径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 {@Beanpublic HttpMessageConverter configureMessageConverters() {FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();FastJsonConfig config = new FastJsonConfig();config.setSerializerFeatures(// 保留map空的字段SerializerFeature.WriteMapNullValue,// 将String类型的null转成""SerializerFeature.WriteNullStringAsEmpty,// 将Number类型的null转成0SerializerFeature.WriteNullNumberAsZero,// 将List类型的null转成[]SerializerFeature.WriteNullListAsEmpty,// 将Boolean类型的null转成falseSerializerFeature.WriteNullBooleanAsFalse,// 避免循环引用SerializerFeature.DisableCircularReferenceDetect);converter.setFastJsonConfig(config);converter.setDefaultCharset(Charset.forName("UTF-8"));List<MediaType> mediaTypeList = new ArrayList<>();// 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"mediaTypeList.add(MediaType.APPLICATION_JSON);converter.setSupportedMediaTypes(mediaTypeList);return converter;}
}

参数类代码

(类名我乱取的

后端接收信息参数类

BaseMsg.java

// package com.wmiii.wmsocket.msg;	改成自己package的路径import lombok.Data;	// 记得导入lombok依赖
import java.util.ArrayList;@Data
public class BaseMsg {Integer type;       // 1为指定发送对象,其余暂定为广播testArrayList<String> toPlatform;String msgType;String msg;         // json格式的msg,后端无需关心具体内容
}

后端发送信息参数类

ToMsgParam.java

// package com.wmiii.wmsocket.param;	改成自己package的路径
import lombok.Data;@Data
public class ToMsgParam {String fromPlatform;String msgType;String msg;     // JSON格式的数据
}

WebSocket业务处理代码

// 省略import@ServerEndpoint(value = "/websocket/{device}")
@Component
public class WmWebSocket {@OnOpenpublic void onOpen(Session session, @PathParam("device") String device) {}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session, @PathParam("device") String device) {}/*** 发生错误时调用*te*/@OnErrorpublic void onError(Session session, Throwable error) {}
}

对于一个拥有 @ServerEndpoint 注解的类,它就会被当做处理对应url的websocket业务的组件;其中需要实现四个注解的方法:

拥有 @OnOpen 注解的方法:在创建了一个新的websocket连接时调用;

拥有 @OnClose 注解的方法:websocket连接断开时调用;

拥有 @OnMessage 注解的方法:收到消息时调用;

拥有 @OnError 注解的方法:发生错误时调用;

成品

(看注释就好懒得另外打字了

// 省略import@ServerEndpoint(value = "/websocket/{device}")
@Component
public class WmWebSocket {//用来存放每个客户端对应的WmWebSocket对象。private static CopyOnWriteArraySet<WmWebSocket> webSocketSet = new CopyOnWriteArraySet<WmWebSocket>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;private String device;//用来记录平台名称和该session进行绑定private static Map<String,Session> deviceMap = new HashMap<String, Session>();@OnOpenpublic void onOpen(Session session, @PathParam("device") String device) {this.session = session;this.device = device;deviceMap.put(device, session);webSocketSet.add(this);     // 加入set中System.out.println("设备" + device +"加入, 当前设备数为" + webSocketSet.size());this.session.getAsyncRemote().sendText(device+"成功连接上WebSocket(sessionId: "+session.getId()+")-->当前在线设备数: "+webSocketSet.size());}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);  // 从set中删除deviceMap.remove(device);System.out.println("设备" + this.device +"连接关闭!当前在线设备数: " + webSocketSet.size());}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic 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;// 获取数据目标设备列表ArrayList<String> toList = baseMsg.getToPlatform();// 用来存储数据发送失败的目标设备,暂时没用;ArrayList<String> failed = new ArrayList<>();// 逐个查询session的map进行数据发送for(String toPlatform: toList) {toSession = deviceMap.get(toPlatform);try {toSession.getAsyncRemote().sendText(toMsg);} catch (Exception e) {// 如果该目标平台的数据发送失败,则加入发送失败列表,暂时没用;failed.add(toPlatform);}}break;default:System.out.println("default");}} catch (Exception e){e.printStackTrace();}}/*** 发生错误时调用*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("发生错误");error.printStackTrace();}
}

部署

使用宝塔面板部署,jar包部署。
选择IDEA右侧的Maven,运行Lifecycle下的package:

然后在项目根目录下的target文件夹中找到生成的一个.jar文件,上传到云服务器;

记得在服务器上开放设定的项目端口(我的是8880)。

在上传jar包的路径下运行:

nohup java -jar xxx.jar &

这里的xxx是你的jar包名称,就部署完毕了。

测试

最近(指写下这篇文章的时候)postman更新了WebSocket接口的测试;在Workspace右边点击New选择WebSocket Request就可以了。


(终于不用自写HTML测试了)

更多推荐

基于websocket的跨平台通信——iPhone/iPad/Mac控制树莓派(一):Springboot后端搭建

本文发布于:2024-02-06 12:33:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1749025.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:后端   通信   平台   iPhone   websocket

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!