Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a6b32b2

Browse files
committed
独立抽取 ChatTunnelHandler,补充 Demo 注释
1 parent 2c8e5f1 commit a6b32b2

File tree

4 files changed

+173
-121
lines changed

4 files changed

+173
-121
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.qcloud.weapp.demo;
2+
3+
import java.util.HashMap;
4+
5+
import org.json.JSONException;
6+
import org.json.JSONObject;
7+
8+
import com.qcloud.weapp.authorization.UserInfo;
9+
import com.qcloud.weapp.tunnel.EmitError;
10+
import com.qcloud.weapp.tunnel.EmitResult;
11+
import com.qcloud.weapp.tunnel.Tunnel;
12+
import com.qcloud.weapp.tunnel.TunnelHandler;
13+
import com.qcloud.weapp.tunnel.TunnelInvalidInfo;
14+
import com.qcloud.weapp.tunnel.TunnelMessage;
15+
import com.qcloud.weapp.tunnel.TunnelRoom;
16+
17+
/**
18+
* <h1>实现 WebSocket 信道处理器</h1>
19+
* <p>本示例配合客户端 Demo 实现一个简单的聊天室功能</p>
20+
*
21+
* <p>信道处理器需要处理信道的完整声明周期,包括:</p>
22+
* <ul>
23+
* <li>onTunnelRequest() - 当用户发起信道请求的时候,会得到用户信息,此时可以关联信道 ID 和用户信息</li>
24+
* <li>onTunnelConnect() - 当用户建立了信道连接之后,可以记录下已经连接的信道</li>
25+
* <li>onTunnelMessage() - 当用户消息发送到信道上时,使用该函数处理信道的消息</li>
26+
* <li>onTunnelClose() - 当信道关闭时,清理关于该信道的信息,以及回收相关资源</li>
27+
* </ul>
28+
* */
29+
public class ChatTunnelHandler implements TunnelHandler {
30+
31+
/**
32+
* 记录 WebSocket 信道对应的用户。在实际的业务中,应该使用数据库进行存储跟踪,这里作为示例只是演示其作用
33+
* */
34+
private static HashMap<String, UserInfo> userMap = new HashMap<String, UserInfo>();
35+
36+
/**
37+
* 创建一个房间,包含当前已连接的 WebSocket 信道列表
38+
* */
39+
private static TunnelRoom room = new TunnelRoom();
40+
41+
/**
42+
* 实现 OnTunnelRequest 方法<br/>
43+
* 在客户端请求 WebSocket 信道连接之后,会调用 OnTunnelRequest 方法,此时可以把信道 ID 和用户信息关联起来
44+
* */
45+
@Override
46+
public void onTunnelRequest(Tunnel tunnel, UserInfo userInfo) {
47+
if (tunnel.getTunnelId() == "test") {
48+
userInfo = new UserInfo();
49+
}
50+
if (userInfo != null) {
51+
userMap.put(tunnel.getTunnelId(), userInfo);
52+
}
53+
System.out.println(String.format("Tunnel Connected: %s", tunnel.getTunnelId()));
54+
}
55+
56+
/**
57+
* 实现 OnTunnelConnect 方法<br/>
58+
* 在客户端成功连接 WebSocket 信道服务之后会调用该方法,此时通知所有其它在线的用户当前总人数以及刚加入的用户是谁
59+
* */
60+
@Override
61+
public void onTunnelConnect(Tunnel tunnel) {
62+
if (userMap.containsKey(tunnel.getTunnelId())) {
63+
room.addTunnel(tunnel);
64+
JSONObject peopleMessage = new JSONObject();
65+
try {
66+
peopleMessage.put("total", room.getTunnelCount());
67+
peopleMessage.put("enter", new JSONObject(userMap.get(tunnel.getTunnelId())));
68+
} catch (JSONException e) {
69+
e.printStackTrace();
70+
}
71+
broadcast("people", peopleMessage);
72+
} else {
73+
closeTunnel(tunnel);
74+
}
75+
}
76+
77+
/**
78+
* 实现 OnTunnelMessage 方法
79+
* 客户端推送消息到 WebSocket 信道服务器上后,会调用该方法,此时可以处理信道的消息。
80+
* 在本示例,我们处理 "speak" 类型的消息,该消息表示有用户发言。我们把这个发言的信息广播到所有在线的 WebSocket 信道上
81+
* */
82+
@Override
83+
public void onTunnelMessage(Tunnel tunnel, TunnelMessage message) {
84+
if (message.getType().equals("speak") && userMap.containsKey(tunnel.getTunnelId())) {
85+
JSONObject speakMessage = new JSONObject();
86+
try {
87+
JSONObject messageContent = (JSONObject) message.getContent();
88+
speakMessage.put("word", messageContent.getString("word"));
89+
speakMessage.put("who", new JSONObject(userMap.get(tunnel.getTunnelId())));
90+
} catch (JSONException e) {
91+
e.printStackTrace();
92+
}
93+
broadcast("speak", speakMessage);
94+
} else {
95+
closeTunnel(tunnel);
96+
}
97+
98+
}
99+
100+
/**
101+
* 实现 OnTunnelClose 方法
102+
* 客户端关闭 WebSocket 信道或者被信道服务器判断为已断开后,会调用该方法,此时可以进行清理及通知操作
103+
* */
104+
@Override
105+
public void onTunnelClose(Tunnel tunnel) {
106+
UserInfo leaveUser = null;
107+
if (userMap.containsKey(tunnel.getTunnelId())) {
108+
leaveUser = userMap.get(tunnel.getTunnelId());
109+
userMap.remove(tunnel.getTunnelId());
110+
}
111+
room.removeTunnel(tunnel);
112+
JSONObject peopleMessage = new JSONObject();
113+
try {
114+
peopleMessage.put("total", room.getTunnelCount());
115+
peopleMessage.put("leave", new JSONObject(leaveUser));
116+
} catch (JSONException e) {
117+
e.printStackTrace();
118+
}
119+
broadcast("people", peopleMessage);
120+
}
121+
122+
/**
123+
* 关闭指定的信道
124+
* */
125+
private void closeTunnel(Tunnel tunnel) {
126+
try {
127+
tunnel.close();
128+
} catch (EmitError e) {
129+
e.printStackTrace();
130+
}
131+
}
132+
133+
/**
134+
* 广播消息到房间里所有的信道
135+
* */
136+
private void broadcast(String messageType, JSONObject messageContent) {
137+
try {
138+
EmitResult result = room.broadcast(messageType, messageContent);
139+
// 广播后发现的无效信道进行清理
140+
for (TunnelInvalidInfo invalidInfo : result.getTunnelInvalidInfos()) {
141+
onTunnelClose(Tunnel.getById(invalidInfo.getTunnelId()));
142+
}
143+
} catch (EmitError e) {
144+
// 如果消息发送发生异常,这里可以进行错误处理或者重试的逻辑
145+
e.printStackTrace();
146+
}
147+
}
148+
}

