1.下載好websocket的jar包,下載地址,項目中使用的是1.3.4版本;javascript
2.建立WebSocket類,繼承WebSocketServer,實現onClose,onMessage,onError,onStart方法java
public class WebSocket extends WebSocketServer { private static final Logger LOGGER = LoggerFactory.getLogger(WebSocket.class); //要檢測的頁面名稱 private static final List<String> MENU_LIST = new ArrayList<String>(); //要檢測的頁面對應id private static final List<String> MENU_ID_LIST = new ArrayList<String>(); public WebSocket(InetSocketAddress address) { super(address); } public WebSocket(int port) throws UnknownHostException { super(new InetSocketAddress(port)); } /** * 觸發鏈接事件 */ @Override public void onOpen(org.java_websocket.WebSocket conn, ClientHandshake handshake) { } /** * 觸發關閉事件 */ @SuppressWarnings("static-access") @Override public void onClose(org.java_websocket.WebSocket conn, int message, String reason, boolean remote) { //從鏈接池中獲取鏈接傳輸過來的信息 VisitLengthVO visitLengthVO = WebSocketPool.getInstance().getVisitLength(conn); //判斷是否屬於須要監測的頁面 if (visitLengthVO != null && MENU_LIST.contains(visitLengthVO.getMenuName()) && MENU_ID_LIST.contains(visitLengthVO.getMenuId())) { VisitLengthVO obj = new VisitLengthVO(); try { //轉換實體,計算時長,將數據插入相關表中 BeanUtilEx.copyProperties(obj, visitLengthVO); Long startTime = visitLengthVO.getStartTime(); double timeLength = (System.currentTimeMillis() - startTime) / 1000.0; obj.setTimeLength(timeLength); VisitLengthFacade visitLengthFacade = (VisitLengthFacade) AppContext .getBean("visitLengthFacade"); visitLengthFacade.insertUserVisit(obj); //從鏈接池移除 WebSocketPool.getInstance().removeUser(conn); } catch (Exception e) { LOGGER.error("webscoket關閉時實體轉換異常", e.toString()); } } } /** * 接收到消息觸發事件 */ @SuppressWarnings("static-access") @Override public void onMessage(org.java_websocket.WebSocket conn, String message) { message = message.toString(); JSONObject objparams = JSONObject.fromObject(message); if (objparams != null) { VisitLengthVO vo = new VisitLengthVO(); try { //接收消息,並將消息存入到鏈接池中 BeanUtilEx.copyProperties(vo, objparams); vo.setStartTime(System.currentTimeMillis()); WebSocketPool.getInstance().addVisitLength(vo, conn); } catch (Exception e) { LOGGER.error("webscoket接收消息時實體轉換異常", e.toString()); } } } /** * 觸發異常事件 */ @Override public void onError(org.java_websocket.WebSocket conn, Exception message) { LOGGER.error("websocket關閉異常", message.toString()); } @Override public void onStart() { //初始化要檢測的頁面和頁面對應的id MenuFacade menuFacade = (MenuFacade) AppContext.getBean("menuFacade"); List<MenuVO> menuList = menuFacade.queryMenuList(new MenuVO()); for (MenuVO vo : menuList) { MENU_LIST.add(vo.getMenuName()); MENU_ID_LIST.add(vo.getMenuId()); } } }
/*** websocket鏈接池 */ public final class WebSocketPool { /*** 構造器私有化 */ private WebSocketPool() { } private static class WebSocketPoolHolder { private static WebSocketPool INSTANCE = new WebSocketPool(); } public static WebSocketPool getInstance() { return WebSocketPoolHolder.INSTANCE; } /*** 用戶訪問時長 */ private static final Map<WebSocket, VisitLengthVO> VISIT_LENGTH_MAP = new HashMap<WebSocket, VisitLengthVO>(); /** * 獲取用戶訪問時長信息 * * @param conn 鏈接對應的對象 * @return 用戶訪問時長信息 */ public static VisitLengthVO getVisitLength(WebSocket conn) { return VISIT_LENGTH_MAP.get(conn); } /** * 添加用戶訪問信息 * * @param vo 用戶訪問信息 * @param conn 連接對象 */ public static void addVisitLength(VisitLengthVO vo, WebSocket conn) { VISIT_LENGTH_MAP.put(conn, vo); } /** * 移除連接 * * @param conn 移除連接 */ public static void removeUser(WebSocket conn) { if (VISIT_LENGTH_MAP.containsKey(conn)) { VISIT_LENGTH_MAP.remove(conn); } } }
實體類:web
public class VisitLengthVO { /** * 主鍵ID */ @Column(name = "SEQ_ID", length = 32, precision = 0) private String seqId; /** * 菜單ID */ @Column(name = "MENU_ID", length = 32, precision = 0) private String menuId; /** * 菜單名稱 */ @Column(name = "MENU_NAME", length = 50, precision = 0) private String menuName; /** * 訪問者 */ @Column(name = "EMPLOYEE_NAME", length = 50, precision = 0) private String employeeName; /** * 訪問者帳號 */ @Column(name = "EMPLOYEE_ACCOUNT", length = 100, precision = 0) private String employeeAccount; /** * 訪問者類型,0非重點用戶,1重點用戶 */ @Column(name = "EMPLOYEE_TYPE", length = 32, precision = 0) private String employeeType; /** * 用戶所屬區域 */ @Column(name = "ORG_CODE", length = 32, precision = 0) private String orgCode; /** * 訪問時長 */ @Column(name = "TIME_LENGTH", length = 10, precision = 2) private Double timeLength; /** * 訪問時間 */ @Column(name = "VISIT_DATE", length = 7, precision = 0) private Date visitDate; /** * 統計年月 */ @Column(name = "TIME_ID", length = 32, precision = 0) private String timeId; /** * 訪問時長 */ @Column(name = "IMPORTANT_TIME_LENGTH", length = 10, precision = 2) private Double importantTimeLength; /** * 同比 */ @Column(name = "PRECENT", precision = 2) private Double precent; /** * 開始訪問時間 */ private long startTime; /** * 主鍵ID * * @return 主鍵ID */ public String getSeqId() { return seqId; } /** * 主鍵ID * * @param seqId 主鍵ID */ public void setSeqId(String seqId) { this.seqId = seqId == null ? null : seqId.trim(); } /** * 菜單ID * * @return 菜單ID */ public String getMenuId() { return menuId; } /** * 菜單ID * * @param menuId 菜單ID */ public void setMenuId(String menuId) { this.menuId = menuId == null ? null : menuId.trim(); } /** * 菜單名稱 * * @return 菜單名稱 */ public String getMenuName() { return menuName; } /** * 菜單名稱 * * @param menuName 菜單名稱 */ public void setMenuName(String menuName) { this.menuName = menuName == null ? null : menuName.trim(); } /** * 訪問者 * * @return 訪問者 */ public String getEmployeeName() { return employeeName; } /** * 訪問者 * * @param employeeName 訪問者 */ public void setEmployeeName(String employeeName) { this.employeeName = employeeName == null ? null : employeeName.trim(); } /** * 訪問者帳號 * * @return 訪問者帳號 */ public String getEmployeeAccount() { return employeeAccount; } /** * 訪問者帳號 * * @param employeeAccount 訪問者帳號 */ public void setEmployeeAccount(String employeeAccount) { this.employeeAccount = employeeAccount == null ? null : employeeAccount.trim(); } /** * 訪問者類型,0非重點用戶,1重點用戶 * * @return 訪問者類型,0非重點用戶,1重點用戶 */ public String getEmployeeType() { return employeeType; } /** * 訪問者類型,0非重點用戶,1重點用戶 * * @param employeeType 訪問者類型,0非重點用戶,1重點用戶 */ public void setEmployeeType(String employeeType) { this.employeeType = employeeType == null ? null : employeeType.trim(); } /** * 用戶所屬區域 * * @return 用戶所屬區域 */ public String getOrgCode() { return orgCode; } /** * 用戶所屬區域 * * @param orgCode 用戶所屬區域 */ public void setOrgCode(String orgCode) { this.orgCode = orgCode == null ? null : orgCode.trim(); } /** * 訪問時長 * * @return 訪問時長 */ public Double getTimeLength() { return timeLength; } /** * 訪問時長 * * @param timeLength 訪問時長 */ public void setTimeLength(Double timeLength) { this.timeLength = timeLength; } public Date getVisitDate() { return visitDate; } public void setVisitDate(Date visitDate) { this.visitDate = visitDate; } public String getTimeId() { return timeId; } public void setTimeId(String timeId) { this.timeId = timeId; } public Double getImportantTimeLength() { return importantTimeLength; } public void setImportantTimeLength(Double importantTimeLength) { this.importantTimeLength = importantTimeLength; } public Double getPrecent() { return precent; } public void setPrecent(Double precent) { this.precent = precent; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } }
3.建立一個WebSocketFilter,用來啓動攔截請求,並啓動websocket;安全
public class WebSocketFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(request, response); } @Override public void init(FilterConfig arg0) throws ServletException { this.startWebsocketOnline(); } public void startWebsocketOnline() { System.out.println("開始啓動websocket"); WebSocketImpl.DEBUG = false; int port =8888; //端口號 WebSocket s = null; try { s = new WebSocket(port); } catch (UnknownHostException e) { e.printStackTrace(); } s.start(); System.out.println("啓動websocket成功!"); } }
4.在web.xml中配置攔截器服務器
<!-- websocket過濾器 --> <filter> <filter-name>websocketFilter</filter-name> <filter-class>com.filiter.WebSocketFilter</filter-class> </filter> <filter-mapping> <filter-name>websocketFilter</filter-name> <url-pattern>*.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping> <filter-mapping> <filter-name>websocketFilter</filter-name> <url-pattern>*.ac</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
5.實現websocket.js,主要實現兩個方法websocket
/** * 申請一個WebSocket對象,參數是須要鏈接的服務器端的地址, 同http協議使用http://開頭同樣, * WebSocket協議的URL使用ws://開頭, 另外安全的WebSocket協議使用wss://開頭 */ function openWs(message){ var ws = new WebSocket("ws://127.0.0.1:8888"); //當websocket建立成功時,即會觸發onopen事件 ws.onopen = function(){ ws.send(message); }; //當客戶端收到服務端發來的消息時,會觸發onmessage事件,參數evt.data中包含server傳輸過來的數據 ws.onmessage = function(evt){ }; //當客戶端收到服務端發送的關閉鏈接的請求時,觸發onclose事件 ws.onclose = function(evt){ }; //若是出現鏈接,處理,接收,發送數據失敗的時候就會觸發onerror事件 ws.onerror = function(evt){ }; } /** * 根據指標序號封裝不一樣的客戶端信息 * @param index 指標序號 */ function getWsMessage(index){ var message = {}; message = { employeeAccount :"", employeeName : "", orgCode : "", menuId : "", menuName : "" } return message; }
6.在jsp的onload裏面調用openWs方法java-web
$(function(){ //開啓websocket openWs(JSON.stringify(getWsMessage("9"))); });