lcpsky

导航

springboot2.0集成websocket发送日志

后台引入websocket

在pom.xml中引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
package com.plat.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.*;

import com.plat.common.Constant;

@Configuration
@EnableWebSocket
public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport {

   @Override
   public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
      // 注册一个Stomp的节点(endpoint),并指定使用SockJS协议。
      stompEndpointRegistry.addEndpoint(Constant.WEBSOCKETPATH).setAllowedOrigins("*").withSockJS();
   }

   @Override
   public void configureMessageBroker(MessageBrokerRegistry registry) {
      // 服务端发送消息给客户端的域,多个用逗号隔开
      registry.enableSimpleBroker(Constant.WEBSOCKETBROADCASTPATH, Constant.P2PPUSHBASEPATH);
      // 定义一对一推送的时候前缀
      registry.setUserDestinationPrefix(Constant.P2PPUSHBASEPATH);
      // 定义websoket前缀
      registry.setApplicationDestinationPrefixes(Constant.WEBSOCKETPATHPERFIX);
   }

}
/**
 * 
 */
package com.plat.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import com.plat.common.Constant;
import com.plat.common.WiselyResponse;

/**   
 * @ClassName:  WebSocketService   
 * @Description:    
 * @author: lcp
 * @date:   2019年12月4日 下午11:23:49   
 *     
 * @Copyright: 2019 www.ankept.com Inc. All rights reserved. 
 */
@Service
public class WebSocketService {
    @Autowired
    private SimpMessagingTemplate template;
 
    /**
     * 广播
     * 发给所有在线用户
     * @param msg
     */
    public void sendMsg(WiselyResponse msg) {
        template.convertAndSend(Constant.PRODUCERPATH, msg);
    }
 
    /**
     * 发送给指定用户
     * @param users
     * @param msg
     */
    public void send2Users(List<String> users, WiselyResponse msg) {
        users.forEach(userName -> {
            template.convertAndSendToUser(userName, Constant.P2PPUSHPATH, msg);
        });
    }
}
public class Constant {
   //webSocket相关配置
   //链接地址
   public static String WEBSOCKETPATHPERFIX = "/ws-push";
   public static String WEBSOCKETPATH = "/endpointWisely";
   //消息代理路径
   public static String WEBSOCKETBROADCASTPATH = "/topic";
   //前端发送给服务端请求地址
   public static final String FORETOSERVERPATH = "/welcome";
   //服务端生产地址,客户端订阅此地址以接收服务端生产的消息
   public static final String PRODUCERPATH = "/topic/getResponse";
   //点对点消息推送地址前缀
   public static final String P2PPUSHBASEPATH = "/user";
   //点对点消息推送地址后缀,最后的地址为/user/用户识别码/msg
   public static final String P2PPUSHPATH = "/msg";
   public static final String LOGCURRENT = "/logcur";
}
public class WiselyMessage {
   private String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}
public class WiselyResponse {
   private String responseMessage;
    
   public WiselyResponse(String responseMessage){
       this.responseMessage = responseMessage;
   }
    
   public String getResponseMessage() {
       return responseMessage;
   }
    
   public void setResponseMessage(String responseMessage) {
       this.responseMessage = responseMessage;
   }
}

编写服务端接口,向客户端推送日志

@Controller
public class WebSocketController {
	@Value("${logfile-path}")
	private String path;

	@Resource
	WebSocketService webSocketService;
	final DateTimeFormatter ptn = DateTimeFormatter.ofPattern(DateUtils._sdfPattern);

	/**
	 * 	@MessageMapping和@RequestMapping功能类似,用于设置URL映射地址,浏览器向服务器发起请求,需要通过该地址。
	 * 如果服务器接受到了消息,就会对订阅了@SendTo括号中的地址传送消息。
	 * @throws Exception
	 */
	