com.qcloud.weapp.demo/src/com/qcloud/weapp/demo/servlet/LoginServlet.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,21 @@ public class LoginServlet extends HttpServlet {
1818
private static final long serialVersionUID = 6585319986631669934L;
1919

2020
/**
21-
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
22-
*/
21+
* 处理登录请求
22+
* */
2323
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
24+
// 通过 ServletRequest 和 ServletResponse 初始化登录服务
2425
LoginService service = new LoginService(request, response);
2526
try {
27+
// 调用登录接口,如果登录成功可以获得登录信息
2628
UserInfo userInfo = service.login();
2729
System.out.println("========= LoginSuccess, UserInfo: ==========");
2830
System.out.println(userInfo.toString());
29-
} catch (IllegalArgumentException e) {
30-
e.printStackTrace();
3131
} catch (LoginServiceException e) {
32+
// 登录失败会抛出登录失败异常
3233
e.printStackTrace();
3334
} catch (ConfigurationException e) {
35+
// SDK 如果还没有配置会抛出配置异常
3436
e.printStackTrace();
3537
}
3638
}

com.qcloud.weapp.demo/src/com/qcloud/weapp/demo/servlet/TunnelServlet.java

Lines changed: 12 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,40 @@
11
package com.qcloud.weapp.demo.servlet;
22

