websocket 点对点单播的点对点和广播有什么不同

详解在Spring Boot框架下使用WebSocket实现消息推送
作者:_江南一点雨
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了详解在Spring Boot框架下使用WebSocket实现消息推送,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
spring Boot的学习持续进行中。前面两篇博客我们介绍了如何使用Spring Boot容器搭建Web项目以及怎样为我们的Project添加HTTPS的支持,在这两篇文章的基础上,我们今天来看看如何在Spring Boot中使用WebSocket。
什么是WebSocket
WebSocket为浏览器和服务器之间提供了双工异步通信功能,也就是说我们可以利用浏览器给服务器发送消息,服务器也可以给浏览器发送消息,目前主流浏览器的主流版本对WebSocket的支持都算是比较好的,但是在实际开发中使用WebSocket工作量会略大,而且增加了浏览器的兼容问题,这种时候我们更多的是使用WebSocket的一个子协议stomp,利用它来快速实现我们的功能。OK,关于WebSocket我这里就不再多说,我们主要看如何使用。
Project创建
使用WebSocket需要我们先创建一个Project,这个Project的创建方式和我们前文(初识Spring Boot框架)说的一样,不同的是在选择依赖的时候选择Thymeleaf和WebSocket依赖,如下图:
配置WebSocket
Project创建成功之后,我们先来配置WebSocket,创建如下类:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/endpointSang").withSockJS();
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
关于这个类我说如下几点:
1@EnableWebSocketMessageBroker注解表示开启使用STOMP协议来传输基于代理的消息,Broker就是代理的意思。
2.registerStompEndpoints方法表示注册STOMP协议的节点,并指定映射的URL。
3.stompEndpointRegistry.addEndpoint("/endpointSang").withSockJS();这一行代码用来注册STOMP协议节点,同时指定使用SockJS协议。
4.configureMessageBroker方法用来配置消息代理,由于我们是实现推送功能,这里的消息代理是/topic
创建浏览器发送消息的接收类
浏览器发送来的消息用这个类来接收:
public class RequestMessage {
public String getName() {
创建响应消息类
服务器返回给浏览器的消息由这个类来承载:
public class ResponseMessage {
private String responseM
public ResponseMessage(String responseMessage) {
this.responseMessage = responseM
public String getResponseMessage() {
return responseM
创建控制器
@Controller
public class WsController {
@MessageMapping("/welcome")
@SendTo("/topic/getResponse")
public ResponseMessage say(RequestMessage message) {
System.out.println(message.getName());
return new ResponseMessage("welcome," + message.getName() + " !");
关于这个控制器,首先@Controller注解不必多言,say方法上添加的@MessageMapping注解和我们之前使用的@RequestMapping类似。@SendTo注解表示当服务器有消息需要推送的时候,会对订阅了@SendTo中路径的浏览器发送消息。
我们这个案例需要三个js脚本文件,分别是STOMP协议的客户端脚本stomp.js、SockJS的客户端脚本sock.js以及jQuery,这三个js文件拷贝到src/main/resources/static/js目录下。OK,这三个js文件我已经为小伙伴们准备好了,可以直接在文末下载案例,案例中有,也可以自行下载这三个js文件。
在写这个HTML页面之前,我想先说我们要实现的效果是什么样子的。当我的Project启动之后,在浏览器访问消息发送页面,在该页面发送一条消息,当服务端收到这条消息之后给所有的连接上了服务器的浏览器都发送一条消息。OK,我们在src/main/resources/templates目录下新建一个ws.html页面,内容如下:
&html lang="en" xmlns:th="http://www.thymeleaf.org"&
&meta charset="UTF-8"/&
&title&广播式WebSocket&/title&
&script th:src="@{js/sockjs.min.js}"&&/script&
&script th:src="@{js/stomp.js}"&&/script&
&script th:src="@{js/jquery-3.1.1.js}"&&/script&
&body onload="disconnect()"&
&noscript&&h2 style="color: #e80b0a;"&Sorry,浏览器不支持WebSocket&/h2&&/noscript&
&button id="connect" onclick="connect();"&连接&/button&
&button id="disconnect" disabled="disabled" onclick="disconnect();"&断开连接&/button&
&div id="conversationDiv"&
&label&输入你的名字&/label&&input type="text" id="name"/&
&button id="sendName" onclick="sendName();"&发送&/button&
&p id="response"&&/p&
&script type="text/javascript"&
var stompClient =
function setConnected(connected) {
document.getElementById("connect").disabled =
document.getElementById("disconnect").disabled = !
document.getElementById("conversationDiv").style.visibility = connected ? 'visible' : 'hidden';
$("#connect").disabled =
$("#disconnect").disabled = !
$("#response").html();
function connect() {
var socket = new SockJS('/endpointSang');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected:' + frame);
stompClient.subscribe('/topic/getResponse', function (response) {
showResponse(JSON.parse(response.body).responseMessage);
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
setConnected(false);
console.log('Disconnected');
function sendName() {
var name = $('#name').val();
console.log('name:' + name);
stompClient.send("/welcome", {}, JSON.stringify({'name': name}));
function showResponse(message) {
$("#response").html(message);
这里虽然代码略多,但是仔细分析一下却也很简单。首先js文件引入的那一部分我就不再多说,这里如果又不理解的可以参考使用Spring Boot开发Web项目。然后我们的页面上先有两个按钮,一个是连接,一个是断开连接,两个按钮分别对应不同的点击事件,在这两个按钮下方有一个输入框,就是我们要发送的内容,然后还有一个发送按钮,发送按钮对应了一个发送消息的点击事件。这是整个页面的元素,很简单,我们这里重点来看一下js逻辑代码。
connect方法是当我点击连接按钮的时候执行的,var socket = new SockJS('/endpointSang');表示连接的SockJS的endpoint名称为/endpointSang,stompClient = Stomp.over(socket);表示使用STOMP来创建WebSocket客户端。然后调用stompClient中的connect方法来连接服务端,连接成功之后调用setConnected方法,该隐藏的隐藏,该显示的显示。然后再通过调用stompClient中的subscribe方法来订阅/topic/getResponse发送来的消息,也就是我们在Controller中的say方法上添加的@SendTo注解的参数。stompClient中的send方法表示发送一条消息到服务端,其他的都是常规的js用法我就不再赘述。
配置viewController
接下来就是要为ws.html提供路径映射:
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ws").setViewName("/ws");
OK,做完这一切之后我们就可以运行项目了,我同时打开多个浏览器,然后在其中一个上发送消息,我们来看看结果:
我在最上面的浏览器上发送消息,其他两个浏览器都能收到我的消息。
OK ,以上就是我们在Spring Boot框架下使用WebSocket实现消息推送的全过程。
本案例下载地址:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具前两篇博客演示了广播式的websocket 推送。
广播式有自己的应用场景,但是广播式不能解决我门一个常见的场景,即消息由谁发送、由谁接收的问题。
本例中演示了一个简单的聊天室程序。例子中只有两个用户,互相发送消息给彼此,因需要用户相关内容,所以这里引入了最简单的spring Security相关内容。
本文原代码会在文章末尾给出,但是原代码中包含
本文目录:
1.新建maven工程
2.新建Websocket 配置类
3.新建WebSecurityConfig配置
4.新建java bean
5.新建WebSocketController类
7.新建映射类WebMvcConfig
8.新建Application 启动类
1.导入脚本
2.编写login.html
3.编写chat.html
1.新建maven工程
新建maven 工程,pom.xml 文件内容如下:
&?xml version="1.0" encoding="UTF-8"?&
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&com.us.example&
&springWebSocket&
&1.0-SNAPSHOT&
&org.springframework.boot&
&spring-boot-starter-parent&
&1.3.0.RELEASE&
&com.us.Application&
&org.springframework.boot&
&spring-boot-starter&
&org.springframework.boot&
&spring-boot-starter-test&
&org.springframework.boot&
&spring-boot-starter-thymeleaf&
&org.springframework.boot&
&spring-boot-starter-web&
&org.springframework.boot&
&spring-boot-starter-websocket&
&org.springframework.boot&
&spring-boot-starter-security&
2.新建WebsocketConfig 配置类
package com.us.example.
import org.springframework.context.annotation.C
import org.springframework.messaging.simp.config.MessageBrokerR
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerC
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageB
import org.springframework.web.socket.config.annotation.StompEndpointR
* Created by yangyibo on 16/12/29.
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/endpointChat").withSockJS();
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue","/topic");
3.新建WebSecurityConfig配置
package com.us.example.config
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
protected void configure(HttpSecurity http) throws Exception {
.authorizeRequests()
.antMatchers("/","/login").permitAll()//根路径和/login路径不拦截
.anyRequest().authenticated()
.formLogin()
.loginPage("/login") //2登陆页面路径为/login
.defaultSuccessUrl("/chat") //3登陆成功转向chat页面
.permitAll()
.permitAll()
//4在内存中配置两个用户 wyf 和 wisely ,密码和用户名一致,角色是 USER
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
.inMemoryAuthentication()
.withUser("wyf").password("wyf").roles("USER")
.withUser("wisely").password("wisely").roles("USER")
//5忽略静态资源的拦截
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/static/**")
4.新建java bean
package com.us.example.
* Created by yangyibo on 16/12/29.
public class Message {
public String getName(){
5.新建WebSocketController类
package com.us.example.controller
import com.us.example.bean.Message
import com.us.example.bean.Response
import com.us.example.service.WebSocketService
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.SimpMessagingTemplate
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseBody
import java.security.Principal
@Controller
public class WebSocketController {
@Autowired
private SimpMessagingTemplate messagingTemplate
@MessageMapping("/chat")
//在springmvc 中可以直接获得principal,principal 中包含当前用户的信息
public void handleChat(Principal principal, Message message) {
if (principal.getName().equals("wyf")) {
//通过convertAndSendToUser 向用户发送信息,
// 第一个参数是接收消息的用户,第二个参数是浏览器订阅的地址,第三个参数是消息本身
messagingTemplate.convertAndSendToUser("wisely",
"/queue/notifications", principal.getName() + "-send:"
+ message.getName())
messagingTemplate.convertAndSendToUser("wyf",
"/queue/notifications", principal.getName() + "-send:"
+ message.getName())
7.新建映射类WebMvcConfig
为HTML 提供便捷的路径映射。
package com.us.example.
import org.springframework.context.annotation.C
import org.springframework.web.servlet.config.annotation.ViewControllerR
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerA
@Configuration
public class WebMvcConfig
extends WebMvcConfigurerAdapter{
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("/login");
registry.addViewController("/chat").setViewName("/chat");
8.新建Application 启动类
package com.us.
* Created by yangyibo on 16/12/29.
import org.springframework.boot.autoconfigure.SpringBootA
import org.springframework.context.ConfigurableApplicationC
import org.springframework.ponentS
import org.springframework.scheduling.annotation.EnableS
import static org.springframework.boot.SpringApplication.
@ComponentScan(basePackages ="com.us.example")
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext run = run(Application.class, args);
1.导入脚本
添加脚本,将stomp.js、sockjs.min.js 以及jQuery 脚本放在src/main/resources/static下。
2.编写login.html
在src/main/resources/templates 下新建 login.html。(源代码会在文章底部给出)
&!DOCTYPE html&
xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"&
charset="UTF-8" /&
&登陆页面&
th:if="${param.error}"&
无效的账号和密码
th:if="${param.logout}"&
th:action="@{/login}" method="post"&
type="text" name="username"/& &&
type="password" name="password"/& &&
& type="submit" value="登陆"/&&
3.编写chat.html
在src/main/resources/templates 下新建 chat.html。(源代码会在文章底部给出)
&!DOCTYPE html&
xmlns:th="http://www.thymeleaf.org"&
charset="UTF-8" /&
th:src="@{sockjs.min.js}"&&
th:src="@{stomp.min.js}"&&
th:src="@{jquery.js}"&&
id="wiselyForm"&
rows="4" cols="60" name="text"&&
type="submit"/&
th:inline="javascript"&
$('#wiselyForm').submit(function(e){
e.preventDefault();
var text = $('#wiselyForm').find('textarea[name="text"]').val();
sendSpittle(text);
var sock = new SockJS("/endpointChat");
var stomp = Stomp.over(sock);
stomp.connect('guest', 'guest', function(frame) {
stomp.subscribe("/user/queue/notifications", handleNotification);
function handleNotification(message) {
$('#output').append("&b&Received: " + message.body + "&/b&&br/&")
function sendSpittle(text) {
stomp.send("/chat", {}, JSON.stringify({ 'name': text }));
$('#stop').click(function() {sock.close()});
id="output"&&
打开两个浏览器,访问 进行登录,两个用户是wyf 和 wisely 账号密码一样。
登录成功后就可以相互发送信息聊天了。
本文参考:《JavaEE开发的颠覆者:Spring Boot实战 》
本文源代码:
本文已收录于以下专栏:
相关文章推荐
Gson解析复杂的json数据
Gson是google的一个Json库,使用非常简单。在Java中,只要引入包,创建对象就可以用了。
fromJson是Gson提供的一个方法,用来将一个Json数据转换为对象。需要注意的是,它会...
Gson是google的一个Json库,使用非常简单。在Java中,只要引入包,创建对象就可以用了。
fromJson是Gson提供的一个方法。用来将一个Json数据转换为对象。调用方法是:ne...
我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信,HttpUR...
Gson提供了fromJson()方法来实现从Json相关对象到java实体的方法。在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构。先来看第一种:比如json字符...
简单几步,在spring-boot项目中配置和实现websocket的服务端和html客户端。
WebSocket 为浏览器和服务器端提供了双工异步通信的功能,即浏览器可以向服务器发送消息,服务器也可以向浏览器发送消息。WebSocket 需要浏览器的支持,如IE 10+、Chrome 13+、...
Spring Boot的学习持续进行中。前面两篇博客我们介绍了如何使用Spring Boot容器搭建Web项目(使用Spring Boot开发Web项目)以及怎样为我们的Project添加HTTPS的...
使用websocket有两种方式:1是使用sockjs,2是使用h5的标准。使用Html5标准自然更方便简单,所以记录的是配合h5的使用方法。
  核心是@ServerEndp...
上篇博客使用Spring Boot开发Web项目我们简单介绍了使用如何使用Spring Boot创建一个使用了Thymeleaf模板引擎的Web项目,当然这还远远不够。今天我们再来看看如何给我们的We...
他的最新文章
讲师:刘文志
讲师:陈伟
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)SpringBoot webSocket 发送广播、点对点消息,Android接收
1、SpringBoot webSocket
SpringBoot 使用的websocket 协议,不是标准的websocket协议,使用的是名称叫做STOMP的协议。
1.1 STOMP协议说明
stomp协议 官方:
csdn 大神博客:
iteye 大神博客
(务必看一下,了解协议的一些使用)
本人使用的是Inject idea 搭建的springBoot websocket,并未采用熟悉的gradle,而是采用了maven方式搭建。
项目结构如下
&?xml version="1.0" encoding="UTF-8"?&
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&
&com.drawthink&
&websocketdemo&
&0.0.1-SNAPSHOT&
&webSocketdemo&
&webSocketDemo project for Spring Boot&
&org.springframework.boot&
&spring-boot-starter-parent&
&1.3.6.RELEASE&
&org.springframework.boot&
&spring-boot-starter-thymeleaf&
&org.springframework.boot&
&spring-boot-starter-websocket&
&org.springframework.boot&
&spring-boot-starter-test&
&org.springframework.boot&
&spring-boot-maven-plugin&
Application:
package com.
import org.springframework.boot.SpringA
import org.springframework.boot.autoconfigure.SpringBootA
@SpringBootApplication
public class WebSocketdemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebSocketdemoApplication.class, args);
WebSocketConfig
package com.drawthink.
import org.springframework.context.annotation.C
import org.springframework.messaging.simp.config.MessageBrokerR
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerC
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageB
import org.springframework.web.socket.config.annotation.StompEndpointR
* Created by lincoln on 16-10-25
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/hello").setAllowedOrigins("*").withSockJS();
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic","/user");
registry.setApplicationDestinationPrefixes("/app/");
WebSocketController
package com.drawthink.websocket.
import com.drawthink.message.ClientM
import com.drawthink.message.ServerM
import com.drawthink.message.ToUserM
import org.springframework.beans.factory.annotation.A
import org.springframework.messaging.handler.annotation.MessageM
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingT
import org.springframework.stereotype.C
* Created by lincoln on 16-10-25
@Controller
public class WebSocketController {
@MessageMapping("/welcome")
@SendTo("/topic/getResponse")
public ServerMessage say(ClientMessage clientMessage){
System.out.println("clientMessage.getName() = " + clientMessage.getName());
return new ServerMessage("Welcome , "+clientMessage.getName()+" !");
@Autowired
private SimpMessagingTemplate messagingT
@MessageMapping("/cheat")
public void cheatTo(ToUserMessage toUserMessage){
System.out.println("toUserMessage.getMessage() = " + toUserMessage.getMessage());
System.out.println("toUserMessage.getUserId() = " + toUserMessage.getUserId());
messagingTemplate.convertAndSendToUser(toUserMessage.getUserId(),"/message",toUserMessage.getMessage());
package com.drawthink.
* Created by lincoln on 16-10-25
public class ClientMessage {
public String getName() {
public void setName(String name) {
this.name =
package com.drawthink.
* Created by lincoln on 16-10-25
public class ServerMessage {
private String responseM
public ServerMessage(String responseMessage) {
this.responseMessage = responseM
public String getResponseMessage() {
return responseM
public void setResponseMessage(String responseMessage) {
this.responseMessage = responseM
package com.drawthink.
* Created by lincoln on 16-10-25
public class ToUserMessage {
private String userId;
public String getUserId() {
return userId;
public void setUserId(String userId) {
this.userId = userId;
public String getMessage() {
public void setMessage(String message) {
this.message =
Android 客户端
STOMP协议在Android系统中没有默认实现,必须自行去实现。不过好消息是,开源大神们已经完成了Android上使用STOMP协议的实现,所以我们只需要使用就好了。
推荐使用:StompProtocolAndroid
当然,开源的世界,你也可以自行去寻找STOMP的其他实现
build.gradle(app)
apply plugin: 'com.android.application'
compileSdkVersion 24
buildToolsVersion "24.0.3"
defaultConfig {
applicationId "com.drawthink.websocket"
minSdkVersion 16
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildTypes {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
compile 'com.github.NaikSoftware:StompProtocolAndroid:1.1.1'
compile 'org.java-websocket:Java-WebSocket:1.3.0'
接收广播实例:
package com.drawthink.
import android.content.I
import android.os.B
import android.support.v7.app.AppCompatA
import android.util.L
import android.view.V
import android.widget.B
import android.widget.EditT
import android.widget.TextV
import android.widget.T
import org.java_websocket.WebS
import rx.S
import rx.functions.Action1;
import ua.naiksoftware.stomp.LifecycleE
import ua.naiksoftware.stomp.S
import ua.naiksoftware.stomp.client.StompC
import ua.naiksoftware.stomp.client.StompM
import static android.content.ContentValues.TAG;
public class MainActivity extends AppCompatActivity {
private TextView serverM
private EditText editT
private StompClient mStompC
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindView();
start.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
createStompClient();
registerStompTopic();
send.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mStompClient.send("/app/welcome","{\"name\":\""+editText.getText()+"\"}")
.subscribe(new Subscriber&Void&() {
public void onCompleted() {
toast("发送成功");
public void onError(Throwable e) {
e.printStackTrace();
toast("发送错误");
public void onNext(Void aVoid) {
stop.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mStompClient.disconnect();
cheat.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startActivity(new Intent(MainActivity.this,CheatActivity.class));
if(mStompClient != null) {
mStompClient.disconnect();
private void showMessage(final StompMessage stompMessage) {
runOnUiThread(new Runnable() {
public void run() {
serverMessage.setText("stomp command is ---&"+stompMessage.getStompCommand() +" body is ---&"+stompMessage.getPayload());
private void createStompClient() {
mStompClient = Stomp.over(WebSocket.class, "ws://192.168.0.46:8080/hello/websocket");
mStompClient.connect();
Toast.makeText(MainActivity.this,"开始连接 192.168.0.46:8080",Toast.LENGTH_SHORT).show();
mStompClient.lifecycle().subscribe(new Action1&LifecycleEvent&() {
public void call(LifecycleEvent lifecycleEvent) {
switch (lifecycleEvent.getType()) {
case OPENED:
Log.d(TAG, "Stomp connection opened");
toast("连接已开启");
case ERROR:
Log.e(TAG, "Stomp Error", lifecycleEvent.getException());
toast("连接出错");
case CLOSED:
Log.d(TAG, "Stomp connection closed");
toast("连接关闭");
private void registerStompTopic() {
mStompClient.topic("/topic/getResponse").subscribe(new Action1&StompMessage&() {
public void call(StompMessage stompMessage) {
Log.e(TAG, "call: " +stompMessage.getPayload() );
showMessage(stompMessage);
private void toast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this,message,Toast.LENGTH_SHORT).show();
private void bindView() {
serverMessage = (TextView) findViewById(R.id.serverMessage);
start = (Button) findViewById(R.id.start);
stop = (Button) findViewById(R.id.stop);
send = (Button) findViewById(R.id.send);
editText = (EditText) findViewById(R.id.clientMessage);
cheat = (Button) findViewById(R.id.cheat);
package com.drawthink.
import android.os.B
import android.support.v7.app.AppCompatA
import android.util.L
import android.view.V
import android.widget.B
import android.widget.EditT
import android.widget.LinearL
import android.widget.TextV
import android.widget.T
import org.java_websocket.WebS
import rx.S
import rx.functions.Action1;
import ua.naiksoftware.stomp.LifecycleE
import ua.naiksoftware.stomp.S
import ua.naiksoftware.stomp.client.StompC
import ua.naiksoftware.stomp.client.StompM
import static android.content.ContentValues.TAG;
public class CheatActivity extends AppCompatActivity {
private EditT
private LinearL
private StompClient mStompC
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cheat);
bindView();
createStompClient();
registerStompTopic();
send.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mStompClient.send("/app/cheat","{\"userId\":\"lincoln\",\"message\":\""+cheat.getText()+"\"}")
.subscribe(new Subscriber&Void&() {
public void onCompleted() {
toast("发送成功");
public void onError(Throwable e) {
e.printStackTrace();
toast("发送错误");
public void onNext(Void aVoid) {
private void bindView() {
cheat = (EditText) findViewById(R.id.cheat);
send = (Button) findViewById(R.id.send);
message = (LinearLayout) findViewById(R.id.message);
private void createStompClient() {
mStompClient = Stomp.over(WebSocket.class, "ws://192.168.0.46:8080/hello/websocket");
mStompClient.connect();
Toast.makeText(CheatActivity.this,"开始连接 192.168.0.46:8080",Toast.LENGTH_SHORT).show();
mStompClient.lifecycle().subscribe(new Action1&LifecycleEvent&() {
public void call(LifecycleEvent lifecycleEvent) {
switch (lifecycleEvent.getType()) {
case OPENED:
Log.d(TAG, "Stomp connection opened");
toast("连接已开启");
case ERROR:
Log.e(TAG, "Stomp Error", lifecycleEvent.getException());
toast("连接出错");
case CLOSED:
Log.d(TAG, "Stomp connection closed");
toast("连接关闭");
private void registerStompTopic() {
mStompClient.topic("/user/xiaoli/message").subscribe(new Action1&StompMessage&() {
public void call(StompMessage stompMessage) {
Log.e(TAG, "call: " +stompMessage.getPayload() );
showMessage(stompMessage);
private void showMessage(final StompMessage stompMessage) {
runOnUiThread(new Runnable() {
public void run() {
TextView text = new TextView(CheatActivity.this);
text.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
text.setText(System.currentTimeMillis() +" body is ---&"+stompMessage.getPayload());
message.addView(text);
private void toast(final String message) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(CheatActivity.this,message,Toast.LENGTH_SHORT).show();
代码比较乱,说明一下。
1、STOMP 使用的时候,关键是发布订阅的关系,使用过消息队列,例如rabbitMQ的应该很容易理解。
服务器端 WebSocketConfig.java文件控制的就是订阅发布的路径关系。
2、websocket的路径说明,本例中连接的是ws://192.168.0.46:8080/hello/websocket路径,/hello是在WebSocketConfig的stompEndpointRegistry.addEndpoint(“/hello”).setAllowedOrigins(““).withSockJS();*确定的,
如果有多个endpoint,这个地方的路径也会随之变化。
3、发布路径
发布信息的路径是由WebSocketConfig中的 setApplicationDestinationPrefixes(“/app/”); 和 Controller 中@MessageMapping(“/welcome”) 组合确定的。
例如发广播消息,路径为/app/welcome
例如发点对点消息,路径为/app/cheat
4、消息订阅路径
订阅broker源自WebSocketConfig中的registry.enableSimpleBroker(“/topic”,”/user”);此处开放了两个broker,具体的订阅服务路径给基于Controller中的 @SendTo(“/topic/getResponse”)或SimpMessagingTemplate中给定。(注:此处,服务器和客户端须约定订阅路径)
5、关于心跳
订阅发布模型的心跳很简单,客户端向一个指定的心跳路径发送心跳,服务器处理,服务器使用指定的订阅路径向客户端发心跳,即可。因为没有Socket,只需要记录是否联通的状态即可,重连客户端做一下就好了。
本人菜鸟,肯定有些地方没有搞清楚,如果有误,请大神斧正。
代码下载地址
服务器代码:
SpringBootWebSocketDemo.rar
客户端代码:
AndroidClientWebSocket.rar
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?

我要回帖

更多关于 socket.io 点对点聊天 的文章

 

随机推荐