	@MessageMapping(Constant.LOGCURRENT)
	@SendTo(Constant.PRODUCERPATH)
	public void say() throws Exception {
		String log = logCreator();
		WiselyResponse msg = new WiselyResponse(log);
		if (!log.isEmpty()) {
			webSocketService.sendMsg(msg);
		}else {
			webSocketService.sendMsg(new WiselyResponse("暂无日志"));
		}
	}

private String logCreator() {
		String res = "";
		BufferedReader reader = null;
		try {
			// 日志文件路径,获取最新的
			String filePath = path;

			// 字符流
			reader = new BufferedReader(new FileReader(filePath));
			Object[] lines = reader.lines().toArray();

			// 只取从上次之后产生的日志
			LocalDateTime timeStart = LocalDateTime.now().minusMinutes(10);
			for (int i=0;i<lines.length;i++) {
				String record = (String) lines[i];
				LocalDateTime time = containTime(record);
				if (time!=null && time.isAfter(timeStart)) {
					Object[] copyOfRange = Arrays.copyOfRange(lines, i, lines.length);
					res = Joiner.on("<br>").join(copyOfRange);
					break;	
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(reader!=null){
					reader.close();
				}
			} catch (IOException ignored) {
			}
		}
		return res;
	}
	private LocalDateTime containTime(String record) {
		LocalDateTime res = null;
		//匹配时间格式2019-10-11 15:03:16
		String regex = "^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{1,2}:\\d{1,2}";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(record);
		if (matcher.find()) {
			res = LocalDateTime.parse(matcher.group(), ptn);
		}
		return res;
	}
}

前端页面

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>日志</title>
</head>

<body onload="disconnect()">
    <noscript><h2 style="color: #ff0000">貌似你的浏览器不支持websocket</h2>          </noscript>
    <div>
        <div>
            <button id="connect" onclick="connect();">连接日志服务器</button>
            <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
        </div>
        <div id="conversationDiv">
<!--             <label>输入你的名字</label><input type="text" id="name" />
 -->            <button id="sendName" onclick="sendName();">获取日志/刷新</button>
            <p id="response"></p>
            <p id="response1"></p>
        </div>
    </div>
    <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js">
    </script>
    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript">
        var stompClient = null;
        //此值有服务端传递给前端,实现方式没有要求
        var userId = "123";

        function setConnected(connected) {
            document.getElementById('connect').disabled = connected;
            document.getElementById('disconnect').disabled = !connected;
            document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
            $('#response').html();
        }

        function connect() {
            var socket = new SockJS('/endpointWisely'); //1连接SockJS的endpoint是“endpointWisely”,与后台代码中注册的endpoint要一样。
            stompClient = Stomp.over(socket); //2创建STOMP协议的webSocket客户端。
            let headers = {
                withCredentials: false
            };
            stompClient.connect(headers, function(frame) { //3连接webSocket的服务端。
                setConnected(true);
                console.log('开始进行连接Connected: ' + frame);
                //4通过stompClient.subscribe()订阅服务器的目标是'/topic/getResponse'发送过来的地址,与@SendTo中的地址对应。
                stompClient.subscribe('/topic/getResponse', function(respnose) {
                    showResponse(JSON.parse(respnose.body).responseMessage);
                });
                //4通过stompClient.subscribe()订阅服务器的目标是'/user/' + userId + '/msg'接收一对一的推送消息,其中userId由服务端传递过来,用于表示唯一的用户,通过此值将消息精确推送给一个用户
                //stompClient.subscribe('/user/' + userId + '/msg', function(respnose) {
                //    console.log(respnose);
                //    showResponse1(JSON.parse(respnose.body).responseMessage);
                //});
            });
        }


        function disconnect() {
            if (stompClient != null) {
                stompClient.disconnect();
            }
            setConnected(false);
            console.log("Disconnected");
        }

        function sendName() {
            var name = $('#name').val();
            //通过stompClient.send()向地址为"/welcome"的服务器地址发起请求,与@MessageMapping里的地址对应。因为我们配置了registry.setApplicationDestinationPrefixes(Constant.WEBSOCKETPATHPERFIX);所以需要增加前缀/ws-push/
            stompClient.send("/ws-push/logcur", {}, JSON.stringify({
                'name': name
            }));
        }

        function showResponse(message) {
            var response = $("#response");
            response.html(message);
        }

        function showResponse1(message) {
            var response = $("#response1");
            response.html(message);
        }
    </script>
</body>

</html>

测试

在这里插入图片描述

posted on 2021-07-21 21:14  lcpsky  阅读(74)  评论(0编辑  收藏  举报