diff --git a/AndroidClient/app/src/main/java/app/xlui/example/im/activities/BroadcastActivity.java b/AndroidClient/app/src/main/java/app/xlui/example/im/activities/BroadcastActivity.java
index 46993f5..153f6e4 100644
--- a/AndroidClient/app/src/main/java/app/xlui/example/im/activities/BroadcastActivity.java
+++ b/AndroidClient/app/src/main/java/app/xlui/example/im/activities/BroadcastActivity.java
@@ -1,6 +1,5 @@
package app.xlui.example.im.activities;
-import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
@@ -24,27 +23,26 @@
import ua.naiksoftware.stomp.dto.StompHeader;
import ua.naiksoftware.stomp.dto.StompMessage;
+@SuppressWarnings({"FieldCanBeLocal", "ResultOfMethodCallIgnored", "CheckResult"})
public class BroadcastActivity extends AppCompatActivity {
- private Button broadcast;
- private Button groups;
- private Button chat;
+ private Button broadcastButton;
+ private Button groupButton;
+ private Button chatButton;
- private EditText name;
- private Button send;
- private TextView result;
+ private EditText nameText;
+ private Button sendButton;
+ private TextView resultText;
private void init() {
- broadcast = findViewById(R.id.broadcast);
- broadcast.setEnabled(false);
- groups = findViewById(R.id.groups);
- chat = findViewById(R.id.chat);
- name = findViewById(R.id.name);
- send = findViewById(R.id.send);
- result = findViewById(R.id.show);
+ broadcastButton = findViewById(R.id.broadcast);
+ broadcastButton.setEnabled(false);
+ groupButton = findViewById(R.id.groups);
+ chatButton = findViewById(R.id.chat);
+ nameText = findViewById(R.id.name);
+ sendButton = findViewById(R.id.send);
+ resultText = findViewById(R.id.show);
}
- @SuppressLint("CheckResult")
- @SuppressWarnings("ResultOfMethodCallIgnored")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -53,29 +51,29 @@ protected void onCreate(Bundle savedInstanceState) {
this.init();
StompClient stompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, Const.address);
- // 连接服务器
- stompClient.connect();
- Toast.makeText(this, "Connect start", Toast.LENGTH_SHORT).show();
StompUtils.lifecycle(stompClient);
+ Toast.makeText(this, "Start connecting to server", Toast.LENGTH_SHORT).show();
+ // Connect to WebSocket server
+ stompClient.connect();
// 订阅消息
- Log.i(Const.TAG, "Subscribe broadcast");
+ Log.i(Const.TAG, "Subscribe broadcast endpoint to receive response");
stompClient.topic(Const.broadcastResponse).subscribe(stompMessage -> {
JSONObject jsonObject = new JSONObject(stompMessage.getPayload());
Log.i(Const.TAG, "Receive: " + stompMessage.getPayload());
runOnUiThread(() -> {
try {
- result.append(jsonObject.getString("response") + "\n");
+ resultText.append(jsonObject.getString("response") + "\n");
} catch (JSONException e) {
e.printStackTrace();
}
});
});
- send.setOnClickListener(v -> {
+ sendButton.setOnClickListener(v -> {
JSONObject jsonObject = new JSONObject();
try {
- jsonObject.put("name", name.getText());
+ jsonObject.put("name", nameText.getText());
} catch (JSONException e) {
e.printStackTrace();
}
@@ -84,7 +82,7 @@ protected void onCreate(Bundle savedInstanceState) {
// Stomp command
StompCommand.SEND,
// Stomp Headers, Send Headers with STOMP
- // the first header is necessary, and the other can be customized by ourselves
+ // the first header is required, and the other can be customized by ourselves
Arrays.asList(
new StompHeader(StompHeader.DESTINATION, Const.broadcast),
new StompHeader("authorization", "this is a token generated by your code!")
@@ -92,15 +90,16 @@ protected void onCreate(Bundle savedInstanceState) {
// Stomp payload
jsonObject.toString())
).subscribe();
+ nameText.setText("");
});
- groups.setOnClickListener(v -> {
+ groupButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(BroadcastActivity.this, GroupActivity.class);
startActivity(intent);
this.finish();
});
- chat.setOnClickListener(v -> {
+ chatButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(BroadcastActivity.this, ChatActivity.class);
startActivity(intent);
diff --git a/AndroidClient/app/src/main/java/app/xlui/example/im/activities/ChatActivity.java b/AndroidClient/app/src/main/java/app/xlui/example/im/activities/ChatActivity.java
index fe0ace7..5f2040e 100644
--- a/AndroidClient/app/src/main/java/app/xlui/example/im/activities/ChatActivity.java
+++ b/AndroidClient/app/src/main/java/app/xlui/example/im/activities/ChatActivity.java
@@ -1,6 +1,5 @@
package app.xlui.example.im.activities;
-import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -24,44 +23,43 @@
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompClient;
+@SuppressWarnings({"FieldCanBeLocal", "ResultOfMethodCallIgnored", "CheckResult"})
public class ChatActivity extends AppCompatActivity {
- private Button broadcast;
- private Button groups;
- private Button chat;
+ private Button broadcastButton;
+ private Button groupButton;
+ private Button chatButton;
- private TextView userId;
- private EditText chatUserId;
- private Button submit;
- private EditText chatMessage;
- private Button send;
- private TextView show;
+ private TextView userIdText;
+ private EditText chatUserIdText;
+ private Button submitButton;
+ private EditText chatMessageText;
+ private Button sendButton;
+ private TextView showText;
- private String user_id;
- private String chat_user_id;
+ private String userId;
+ private String chatUserId;
private void init() {
- broadcast = findViewById(R.id.broadcast);
- groups = findViewById(R.id.groups);
- chat = findViewById(R.id.chat);
- chat.setEnabled(false);
+ broadcastButton = findViewById(R.id.broadcast);
+ groupButton = findViewById(R.id.groups);
+ chatButton = findViewById(R.id.chat);
+ chatButton.setEnabled(false);
- userId = findViewById(R.id.id);
- user_id = String.valueOf(new Random().nextInt(100));
- userId.setText(user_id);
+ userIdText = findViewById(R.id.id);
+ userId = String.valueOf(new Random().nextInt(100));
+ userIdText.setText(userId);
- chatUserId = findViewById(R.id.chat_user_id);
- submit = findViewById(R.id.submit);
- submit.setEnabled(false);
+ chatUserIdText = findViewById(R.id.chat_user_id);
+ submitButton = findViewById(R.id.submit);
+ submitButton.setEnabled(false);
- chatMessage = findViewById(R.id.chat_message);
- send = findViewById(R.id.send);
- send.setEnabled(false);
+ chatMessageText = findViewById(R.id.chat_message);
+ sendButton = findViewById(R.id.send);
+ sendButton.setEnabled(false);
- show = findViewById(R.id.show);
+ showText = findViewById(R.id.show);
}
- @SuppressWarnings("ResultOfMethodCallIgnored")
- @SuppressLint("CheckResult")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -70,23 +68,24 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
this.init();
StompClient stompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, Const.address);
+ Toast.makeText(this, "Start connecting to server", Toast.LENGTH_SHORT).show();
stompClient.connect();
- Toast.makeText(this, "Connect start", Toast.LENGTH_SHORT).show();
StompUtils.lifecycle(stompClient);
- stompClient.topic(Const.chatResponse.replace(Const.placeholder, user_id)).subscribe(stompMessage -> {
+ Log.i(Const.TAG, "Subscribe chat endpoint to receive response");
+ stompClient.topic(Const.chatResponse.replace(Const.placeholder, userId)).subscribe(stompMessage -> {
JSONObject jsonObject = new JSONObject(stompMessage.getPayload());
Log.i(Const.TAG, "Receive: " + jsonObject.toString());
runOnUiThread(() -> {
try {
- show.append(jsonObject.getString("response") + "\n");
+ showText.append(jsonObject.getString("response") + "\n");
} catch (JSONException e) {
e.printStackTrace();
}
});
});
- chatUserId.addTextChangedListener(new TextWatcher() {
+ chatUserIdText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -99,42 +98,43 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
@Override
public void afterTextChanged(Editable s) {
- if (!submit.isEnabled())
- submit.setEnabled(true);
+ if (!submitButton.isEnabled())
+ submitButton.setEnabled(true);
}
});
- submit.setOnClickListener(v -> {
- chat_user_id = chatUserId.getText().toString();
- if (chat_user_id.length() == 0) {
+ submitButton.setOnClickListener(v -> {
+ chatUserId = chatUserIdText.getText().toString();
+ if (chatUserId.length() == 0) {
return;
}
- submit.setEnabled(false);
- send.setEnabled(true);
+ submitButton.setEnabled(false);
+ sendButton.setEnabled(true);
});
- send.setOnClickListener(v -> {
+ sendButton.setOnClickListener(v -> {
JSONObject jsonObject = new JSONObject();
try {
- jsonObject.put("userID", chat_user_id);
- jsonObject.put("fromUserID", userId.getText().toString());
- jsonObject.put("message", chatMessage.getText());
+ jsonObject.put("userID", chatUserId);
+ jsonObject.put("fromUserID", userIdText.getText().toString());
+ jsonObject.put("message", chatMessageText.getText());
} catch (JSONException e) {
e.printStackTrace();
}
- if (chat_user_id == null || chat_user_id.length() == 0) {
- chat_user_id = chatUserId.getText().toString();
+ if (chatUserId == null || chatUserId.length() == 0) {
+ chatUserId = chatUserIdText.getText().toString();
}
stompClient.send(Const.chat, jsonObject.toString()).subscribe();
+ chatMessageText.setText("");
});
- broadcast.setOnClickListener(v -> {
+ broadcastButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(ChatActivity.this, BroadcastActivity.class);
startActivity(intent);
this.finish();
});
- groups.setOnClickListener(v -> {
+ groupButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(ChatActivity.this, GroupActivity.class);
startActivity(intent);
diff --git a/AndroidClient/app/src/main/java/app/xlui/example/im/activities/GroupActivity.java b/AndroidClient/app/src/main/java/app/xlui/example/im/activities/GroupActivity.java
index ea09010..13af9bb 100644
--- a/AndroidClient/app/src/main/java/app/xlui/example/im/activities/GroupActivity.java
+++ b/AndroidClient/app/src/main/java/app/xlui/example/im/activities/GroupActivity.java
@@ -1,6 +1,5 @@
package app.xlui.example.im.activities;
-import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -22,38 +21,37 @@
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompClient;
+@SuppressWarnings({"FieldCanBeLocal", "ResultOfMethodCallIgnored", "CheckResult"})
public class GroupActivity extends AppCompatActivity {
- private Button broadcast;
- private Button groups;
- private Button chat;
+ private Button broadcastButton;
+ private Button groupButton;
+ private Button chatButton;
- private EditText groupId;
- private Button submit;
- private EditText name;
- private Button send;
- private TextView show;
+ private EditText groupIdText;
+ private Button submitButton;
+ private EditText nameText;
+ private Button sendButton;
+ private TextView showText;
- private String group_id;
+ private String groupId;
private void init() {
- broadcast = findViewById(R.id.broadcast);
- groups = findViewById(R.id.groups);
- groups.setEnabled(false);
- chat = findViewById(R.id.chat);
+ broadcastButton = findViewById(R.id.broadcast);
+ groupButton = findViewById(R.id.groups);
+ groupButton.setEnabled(false);
+ chatButton = findViewById(R.id.chat);
- groupId = findViewById(R.id.group_id);
- submit = findViewById(R.id.submit);
- submit.setEnabled(false);
+ groupIdText = findViewById(R.id.group_id);
+ submitButton = findViewById(R.id.submit);
+ submitButton.setEnabled(false);
- name = findViewById(R.id.name);
- send = findViewById(R.id.send);
- send.setEnabled(false);
+ nameText = findViewById(R.id.name);
+ sendButton = findViewById(R.id.send);
+ sendButton.setEnabled(false);
- show = findViewById(R.id.show);
+ showText = findViewById(R.id.show);
}
- @SuppressWarnings("ResultOfMethodCallIgnored")
- @SuppressLint("CheckResult")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -62,11 +60,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
this.init();
StompClient stompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, Const.address);
+ Toast.makeText(this, "Start connecting to server", Toast.LENGTH_SHORT).show();
stompClient.connect();
- Toast.makeText(this, "Connect start", Toast.LENGTH_SHORT).show();
StompUtils.lifecycle(stompClient);
- groupId.addTextChangedListener(new TextWatcher() {
+ groupIdText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -79,51 +77,52 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
@Override
public void afterTextChanged(Editable s) {
- if (!submit.isEnabled())
- submit.setEnabled(true);
+ if (!submitButton.isEnabled())
+ submitButton.setEnabled(true);
}
});
- submit.setOnClickListener(v -> {
- group_id = groupId.getText().toString();
- if (group_id.length() == 0) {
+ submitButton.setOnClickListener(v -> {
+ groupId = groupIdText.getText().toString();
+ if (groupId.length() == 0) {
return;
}
- stompClient.topic(Const.groupResponse.replace("placeholder", group_id)).subscribe(stompMessage -> {
+ stompClient.topic(Const.groupResponse.replace(Const.placeholder, groupId)).subscribe(stompMessage -> {
JSONObject jsonObject = new JSONObject(stompMessage.getPayload());
Log.i(Const.TAG, "Receive: " + stompMessage.getPayload());
runOnUiThread(() -> {
try {
- show.append(jsonObject.getString("response") + "\n");
+ showText.append(jsonObject.getString("response") + "\n");
} catch (JSONException e) {
e.printStackTrace();
}
});
});
- submit.setEnabled(false);
- send.setEnabled(true);
+ submitButton.setEnabled(false);
+ sendButton.setEnabled(true);
});
- send.setOnClickListener(v -> {
+ sendButton.setOnClickListener(v -> {
JSONObject jsonObject = new JSONObject();
try {
- jsonObject.put("name", name.getText().toString());
+ jsonObject.put("name", nameText.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
- if (group_id == null || group_id.length() == 0) {
- group_id = groupId.getText().toString();
+ if (groupId == null || groupId.length() == 0) {
+ groupId = groupIdText.getText().toString();
}
- stompClient.send(Const.group.replace("placeholder", group_id), jsonObject.toString()).subscribe();
+ stompClient.send(Const.group.replace(Const.placeholder, groupId), jsonObject.toString()).subscribe();
+ nameText.setText("");
});
- broadcast.setOnClickListener(v -> {
+ broadcastButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(GroupActivity.this, BroadcastActivity.class);
startActivity(intent);
this.finish();
});
- chat.setOnClickListener(v -> {
+ chatButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(GroupActivity.this, ChatActivity.class);
startActivity(intent);
diff --git a/AndroidClient/app/src/main/java/app/xlui/example/im/conf/Const.java b/AndroidClient/app/src/main/java/app/xlui/example/im/conf/Const.java
index e7dbca0..6bd3a37 100644
--- a/AndroidClient/app/src/main/java/app/xlui/example/im/conf/Const.java
+++ b/AndroidClient/app/src/main/java/app/xlui/example/im/conf/Const.java
@@ -5,9 +5,10 @@ public class Const {
public static final String placeholder = "placeholder";
/**
- * URL 中的 {@code im} 是在服务器中配置的 endpoint,
- * 如果使用 Android Studio 自带的 AVD,地址应该是 10.0.2.2;
- * 如果使用 Genymotion,地址应该是 10.0.3.2
+ * im in address is the endpoint configured in server.
+ * If you are using AVD provided by Android Studio, you should uncomment the upper address.
+ * If you are using Genymotion, nothing else to do.
+ * If you are using your own phone, just change the server address and port.
*/
// private static final String address = "ws://10.0.2.2:8080/im/websocket";
public static final String address = "ws://10.0.3.2:8080/im/websocket";
diff --git a/AndroidClient/app/src/main/java/app/xlui/example/im/util/StompUtils.java b/AndroidClient/app/src/main/java/app/xlui/example/im/util/StompUtils.java
index a322b4e..d037138 100644
--- a/AndroidClient/app/src/main/java/app/xlui/example/im/util/StompUtils.java
+++ b/AndroidClient/app/src/main/java/app/xlui/example/im/util/StompUtils.java
@@ -1,28 +1,29 @@
package app.xlui.example.im.util;
-import android.annotation.SuppressLint;
import android.util.Log;
import app.xlui.example.im.conf.Const;
import ua.naiksoftware.stomp.StompClient;
+import static app.xlui.example.im.conf.Const.TAG;
+
public class StompUtils {
- @SuppressLint("CheckResult")
+ @SuppressWarnings({"ResultOfMethodCallIgnored", "CheckResult"})
public static void lifecycle(StompClient stompClient) {
- stompClient.lifecycle().subscribe(lifecycleEvent -> {
- switch (lifecycleEvent.getType()) {
- case OPENED:
- Log.d(Const.TAG, "Stomp connection opened");
- break;
+ stompClient.lifecycle().subscribe(lifecycleEvent -> {
+ switch (lifecycleEvent.getType()) {
+ case OPENED:
+ Log.d(TAG, "Stomp connection opened");
+ break;
- case ERROR:
- Log.e(Const.TAG, "Error", lifecycleEvent.getException());
- break;
+ case ERROR:
+ Log.e(TAG, "Error", lifecycleEvent.getException());
+ break;
- case CLOSED:
- Log.d(Const.TAG, "Stomp connection closed");
- break;
- }
- });
- }
+ case CLOSED:
+ Log.d(TAG, "Stomp connection closed");
+ break;
+ }
+ });
+ }
}
diff --git a/AndroidClient/app/src/main/res/values/strings.xml b/AndroidClient/app/src/main/res/values/strings.xml
index 6de869e..0bd4d6e 100644
--- a/AndroidClient/app/src/main/res/values/strings.xml
+++ b/AndroidClient/app/src/main/res/values/strings.xml
@@ -1,17 +1,17 @@
- * 可以设置数据到 attributes 中,并在 WebSocketHandler 的 session 中获取
+ * WebSocket 握手前 —— 可以设置数据到 attributes 中,并在 WebSocketHandler 的 session 中获取
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map
* 注册 STOMP 协议的节点(Endpoint),并映射为指定的 URL
* 我们使用 STOMP,所以不需要再实现 WebSocketHandler。
* 实现 WebSocketHandler 的目的是接收和处理消息,STOMP 已经为我们做了这些。
@@ -26,7 +26,13 @@ public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry)
stompEndpointRegistry.addEndpoint("/im").addInterceptors(new HandshakeInterceptor()).withSockJS();
}
- // 配置使用消息代理
+ /**
+ * Configure message broker
+ *
+ * 配置使用消息代理
+ *
+ * @param registry message broker registry
+ */
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// Configure global message broker, client will subscribe these message brokers to receive messages
diff --git a/WebSocketServer/src/main/java/app/xlui/example/im/web/WebSocketController.java b/WebSocketServer/src/main/java/app/xlui/example/im/web/WebSocketController.java
index 2dd6a3a..72e6642 100644
--- a/WebSocketServer/src/main/java/app/xlui/example/im/web/WebSocketController.java
+++ b/WebSocketServer/src/main/java/app/xlui/example/im/web/WebSocketController.java
@@ -15,6 +15,7 @@
@Controller
@Slf4j
public class WebSocketController {
+ // You cannot integrate WebSocket with JWT for token validate.
private static final String token = "this is a token generated by your code!";
private final SimpMessagingTemplate simpMessagingTemplate;
@@ -23,23 +24,25 @@ public WebSocketController(SimpMessagingTemplate simpMessagingTemplate) {
}
/**
- *
* 通过在
* 依据 {@code ChatMessage} 中的内容发送消息给特定用户,每个用户都订阅自己接受消息的端点
* {@code /user/@MessageMapping defines the endpoint for receiving message, client will send websocket message
- * to endpoints defined in this method. @SendTo defines the return value's target endpoint of some
- * method, clients which subscribe to this endpoint will receive the return value of this method. This method will
- * send received message to all clients that subscribe @SendTo endpoint, just like a broadcast
+ * @MessageMapping defines the endpoint for receiving messages, client will send websocket message
+ * to endpoints defined in this annotation.
+ * @SendTo defines the return value's target endpoint of this method, clients which subscribe to
+ * this endpoint will receive the return value of this method.
+ * This method will simply send messages received to all clients that subscribe to endpoint specified in
+ * @SendTo, just like a broadcast
*
* @MessageMapping 定义接收消息的端点,客户端发送 WebSocket 消息到此端点。
* @SendTo 定义方法返回值发送的端点,订阅该端点的客户端可以收到服务器端的回复。
* 此端点默认将收到的消息发送到所有订阅了 @SendTo 端点的客户端,相当于广播。
*
- * @param message 客户端消息
- * @param authorizationToken 自定义的请求校验 Token,后续也可以与 JWT 集成进行验证
- * @return 返回消息
+ * @param message client message
+ * @param authorizationToken customize header, for token validate
+ * @return return client message to all clients that subscribe to /b
*/
//
@MessageMapping("/broadcast")
@SendTo("/b")
- public Response say(Message message, @Header(value = "authorization") String authorizationToken) {
+ public Response broadcast(Message message, @Header(value = "authorization") String authorizationToken) {
val response = new Response("Token check failed!");
if (authorizationToken.equals(token)) {
log.info("Token check success!!!");
@@ -52,14 +55,14 @@ public Response say(Message message, @Header(value = "authorization") String aut
/**
* Add a placeholder in @MessageMapping to get the dynamic param in websocket url, for dynamic
- * resending. Message sent to this method will be resent to any clients that subscribe endpoint {@code /g/@MessageMapping 中添加消息占位符来获取 url 内容,从而动态转发。
* 消息会发送到所有订阅了 {@code /g/