# Spring WebSocket Example

这是一个演示 Spring OAuth2 上整合 WebSocket 的例子,同时有一个整合 RabbitMQ 作为 Message Broker 的分支。

## 特性

* 以 Spring Cloud starter 项目为例。

* Gradle 构建,多层模块结构。同时演示一份微服务模块的代码结构。

* Spring OAuth2, WebSocket, RabbitMQ

* WebSocket 分布式部署

* WebSocket 压测和性能考虑

## 缘由

* 需求:新增在线课堂产品功能,老师创建课堂,配合手机操控多端,进行点名、计时、资源阅读等;学生需要时也能连接课堂,进行作业、考试等互动。

* 考虑多个可选方案,确定先集成 Spring WebSocket 生产上线验证,后期可重新评估,持续改善。详情可见“ WebSocket 压测和性能考虑”中描述的选型考虑。

## 用法

### 相关实现

编译依赖:

```

// websocket

compile("org.springframework.boot:spring-boot-starter-websocket")

// 当前版本 starter-websocket 不包括这个,要显式声明

compile("org.springframework.security:spring-security-messaging")

// 辅助调试 websocket 前端(可选)

compile("org.webjars:webjars-locator-core:0.35")

compile("org.webjars:sockjs-client:1.0.2")

compile("org.webjars:stomp-websocket:2.3.3")

compile("org.webjars:bootstrap:3.3.7")

compile("org.webjars:jquery:3.1.0")

```

自动配置和扩展:

```

@Configuration

@EnableWebSocketMessageBroker

@Order(Ordered.HIGHEST_PRECEDENCE + 50)

@EnableConfigurationProperties(StompProperties.class)

public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

```

实现业务指令:

```

/**

* 通用的给某指定频道发消息.

*

* @param message 带有频道信息 type 和 id

* @param principal 当前用户

* @throws Exception Exception

*/

@MessageMapping("/chat/sendMsg")

public void sendMsg(ChatMessage message, Principal principal) throws Exception {

if (StringUtils.isBlank(message.getType()) || StringUtils.isBlank(message.getId())) {

throw new MessagingException("频道type和id不能为空");

}

String separator = WsConstant.getNameSeparator(stompProperties.ifExternalBroker());

String channelId = "/topic/messages" + separator + message.getType() + separator + message.getId();

Map map = new HashMap<>();

map.put(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);

ChatMessage result = new ChatMessage("(频道 " + channelId + ") 消息: "

+ HtmlUtils.htmlEscape(message.getContent()); // TODO:目前仅演示,正式时直接转发信息

result.setId(message.getId());

result.setType(message.getType());

messagingTemplate.convertAndSend(channelId, result, map);

}

```

### 编译和使用

#### (1) build-all-projects.sh 直接运行 ```bash build-all-projects.sh``` 或参考其中的编译命令单独编译。

#!/bin/sh

# build_type 有 release 或 test 等

cd base-common; ./gradlew clean build -P build_type=release; cd ..

cd websocket-teaching; ./gradlew clean build -P build_type=release; cd ..

#### (2) 运行 websocket-teaching 。请参照 ```websocket-teaching/run-local.sh``` 的启动命令行,可能需要调整 jar 的版本号。

java -jar build/libs/basic-websocket-teaching-0.0.1.jar

或调整为:

java -jar build/libs/basic-websocket-teaching-1.0.0.jar

#### (3) Websocket 前端辅助调试页面

使用浏览器访问: `http://localhost:8082/api/ws/index.html`

![wstest.jpg](docs/reports/wstest.jpg)

#### (4) 业务指令样例。

```

/**

* ws 命令 model 基类.

*/

public class BaseCommand {

/** 从哪个平台发出的: pc | ios | android | web */

private String fromPlatform;

/** 角色 */

private String role;

/** 时间戳 */

private Long timestamp;

/** 类型 */

private String type;

/** 动作,不同类型带不同的动作 */

private String action;

/**

* 可由前端自定义的可变指定参数.

*

*

需要时,前端自定义可变参数,在多端前端交互时使用。参数的意义,由前端确定和使用,后端只是帮助传递

*/

private Map remarks;

```

```

/**

* 计时器命令.

*/

public class TimerCommand extends BaseCommand {

/**

* The constant TYPE.

*/

public static final String TYPE = "timer";

/**

* 计时类型:顺计时还是倒计时.

*/

private String subType;

/**

* 时长.

*/

private String time;

```

```

一个指令具体例子(字符串引号可能省略, | 表示值可选其中一个):

{

fromPlatform : PC | iOS | Android | web ,

timestamp:1599146332000 ,

type: timer ,

subType: countDown(倒计时) | countUp(顺计时) ,

action: start(开始计时) | stop(停止计时) | pause(暂停) | reset(重置) | fullScreen(全屏) | (等等) ,

time: "00:12:23" // 当前计时器的显示时间

}

```

#### (5) WebSocket 分布式部署

具体请查看 “mq” 分支

#### (6) WebSocket 压测和性能考虑

