最近研究了两种服务器消息推送技术,一种是WebSocket技术,一种是基于Servlet3.0实现的服务器异步消息推送技术,具体实现如下:
1. WebSocket(聊天室)
WebSocket客户端连接类(javaee-api-7.0.jar)
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
/**
* @ServerEndpoint 功能主要是将CharRoomServer 定义为websocket服务器端
*/
@ServerEndpoint("/ws/charRoomServer")
public class CharRoomServer {
// 会话,主要用于向客户端发送数据
private Session session;
public Session getSession() {
return session;
}
/**
* websocket连接
* @param session
*/
@OnOpen
public void onOpen(Session session){
this.session = session;
SessionManager.add(this);
}
/**
* websocket断开
*/
@OnClose
public void onClose(){
SessionManage.remove(this);
}
/**
* websocket消息
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String messageFormat = "{\"date\":\"%s\",\"name\":\"%s\",\"content\":\"%s\"}";
String msg = String.format(messageFormat, sdf.format(date),
"客户端" + session.getId(), message);
// 广播
SessionManage.broadCast(msg);
}
/**
* websocket错误
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
error.printStackTrace();
}
/**
* 广播消息方法
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException{
this.session.getBasicRemote().sendText(message);
}
}
SessionManage类
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
public class SessionManage {
private static Collection<CharRoomServer> charRoomServers = Collections.synchronizedCollection(new ArrayList<CharRoomServer>());
/**
* 广播
* @param msg
*/
public static void broadCast(String msg){
for (CharRoomServer charRoomServer : charRoomServers) {
try {
charRoomServer.sendMessage(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 新增客户端服务器
* @param charRoomServer
*/
public static void add(CharRoomServer charRoomServer){
// 使用时间构造登录信息
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String messageFormat = "{\"date\":\"%s\",\"name\":\"系统\",\"content\":\"%s\"}";
String content = "欢迎客户端" + charRoomServer.getSession().getId();
String message = String.format(messageFormat, sdf.format(date), content);
// 广播
broadCast(message);
// 加入服务组
charRoomServers.add(charRoomServer);
}
/**
* 客户端服务器退出
* @param charRoomServer
*/
public static void remove(CharRoomServer charRoomServer){
// 客户端服务器退出
charRoomServers.remove(charRoomServer);
// 使用时间构造退出信息
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String messageFormat = "{\"date\":\"%s\",\"name\":\"系统\",\"content\":\"%s\"}";
String name = "客户端" + charRoomServer.getSession().getId();
String message = String.format(messageFormat, sdf.format(date), name + "已退出");
// 广播
broadCast(message);
}
}
2. Servlet3.0(SpringBoot:DeferredResult)
Application 入口类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableAsync
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AsyncController异步控制器
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
/**
* 异步控制器
*/
@RequestMapping("/async")
@RestController
public class AsyncController {
private DeferredResult<String> deferredResult;
@RequestMapping("/getDeferredResult")
public DeferredResult<String> getDeferredResult() {
deferredResult = new DeferredResult<String>();
return deferredResult;
}
/**
* 每2秒执行一次
*/
@Scheduled(fixedDelay = 2000)
public void refreshDeferredResult() {
if (deferredResult != null) {
String result = "getDeferredResult:" + System.currentTimeMillis();
deferredResult.setResult(result);
}
}
@RequestMapping("/getResult")
public String getResult() {
return "getResult";
}
}
前端页面关键js代码
function getDeferredResult() {
$.ajax({
url:"/async/getDeferredResult",
type:"post",
success:function(data){
$("table").html(data);
getDeferredResult();
}
});
}
getDeferredResult();
pom文件配置
<?xml version="1.0" encoding="UTF-8"?>
<project 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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.async</groupId>
<artifactId>async</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 编码和版本 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.plugin.version>3.7.0</maven.compiler.plugin.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>