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"))); });