33
import java.io.IOException;
4-
import java.util.HashMap;
5-
64
import javax.servlet.ServletException;
75
import javax.servlet.annotation.WebServlet;
86
import javax.servlet.http.HttpServlet;
97
import javax.servlet.http.HttpServletRequest;
108
import javax.servlet.http.HttpServletResponse;
119

12-
import org.json.JSONException;
13-
import org.json.JSONObject;
14-
1510
import com.qcloud.weapp.ConfigurationException;
16-
import com.qcloud.weapp.authorization.UserInfo;
17-
import com.qcloud.weapp.tunnel.EmitError;
18-
import com.qcloud.weapp.tunnel.EmitResult;
19-
import com.qcloud.weapp.tunnel.Tunnel;
2011
import com.qcloud.weapp.tunnel.TunnelHandleOptions;
21-
import com.qcloud.weapp.tunnel.TunnelHandler;
22-
import com.qcloud.weapp.tunnel.TunnelInvalidInfo;
23-
import com.qcloud.weapp.tunnel.TunnelMessage;
24-
import com.qcloud.weapp.tunnel.TunnelRoom;
2512
import com.qcloud.weapp.tunnel.TunnelService;
13+
import com.qcloud.weapp.demo.ChatTunnelHandler;
2614

2715
/**
28-
* Servlet implementation class TunnelServlet
16+
* 使用 SDK 提供信道服务
2917
*/
3018
@WebServlet("/tunnel")
3119
public class TunnelServlet extends HttpServlet {
3220
private static final long serialVersionUID = -6490955903032763981L;
3321

34-
private static HashMap<String, UserInfo> userMap = new HashMap<String, UserInfo>();
35-
private static TunnelRoom room = new TunnelRoom();
36-
3722
/**
38-
* @see HttpServlet#service(HttpServletRequest request, HttpServletResponse
39-
* response)
23+
* 把所有的请求交给 SDK 处理,提供 TunnelHandler 处理信道事件
4024
*/
4125
protected void service(HttpServletRequest request, HttpServletResponse response)
4226
throws ServletException, IOException {
27+
28+
// 创建信道服务处理信道相关请求
4329
TunnelService tunnelService = new TunnelService(request, response);
44-
TunnelHandleOptions options = new TunnelHandleOptions();
45-
46-
options.setCheckLogin(true);
47-
30+
4831
try {
49-
tunnelService.handle(new TunnelHandler() {
50-
51-
@Override
52-
public void onTunnelRequest(Tunnel tunnel, UserInfo userInfo) {
53-
if (tunnel.getTunnelId() == "test") {
54-
userInfo = new UserInfo();
55-
}
56-
if (userInfo != null) {
57-
userMap.put(tunnel.getTunnelId(), userInfo);
58-
}
59-
System.out.println(String.format("Tunnel Connected: %s", tunnel.getTunnelId()));
60-
}
61-
62-
@Override
63-
public void onTunnelConnect(Tunnel tunnel) {
64-
if (userMap.containsKey(tunnel.getTunnelId())) {
65-
room.addTunnel(tunnel);
66-
JSONObject peopleMessage = new JSONObject();
67-
try {
68-
peopleMessage.put("total", room.getTunnelCount());
69-
peopleMessage.put("enter", new JSONObject(userMap.get(tunnel.getTunnelId())));
70-
} catch (JSONException e) {
71-
e.printStackTrace();
72-
}
73-
broadcast("people", peopleMessage);
74-
} else {
75-
closeTunnel(tunnel);
76-
}
77-
}
78-
79-
@Override
80-
public void onTunnelMessage(Tunnel tunnel, TunnelMessage message) {
81-
if (message.getType().equals("speak") && userMap.containsKey(tunnel.getTunnelId())) {
82-
JSONObject speakMessage = new JSONObject();
83-
try {
84-
JSONObject messageContent = (JSONObject) message.getContent();
85-
speakMessage.put("word", messageContent.getString("word"));
86-
speakMessage.put("who", new JSONObject(userMap.get(tunnel.getTunnelId())));
87-
} catch (JSONException e) {
88-
e.printStackTrace();
89-
}
90-
broadcast("speak", speakMessage);
91-
} else {
92-
closeTunnel(tunnel);
93-
}
94-
95-
}
96-
97-
@Override
98-
public void onTunnelClose(Tunnel tunnel) {
99-
UserInfo leaveUser = null;
100-
if (userMap.containsKey(tunnel.getTunnelId())) {
101-
leaveUser = userMap.get(tunnel.getTunnelId());
102-
userMap.remove(tunnel.getTunnelId());
103-
}
104-
room.removeTunnel(tunnel);
105-
JSONObject peopleMessage = new JSONObject();
106-
try {
107-
peopleMessage.put("total", room.getTunnelCount());
108-
peopleMessage.put("leave", new JSONObject(leaveUser));
109-
} catch (JSONException e) {
110-
e.printStackTrace();
111-
}
112-
broadcast("people", peopleMessage);
113-
}
114-
115-
private void closeTunnel(Tunnel tunnel) {
116-
try {
117-
tunnel.close();
118-
} catch (EmitError e) {
119-
e.printStackTrace();
120-
}
121-
}
122-
123-
private void broadcast(String messageType, JSONObject messageContent) {
124-
try {
125-
EmitResult result = room.broadcast(messageType, messageContent);
126-
for (TunnelInvalidInfo invalidInfo : result.getTunnelInvalidInfos()) {
127-
onTunnelClose(Tunnel.getById(invalidInfo.getTunnelId()));
128-
}
129-
} catch (EmitError e) {
130-
// 如果消息发送发生异常,这里可以进行错误处理或者重试的逻辑
131-
e.printStackTrace();
132-
}
133-
}
134-
}, options);
32+
// 配置是可选的,配置 CheckLogin 为 true 的话,会在隧道建立之前获取用户信息,以便业务将隧道和用户关联起来
33+
TunnelHandleOptions options = new TunnelHandleOptions();
34+
options.setCheckLogin(true);
35+
36+
// 需要实现信道处理器,ChatTunnelHandler 是一个实现的范例
37+
tunnelService.handle(new ChatTunnelHandler(), options);
13538
} catch (ConfigurationException e) {
13639
e.printStackTrace();
13740
}

com.qcloud.weapp.demo/src/com/qcloud/weapp/demo/servlet/UserServlet.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,25 @@ public class UserServlet extends HttpServlet {
2424
private static final long serialVersionUID = 6579706670441711811L;
2525

2626
/**
27-
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
27+
* 从请求中获取会话中的用户信息
2828
*/
2929
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
3030
LoginService service = new LoginService(request, response);
3131
try {
32+
// 调用检查登录接口,成功后可以获得用户信息,进行正常的业务请求
3233
UserInfo userInfo = service.check();
33-
System.out.println("========= CheckLoginSuccess, UserInfo: ==========");
34-
System.out.println(userInfo.toString());
35-
response.setContentType("application/json");
36-
response.setCharacterEncoding("utf-8");
3734

35+
// 获取会话成功,输出获得的用户信息
3836
JSONObject result = new JSONObject();
3937
JSONObject data = new JSONObject();
4038
data.put("userInfo", new JSONObject(userInfo));
4139
result.put("code", 0);
4240
result.put("message", "OK");
43-
result.put("data", data);
41+
result.put("data", data);
42+
response.setContentType("application/json");
43+
response.setCharacterEncoding("utf-8");
4444
response.getWriter().write(result.toString());
45-
} catch (IllegalArgumentException e) {
46-
e.printStackTrace();
45+
4746
} catch (LoginServiceException e) {
4847
e.printStackTrace();
4948
} catch (JSONException e) {

0 commit comments

Comments
 (0)