java用webSocket实现tomcat的日志实时输出到web页面______软件开发-JAVA
2016-10-10 18:16
836 查看
java用webSocket实现tomcat的日志实时输出到web页面
1.场景需求
后台攻城狮和前端攻城狮一起开发时,经常受到前端攻城狮的骚扰,动不动就来一句,那谁,帮我看一下接口访问出什么错了。。。我刚刚上传的参数过来了吗。。。你返回的是什么。。。我请求过去了吗。。。 好吧,就是这样的一种情况,然后我希望让他们自己去看后台日志,而又不想给他们登陆服务器的权限TAT。那就想办法把访问日志实时输出到web页面,这样他们打开页面就可以了。
2.特别鸣谢
1)特别感谢http://blog.csdn.net/xiao__gui/article/details/50041673的启发,该文章中利用的是linux中的tail日志,本文即是受此启发,基本思路一模一样,感谢感谢。 2)感谢国产博客中各种websocket教程,获益颇多,本文其实也是一个websocket教程,只是稍作拓展。
3.进入正题
配置websocket,大部分web项目都会用到spring框架吧,所有这里贴spring websocket的配置,不用spring的请自行去掉spring部分。spring使用4.0以上,tomcat使用7.0.68版本。
1)pom.xml中包的引入:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.3.1</version> </dependency> <dependenc 1b94c y> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>4.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.5.RELEASE</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2)websocket逻辑代码,需要一个config和一个handle
configuration:
package com.he.websocket; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; /** * WebScoket配置处理器 * @author he * @Date 2016年03月15日 下午1:15:09 */ @Configuration @EnableWebSocket public class WebsocketConfig implements WebSocketConfigurer { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/ws").addInterceptors(new HttpSessionHandshakeInterceptor()); registry.addHandler(myHandler(), "/ws/sockjs").addInterceptors(new HttpSessionHandshakeInterceptor()).withSockJS(); } @Bean public WebsocketHandler myHandler() { return new WebsocketHandler(); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
handle:
package com.he.websocket; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.he.entity.Message; @Component public class WebsocketHandler extends TextWebSocketHandler { protected static final Logger LOG = Logger.getLogger(WebsocketHandler.class); public static final Map<Object, WebSocketSession> userSocketSessionMap; static { userSocketSessionMap = new HashMap<Object, WebSocketSession>(); } /** * 建立连接后 */ public void afterConnectionEstablished(WebSocketSession session) throws Exception { String uid = (String) session.getAttributes().get("uid"); if (userSocketSessionMap.get(uid) == null) { userSocketSessionMap.put(uid, session); } LOG.warn("======建立连接完成======"); } /** * 消息处理,在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理 */ @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { if(message.getPayloadLength()==0)return; Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class); String msgString = message.getPayload().toString(); LOG.warn("收到的消息是:" + msgString); LOG.warn("发送的对象是:" + msg.getTo()); msg.setDate(new Date()); sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg))); LOG.warn("======消息处理结束======"); } /** * 消息传输错误处理 */ public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { if (session.isOpen()) { session.close(); } Iterator<Entry<Object, WebSocketSession>> it = userSocketSessionMap .entrySet().iterator(); LOG.warn("======消息传输错误======"); // 移除Socket会话 while (it.hasNext()) { Entry<Object, WebSocketSession> entry = it.next(); if (entry.getValue().getId().equals(session.getId())) { userSocketSessionMap.remove(entry.getKey()); System.out.println("Socket会话已经移除:用户ID" + entry.getKey()); break; } } } /** * 关闭连接后 */ public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { LOG.warn("Websocket:" + session.getId() + "已经关闭"); Iterator<Entry<Object, WebSocketSession>> it = userSocketSessionMap .entrySet().iterator(); // 移除Socket会话 LOG.warn("======关闭连接======"); while (it.hasNext()) { Entry<Object, WebSocketSession> entry = it.next(); if (entry.getValue().getId().equals(session.getId())) { userSocketSessionMap.remove(entry.getKey()); LOG.warn("Socket会话已经移除:用户ID" + entry.getKey()); break; } } } public boolean supportsPartialMessages() { return false; } /** * 给所有在线用户发送消息 * * @param message * @throws IOException */ public void broadcast(final TextMessage message) throws IOException { Iterator<Entry<Object, WebSocketSession>> it = userSocketSessionMap .entrySet().iterator(); LOG.warn("======群发======"); // 多线程群发 while (it.hasNext()) { final Entry<Object, WebSocketSession> entry = it.next(); if (entry.getValue().isOpen()) { // entry.getValue().sendMessage(message); new Thread(new Runnable() { public void run() { try { if (entry.getValue().isOpen()) { entry.getValue().sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } }).start(); } } } /** * 给某个用户发送消息 * * @param userName * @param message * @throws IOException */ public void sendMessageToUser(String uid, TextMessage message) throws IOException { WebSocketSession session = userSocketSessionMap.get(uid); LOG.warn("======给某个用户发送消息======"); if (session != null && session.isOpen()) { session.sendMessage(message); } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
3)web.xml中配置spring和springMVC,因为借助与springMVC来拦截处理websocket请求,如果用其他MVC框架,请自行替换。不想换也可以用springMVC,侵入性很低,并且本来就可以多种MVC共存。
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/classes/applicationContext.xml </param-value> </context-param> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
注意web.xml的头部:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">[/code]1 2
3
4
5
4)spring的xml文件中对websocket的配置:<!-- websocket配置 --> <bean id="websocket" class="com.he.websocket.WebsocketHandler" /> <websocket:handlers> <websocket:mapping path="/ws.do" handler="websocket" /> <websocket:handshake-interceptors> <bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor" /> </websocket:handshake-interceptors> </websocket:handlers> <!-- 需要扫描的包--> <context:component-scan base-package="com.he.websocket.WebsocketConfig" /> <context:component-scan base-package="com.he.websocket.WebsocketHandler" />1
2
3
4
5
6
7
8
9
10
11
12
注意spring的xml的头部:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:websocket="http://www.springframework.org/schema/websocket" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd ">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
5)日志接收页面:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>tail log</title> <script src="//cdn.bootcss.com/jquery/2.1.4/jquery.js"></script> <style> html,body { height:100%; width:100%; } </style> </head> <body> <div id="log-container" style="height: 100%; overflow-y: scroll; background: #333; color: #aaa; padding: 10px;"> <div> </div> </div> </body> <script> $(document).ready(function() { // 指定websocket路径 var websocket = new WebSocket('ws://localhost:8080/websocket/ws.do'); websocket.onmessage = function(event) { // 接收服务端的实时日志并添加到HTML页面中 $("#log-container div").append(event.data + "<p> </p>"); // 滚动条滚动到最低部 $("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height()); }; }); </script> </body> </html>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
此页面打开时发送了一个websocket请求,ws.do,会被springMVC拦截处理。连接建立之后每当收到新的消息会追加到当前文本的末尾并换行(p标签用来换行)。
6)控制日志的实时打印示例:PrintWriter out = response.getWriter(); MyWebSocketHandler.broadcast(new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson("访问test接口"))); out.println("访问test接口");1
2
3
每次返回给前端某些值的时候通过一个广播将该值传送到web页面。如果不想广播,只需要在程序中对log的session进行特别的标签,然后定向传送即可。
效果示意图:浏览器输入localhost:8080/projectName/log.html,然后访问localhost:8080/projectName/test,每次访问test接口,网页上实时显示tomcat输出的日志。需要完整代码留邮箱,看到就发送,发送的工程是一个基本的web工程,只集成spring websocket,本文的所有效果和引用都有。或者发邮件到smile326@qq.com提醒我。
4.备注:
本例中为方便消息的处理用到如下两个实体类(我也是沿用了别人教程代码):
Message.java:public class Message { //发送者 public Long from; //发送者名称 public String fromName; //接收者 public Long to; //发送的文本 public String text; //发送日期 public Date date; public Long getFrom() { return from; } public void setFrom(Long from) { this.from = from; } public Long getTo() { return to; } public void setTo(Long to) { this.to = to; } public String getText() { return text; } public void setText(String text) { this.text = text; } public String getFromName() { return fromName; } public void setFromName(String fromName) { this.fromName = fromName; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
user.java:public class User { private Long id; private String name; private String password; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
应大家需求,完成工程的代码放在了github上面啦!传上去的代码进一步完善了一下,把建立连接的时候上传参数的问题处理了一下;把存放session的容器换成了线程安全型的!欢迎大家在线讨论!
https://github.com/smile326/springWebsockeForTomcatLog
相关文章推荐
- Java用webSocket实现tomcat的日志实时输出到web页面
- Java用webSocket实现tomcat的日志实时输出到web页面
- Java用webSocket实现tomcat的日志实时输出到web页面
- Java用webSocket实现tomcat的日志实时输出到web页面
- Java用webSocket实现tomcat的日志实时输出到web页面
- 基于https实现webSocket通信实时在web页面输出日志(两个日志输出)
- 基于python的websocket开发,tomcat日志web页面实时打印监控案例
- 如何把tomcat的日志实时输出到web页面上
- JAVA Web快速开发部署(Javarebel实现真正高效的tomcat热部署)
- spring boot集成WebSocket实时输出日志到web页面
- Java用WebSocket + tail命令实现Web实时日志
- 基于Saltstatck实现页面实时显示tomcat启动日志(17)
- 基于Saltstatck实现页面实时显示tomcat启动日志(17)
- Java 使用Spring WebSocket 实现linux tailf 实时日志显示
- 【软件】我安装Tomcat5.5(Java Web开发服务器)的几点经验
- JAVA Web快速开发部署(Javarebel实现真正高效的tomcat热部署)
- python实现websocket服务器,可以在web实时显示远程服务器日志
- 稍微成型点的用WEBSOCKET实现的实时日志LOG输出
- java web开发中,jsp使用了frameset框架,如何实现整个页面跳转,并且同一个表单中可以提交两个action
- Java WEb后端WebSocket的Tomcat实现