写一下这两天遇到的问题
实时数据: 之前用的前台ajax的轮询,现在才知道这种方式特别low,没有一点实用性
解决方法: 使用websocket
websocket 的demo如下
前台:
<%@ page language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <title>Java后端WebSocket的Tomcat实现</title> </head> <body> Welcome<br/><input id="text" type="text"/> <button οnclick="send()">发送消息</button> <marquee id="realtimeContent" bgcolor="#6699CC" behavior="alternate">我是实时消息</marquee> <hr/> <button οnclick="closeWebSocket()">关闭WebSocket连接</button> <hr/> <div id="message"></div> </body> <script type="text/javascript"> var websocket = null; //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost/websocket"); } else { alert('当前浏览器 Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function () { setMessageInnerHTML("WebSocket连接发生错误"); }; //连接成功建立的回调方法 websocket.onopen = function () { setMessageInnerHTML("WebSocket连接成功"); } //接收到消息的回调方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); setMessageInnerHTMLOn(event.data) } //连接关闭的回调方法 websocket.onclose = function () { setMessageInnerHTML("WebSocket连接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { closeWebSocket(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //将消息显示在跑马灯上 function setMessageInnerHTMLOn(innerHTML) { if(innerHTML != null){ document.getElementById('realtimeContent').innerHTML =""; } document.getElementById('realtimeContent').innerHTML += innerHTML + '<br/>'; } //关闭WebSocket连接 function closeWebSocket() { websocket.close(); } //发送消息 function send() { var message = document.getElementById('text').value; websocket.send(message); } </script> </html>
后台:
import javax.websocket.*; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.CopyOnWriteArraySet; /** * Created by admin on 2017/11/17. */ @ServerEndpoint("/websocket") public class WebSocketTest { private static int onlineCount = 0; public static final CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>(); private Session session; @OnOpen public void onOpen(Session session){ this.session = session; webSocketSet.add(this); addOnlineCount(); System.out.println("有新连接加入!当前在线人数为"+ getOnlineCount()); } @OnClose public void onClose(){ webSocketSet.remove(this); subOnlineCount(); System.out.println("有一连接关闭!当前在线人数为"+ getOnlineCount()); } @OnMessage public void onMessage(String message,Session session){ System.out.println("来自客户端的消息:"+message+" "+getDate()); //群发消息 for (WebSocketTest item:webSocketSet){ try { item.sendMessage(message+ getDate()); } catch (IOException e) { e.printStackTrace(); continue; } } } @OnError public void onError(Session session,Throwable error){ System.out.println("发生错误"); error.printStackTrace(); } /** * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 * @param message * @throws IOException */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); //this.session.getAsyncRemote().sendText(message); } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketTest.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketTest.onlineCount--; } public String getDate(){ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 String date = df.format(new Date());// new Date()为获取当前系统时间,也可使用当前时间戳 return date; } }
应用场景:服务器推数据,设置个定时器+websocket
定时器代码如下:
import com.thinkgem.jeesite.common.utils.SpringContextHolder; import com.thinkgem.jeesite.modules.assets.entity.account.AssetsAccount; import com.thinkgem.jeesite.modules.assets.service.account.AssetsAccountService; import org.springframework.stereotype.Service; import javax.websocket.Session; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CopyOnWriteArraySet; /** * Created by admin on 2017/11/17. */ @Service public class TimerTest extends TimerTask { private String jobName = ""; private int currentTimes = 0; public TimerTest(String jobName) { this.jobName = jobName; } @Override public void run() { AssetsAccountService assetsAccountService = SpringContextHolder.getBean(AssetsAccountService.class); List<AssetsAccount> accountList = assetsAccountService.findAllList(new AssetsAccount()); System.out.println(accountList.size()); System.out.println("execute " + jobName+currentTimes); currentTimes++; CopyOnWriteArraySet<WebSocketTest> webSocketSet = WebSocketTest.webSocketSet; for (WebSocketTest item:webSocketSet){ try { item.sendMessage(getDate()); } catch (IOException e) { e.printStackTrace(); continue; } } } public String getDate(){ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 String date = df.format(new Date());// new Date()为获取当前系统时间,也可使用当前时间戳 return date; } }
监听器 :用于在项目初始化的时候就启动定时器,需要在web.xml中配置listener 来启动TaskManager
import java.util.Timer; /** * Created by admin on 2017/11/22. */ @Component public class TaskManager implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("监听开始......."); Timer timer = new Timer(); long delay1 = 1 * 1000; long period1 = 1000; timer.schedule(new TimerTest("job"), delay1, period1); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { } }
webxml 配置
<listener> <listener-class>com.thinkgem.jeesite.modules.sys.listener.TaskManager</listener-class> </listener>