详情请跳转查看配套压测项目及其中的报告分析 [gatling-websocket-stomp](https://github.com/mingt/gatling-websocket-stomp)

### FAQ

(1) 运行日志不停刷新 Connection refused: connect 及 Cannot execute request on any known server 错误?

前者部分与 org.springframework.cloud:spring-cloud-starter-config 配置中心依赖有关。为了演示方便,已略去配置中心,也没有外部运行配置中心,所以默认

尝试连接配置中心 Fetching config from server at: http://localhost:8888 时报错。

前者另一部分和后者与注册中心有关。 注解 EnableEurekaClient 决定了模块作为客户端注册到注册中心,目前已略去也没有外部运行,所以不断尝试重连而报错。

如果的确需要去除,请按参考文档把配置中心、注册中心等先运行起来。

(3) 下一步还能做什么?

(待补充)

## 其他

### Spring Cloud starter

* 注册中心,配置中心,认证中心等已略去。 本项目的业务模块配置改回本地 Spring Boot 配置项。

* 来源于以下项目: [anilallewar/microservices-basics-spring-boot](https://github.com/anilallewar/microservices-basics-spring-boot) 致谢原作者,其最近更新也为 k8s 部署提供了一个方向。

* 为了方便国内访问,正常查看配图,目前在 Gitee 做了一份克隆: [ahming/microservices-basics-spring-boot](https://gitee.com/m1024ing/microservices-basics-spring-boot)

一键复制

编辑

Web IDE

原始数据

按行查看

历史

php rabbitmq报错重连,README.md · ahming/spring-websocket-example - Gitee.com相关推荐

  1. linux 启动rabbitmq 报错:

    linux 启动rabbitmq 报错: Job for rabbitmq-server.service failed because the control process exited with ...

  2. Windows下安装RabbitMQ报错:unable to perform an operation on node时的解决方案

    Windows下安装RabbitMQ报错:unable to perform an operation on node时的解决方案 参考文章: (1)Windows下安装RabbitMQ报错:unab ...

  3. rabbitmq报错:Listener method could not be invoked with the incoming message

    rabbitmq报错:Listener method could not be invoked with the incoming message 错误翻译:无法使用传入消息调用监听器方法 一个top ...

  4. 安装rabbitMq报错:error: unpacking of archive failed on file /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.9

    安装rabbitMq报错: 错误提示:error: unpagacking of archive failed on file /usr/lib/rabbitmq/lib/rabbitmq_serve ...

  5. Rabbitmq报错pika.exceptions.IncompatibleProtocolError: StreamLostError: ('Transport indicated EOF',)

    rabbitmq 报错 pika.exceptions.IncompatibleProtocolError: StreamLostError: ('Transport indicated EOF',) ...

  6. rabbitmq报错:PRECONDITION_FAILED - parameters for queue ‘test-1‘ in vhost ‘/‘ not equivalent

    错误如下: [root@master2 rabbitmq-python]# python send-1.py Traceback (most recent call last):File " ...

  7. window 使用rabbitMQ 报错Applying plugin configuration to rabbit@... failed.

    报错内容: E:\RabbitMQ Server\rabbitmq_server-3.6.5\sbin>rabbitmq-plugins.bat enable rabbitmq_manageme ...

  8. RabbitMQ 报错:connection error; (reply-code=530, reply-text=NOT_ALLOWED - XXX(Hosts名) / not found)

    背景 项目使用了 Spring Cloud Bus,RabbitMQ 作为消息代理,想要做到通过访问暴露的触发消息总线地址来达到开发人员变更 Gitee 上的配置文件后可以自动拉取更新的效果. 但是访 ...

  9. rabbitmq报错无法连接解决方案

    最近在部署spring cloud分布式配置中心时,需要使用rabbitmq作为消息总线.连接的时候却各种报错,无法申明queue和exchange,被各种阻塞,找办法找了很久,最后发现rabbitm ...

最新文章

  1. 用python读写excel(xlrd、xlwt)
  2. 从旁观者到贡献者:经历 OpenYurt 的“开源之夏”,我们想让更多人体验社区的魅力
  3. MySQL5.7.17绿色版安装
  4. 区块链中的数学 - EdDSA签名机制
  5. Linux必知必会的基本命令和部署项目流程
  6. 【java并发编程艺术学习】(一)初衷、感想与笔记目录
  7. LwIP之netbuf
  8. RabbitMQ 实现RPC
  9. 行程单批量打印软件(eTerm航空电子客票行程单打印软件)
  10. 我有一个 APP 创意,如何将其实现?
  11. html上下两个箭头符号怎么打出来,往返双箭头符号怎么打
  12. 网络数据传输的节点大全
  13. python中怎么画一个机器猫_用python画机器猫--哆啦A梦,开干!
  14. android仿网易云音乐引导页、仿书旗小说Flutter版、ViewPager切换、爆炸菜单、风扇叶片效果等源码
  15. cad特性匹配快捷键命令_CAD复制图形或特性的相关命令和操作
  16. Coursera机器学习+deeplearning.ai+斯坦福CS231n
  17. 相机计算坐标公式_相机采样点的坐标转换方法与流程
  18. idea警告:Unchecked cast: ‘java.lang.Object‘ to ‘java.util.List
  19. COMSOL仿真教程—激光烧蚀
  20. VSCODE:从零点五开始运行一个小型vaadin项目

热门文章

  1. 一个冒泡排序让你学完Java基础的数组、随机数、排序、方法等。
  2. 广州.NET微软技术俱乐部微信群有用信息集锦(10) - 大量json数据压缩方案
  3. NGR-PEG-6-FAM 肿瘤新生血管靶向肽NGR-聚乙二醇-6-羧甲基荧光素
  4. 计算机桌面模糊了,桌面背景模糊
  5. 2021年偃师一高高考成绩查询,2021洛阳市地区高考成绩排名查询,洛阳市高考各高中成绩喜报榜单...
  6. 083-我最爱的周杰伦几首歌
  7. C语言小项目——走迷宫
  8. 在Ubuntu上为软件安装桌面快捷方式
  9. arm-gfortran-4.8安装
  10. 分布式管理控制系统Git与项目托管平台Github相关概念、工作流程与操作方法