android與服務端websocket通訊示例
阿新 • • 發佈:2019-01-08
服務端庫依賴詳見章末
spring websocket服務端程式碼(會話過程)
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
private static final Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.class);
//會話開始
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
attributes.put(Constant.WEBSOCKET_USERNAME,"LSH");
// 從session中獲取使用者
/*if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
HttpSession session = serverHttpRequest.getServletRequest().getSession(false);
if (session!=null) {
String username = (String) session.getAttribute(Constant.SESSION_USERNAME);
attributes.put(Constant.WEBSOCKET_USERNAME,username);
}
}*/
return true;
}
//會話結束
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
System.out.println("After Handshake");
super.afterHandshake(request, response, wsHandler, ex);
}
}
服務端websocket訊息處理
import com.beesgame.sanguo.constant.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.ArrayList;
/**
* Created by hackway on
* Date: 2016/1/15.
* Time:11:15
*/
public class WebSocketEndPoint extends TextWebSocketHandler {
private static final ArrayList<WebSocketSession> users;
private static final Logger logger;
static {
users = new ArrayList<WebSocketSession>();
logger = LoggerFactory.getLogger(WebSocketEndPoint.class);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
TextMessage returnMessage = new TextMessage(message.getPayload()+" received at server");
session.sendMessage(returnMessage);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.info("connect to the websocket success......");
//新增使用者到session
users.add(session);
String username = (String) session.getAttributes().get(Constant.WEBSOCKET_USERNAME);
if (username!=null) {
session.sendMessage(new TextMessage("使用者名稱:"+username));
}
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
}
logger.info("websocket transport error, connection closed......");
users.remove(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
logger.info("websocket connection closed......");
users.remove(session);
}
@Override
public boolean supportsPartialMessages() {
return super.supportsPartialMessages();
}
// 傳送資訊給特定使用者(LSH)
public void sendMessageToUser(String username, TextMessage message) {
for (WebSocketSession user:users) {
if (user.getAttributes().get(Constant.WEBSOCKET_USERNAME).equals(username)) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
//傳送資訊給所用使用者,廣播
public void sendMessageToAllUser(TextMessage message) {
for (WebSocketSession user:users) {
try {
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用註解配置websocket(需要在springmvc配置檔案中開啟相應註解支援)
@Configuration
//@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(getWebSocketEndPoint(),"/websocket").addInterceptors(new HandshakeInterceptor());
webSocketHandlerRegistry.addHandler(getWebSocketEndPoint(),"/websocket/sockjs").addInterceptors(new HandshakeInterceptor()).withSockJS();
}
@Bean
public WebSocketEndPoint getWebSocketEndPoint() {
return new WebSocketEndPoint();
}
}
controller呼叫websocket傳送資訊
@Controller("/*")
public class IndexController extends BaseController {
@Autowired
private UserInfoService userInfoService;
//注入websocket
@Bean
public WebSocketEndPoint getWebSocketEndpoint() {
return new WebSocketEndPoint();
}
@RequestMapping(value = "socket.do", produces = "text/json;charset=UTF-8", method = RequestMethod.GET)
@ResponseBody
public String socket(@RequestParam(value = "uid") long uid) throws IOException {
UserInfoVO userToken = userInfoService.getUserInfoVOByUid(uid);
String result = objectMapper.writeValueAsString(userToken);
getWebSocketEndpoint().sendMessageToUser("LSH", new TextMessage(result));
return result;
}
}
*服務端啟動截圖*
客戶端websocket連結服務端(android)
gradle中新增java-websocket依賴
compile ‘org.java-websocket:Java-WebSocket:1.3.0’
websocket客戶端類
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.util.Date;
/**
* Created by hackway on 16/2/24.
*/
public class SiteWebsocket extends WebSocketClient {
//handler通知主執行緒更新textview
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
textView.setText(String.valueOf(msg.obj));
}
};
private TextView textView;
public SiteWebsocket(URI serverUri, Draft draft, TextView tv) {
super(serverUri, draft);
this.textView = tv;
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.d("websocket","open connection");
}
@Override
public void onMessage(String message) {
Log.d("websocket","receive: "+message);
Message msg = new Message();
msg.obj = message;
handler.sendMessage(msg);
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.d("websocket","Connection close by "+(remote?"remote peer":"us") +" at "+new Date(System.currentTimeMillis()));
}
@Override
public void onError(Exception ex) {
ex.printStackTrace();
}
}
客戶端建立連結(MainActivity.java)
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import org.java_websocket.drafts.Draft_17;
import java.net.URI;
import java.net.URISyntaxException;
import site.hackway.www.androidsite.websocket.SiteWebsocket;
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
textView = (TextView) findViewById(R.id.txvw);
SiteWebsocket siteWebsocket = null;
try {
siteWebsocket = new SiteWebsocket(new URI("ws://192.168.1.103:8080/sanguo/websocket"),new Draft_17(),textView);
siteWebsocket.connectBlocking();
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
客戶端程式碼編寫完畢,啟動模擬器(注意客戶端服務端需處於統一區域網)
出現 使用者名稱:LSH 說明連線成功
接著測試服務端向客戶端傳送訊息
通過瀏覽器訪問 http://ip:port/your project name/socket.do?uid=1
服務端推送資訊成功
服務端maven依賴,(其中spring的版本需要大於4)
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.1.0</version>
</dependency>
<!-- logback日誌配置 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>