频道栏目
首页 > 程序开发 > 软件开发 > Java > 正文
Java用webSocket实现tomcat的日志实时输出到web页面
2016-08-20 09:30:07      个评论    来源:旧时光她是个美人  
收藏   我要投稿

进入正题

配置websocket,大部分web项目都会用到spring框架吧,所有这里贴spring websocket的配置,不用spring的请自行去掉spring部分。spring使用4.0以上,tomcat使用7.0.68版本。

1)pom.xml中包的引入:

        
            com.fasterxml.jackson.core
            jackson-annotations
            2.3.0
        
        
            com.fasterxml.jackson.core
            jackson-core
            2.3.1
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.3.3
        
        
            org.springframework
            spring-messaging
            4.0.5.RELEASE
        
        
            org.springframework
            spring-websocket
            4.0.5.RELEASE
        
        
            org.springframework
            spring-webmvc
            4.0.5.RELEASE
        
        
            com.google.code.gson
            gson
            2.3.1
        
        
            javax.servlet
            javax.servlet-api
            3.1.0
            provided
        

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

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 userSocketSessionMap;
    static {
        userSocketSessionMap = new HashMap();
    }
    /**
     * 建立连接后
     */
    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> it = userSocketSessionMap
                .entrySet().iterator();
        LOG.warn("======消息传输错误======");
        // 移除Socket会话
        while (it.hasNext()) {
            Entry 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> it = userSocketSessionMap
                .entrySet().iterator();
        // 移除Socket会话
        LOG.warn("======关闭连接======");
        while (it.hasNext()) {
            Entry 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> it = userSocketSessionMap
                .entrySet().iterator();
        LOG.warn("======群发======");
        // 多线程群发
        while (it.hasNext()) {
            final Entry 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);
        }
    }
}  

3)web.xml中配置spring和springMVC,因为借助与springMVC来拦截处理websocket请求,如果用其他MVC框架,请自行替换。不想换也可以用springMVC,侵入性很低,并且本来就可以多种MVC共存。


        contextConfigLocation
        
            /WEB-INF/classes/applicationContext.xml
        
    
    
        SpringMVC
        org.springframework.web.servlet.DispatcherServlet
        
            contextConfigLocation
            /WEB-INF/classes/applicationContext.xml
        
        1
    
    
        SpringMVC
        *.do
    

注意web.xml的头部:


4)spring的xml文件中对websocket的配置:


    
    
        
        
            
        
    

    
    
    

注意spring的xml的头部:


5)日志接收页面:




<script src="//cdn.bootcss.com/jquery/2.1.4/jquery.js"></script>

 

此页面打开时发送了一个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接口");

每次返回给前端某些值的时候通过一个广播将该值传送到web页面。如果不想广播,只需要在程序中对log的session进行特别的标签,然后定向传送即可。

效果示意图:浏览器输入localhost:8080/projectName/log.html,然后访问localhost:8080/projectName/test,每次访问test接口,网页上实时显示tomcat输出的日志。
这里写图片描述

4.备注:

需要完整代码留邮箱,看到就发送,发送的工程是一个基本的web工程,只集成spring websocket,本文的所有效果和引用都有。或者发邮件到smile326@qq.com提醒我。
本例中为方便消息的处理用到如下两个实体类(我也是沿用了别人教程代码):
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;
    }

}

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

}
点击复制链接 与好友分享!回本站首页
相关TAG标签 实时 页面 日志
上一篇:【JAVA语言程序设计基础篇】--事件驱动程序设计--鼠标事件
下一篇:SpringMVC 视图解析
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站