网站恶意镜像,wordpress idstore,建站公司兴田德润,麻涌网站建设制作多少钱之前写过一个关于websocket的博客#xff0c;是看书时候做的一个demo。但是纸上得来终觉浅#xff0c;这次实战后实打实的踩了不少坑#xff0c;写个博客记录总结。
1.安装postman
websocket接口调试#xff0c;需要8.5以及以上版本的postman
先把以前的卸载#xff0c…之前写过一个关于websocket的博客是看书时候做的一个demo。但是纸上得来终觉浅这次实战后实打实的踩了不少坑写个博客记录总结。
1.安装postman
websocket接口调试需要8.5以及以上版本的postman
先把以前的卸载直接exe安装就好
点击这个连接可以下载或者去官网下载
https://download.csdn.net/download/qq_35653822/88419296
2.postman调试方法
2.1参考这个博客的postman调试方法
Postman进行Websocket接口测试_postman websocket-CSDN博客
2.2请求路径
不是http开头 而是ws开头
如 ws://127.0.0.1:9999/test/3
2.3测试方式
websocket接口和普通接口不同需要先建立连接再发送消息
建立连接时候这个url可以是pathvariable那种
如 /test/{id} 3.上代码
3.1controller层 1.ServerEndpoint 这个注解算是websocket中极其重要的一个注解了 这里边要配置上前后端建立连接的url后端返回前端内容的解析器。我这写了两个分别对应字符串和指定实体的解析器。以及websocket对应的config文件 2. OnOpen OnMessage OnOpen 前后端建立连接时走的方法也就是postman点击connect按钮时候会走的方法 OnMessage 前端给后端发送消息时走的方法也就是postman点击send的时候会走的方法 3.session.getBasicRemote().sendObject(); 后端给前端发送消息此处根据类型不同走不同的解析器。也就是ServerEndpoint中的 encoders 4.注入bean 根据idea提示需要用set方法注入 package websocket;import com.fasterxml.jackson.databind.ObjectMapper;
import com.valley.common.result.Result;
import com.valley.system.enums.LinkType;
import com.valley.system.pojo.bo.ConnectResultBO;
import com.valley.system.pojo.form.SourceForm;
import com.valley.system.service.SysDataSourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;import javax.websocket.EncodeException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.security.Principal;/*** Description: websocket url中得sourceId是为了指定websocket得连接*/ServerEndpoint(value /linkTest/{sourceId}, encoders {ServerEncoder.class,StringEncoder.class},configurator WebSocketConfig.class)
Component
Slf4j
public class WebSocketController {private static SysDataSourceService sysDataSourceService;Autowiredpublic void setDeviceListenerService(SysDataSourceService sysDataSourceService) {WebSocketController.sysDataSourceService sysDataSourceService;}/*** 实现服务器主动推送*/public void sendMessage(String message, Session session) throws IOException {session.getBasicRemote().sendText(message);}/*** 连接建立成功调用的方法*/OnOpenpublic void onOpen(Session session, PathParam(sourceId) String sourceId) throws EncodeException, IOException {log.info(连接成功sourceId:{}, sourceId);session.getBasicRemote().sendObject(sourceId);}/*** 收到客户端消息后调用的方法** param message 客户端发送过来的消息*/OnMessagepublic void onMessage(String message, Session session) throws Exception {log.info(【websocket消息】收到客户端发来的消息:{}, message);// 创建ObjectMapper对象ObjectMapper objectMapper new ObjectMapper();// 将JSON字符串解析为JSON对象SourceForm sourceForm objectMapper.readValue(message, SourceForm.class);//根据type判断是否是心跳连接if(LinkType.HEARTBEAT.equals(sourceForm.getLinkType())){//前端约定返回“pong”session.getBasicRemote().sendObject(pong);return;}ConnectResultBO bo sysDataSourceService.linkTest(sourceForm);try {ResultConnectResultBO result Result.success(bo);session.getBasicRemote().sendObject(result);//session.getBasicRemote().sendText(message.toString());} catch (IOException e) {e.printStackTrace();}}}3.2config层 1.需要配置在controller层的ServerEndpoint中 ServerEndpoint(value /api/v1/source/linkTest/{sourceId}, encoders {ServerEncoder.class,StringEncoder.class},configurator WebSocketConfig.class)2. Configuration修饰 因为要返回其他的bean 3.websocket的token上传返回 需要取header中的 Sec-WebSocket-Protocol 属性并且返回给前端的时候也要在header中携带 package websocket;import cn.hutool.core.lang.Assert;
import com.valley.system.config.Constant;
import jodd.util.StringUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.Collections;
import java.util.List;
import java.util.Map;/*** Description: websocket配置*/
Configuration
public class WebSocketConfig extends ServerEndpointConfig.Configurator{Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}/*** 建立握手时连接前的操作*/Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {// 这个userProperties 可以通过 session.getUserProperties()获取//获取请求头String token request.getHeaders().get(Sec-WebSocket-Protocol).get(0);Assert.notNull(token,token不可为空);//todo 之后需要对token进行解析校验//OAuth2AccessToken accessToken tokenStore.readAccessToken(token);//前端会把空格传成nbsp//token token.replace(Constant.NBSP, );//当Sec-WebSocket-Protocol请求头不为空时,需要返回给前端相同的响应response.getHeaders().put(Sec-WebSocket-Protocol, Collections.singletonList(token));super.modifyHandshake(sec, request, response);}/*** 初始化端点对象,也就是被ServerEndpoint所标注的对象*/Overridepublic T T getEndpointInstance(ClassT clazz) throws InstantiationException {return super.getEndpointInstance(clazz);}
}
3.3解析器 1.如果不配置在调用 session.getBasicRemote().sendObject(sourceId); 返回方法的时候会报此类型解析器不存在的错误 2.解析器写完之后要加到controller层的ServerEndpoint中 ServerEndpoint(value /api/v1/source/linkTest/{sourceId}, encoders {ServerEncoder.class,StringEncoder.class},configurator WebSocketConfig.class)3.3.1实体解析器
package websocket;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.valley.common.result.Result;
import com.valley.system.pojo.bo.ConnectResultBO;import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;/*** Description: websocket发送给前端 泛型中ResultConnectResultBO是要发送的类型*/
public class ServerEncoder implements Encoder.TextResultConnectResultBO {Overridepublic void destroy() {// TODO Auto-generated method stub// 这里不重要}Overridepublic void init(EndpointConfig arg0) {// TODO Auto-generated method stub// 这里也不重要}Overridepublic String encode(ResultConnectResultBO responseMessage) {try {JsonMapper jsonMapper new JsonMapper();return jsonMapper.writeValueAsString(responseMessage);} catch (JsonProcessingException e) {e.printStackTrace();return null;}}
}3.3.2字符串解析器 现在复盘来看我这个解析器写的完全没必要如果要发送字符串 把 session.getBasicRemote().sendObject 改为 session.getBasicRemote().sendText 就行了 public class StringEncoder implements Encoder.TextString{Overridepublic String encode(String s){return s;}Overridepublic void init(EndpointConfig endpointConfig) {}Overridepublic void destroy() {}
}
4.security权限过滤 这块踩了很久的坑我们项目是开源项目改的然后自己拆成了好几个微服务。我开始的时候只专注去改auth项目中的不管是忽略路径permitall还是加切面还是加filter。都不生效。 最后在公共项目common中找到一个关于security的配置改了permitall才生效 但是还要注意哈既然在这里把权限放开了那在config中就得把权限校验加上 此处放开是因为上边说过前端只能把token放到header的Sec-WebSocket-Protocol属性中而不能像平时一样放到Authorization属性中。 5.插曲
在进行实体转换的时候前端多给我传了参数引起了报错
objectMapper.readValue(message, SourceForm.class);
为了让代码健壮一点给实体加了个注解
JsonIgnoreProperties(ignoreUnknown true)
Unrecognized field , not marked as ignorable解决办法-CSDN博客