东台网站设计,wordpress系列教程,wordpress 充值积分,公司简介制作最近在做一个公司的日志组件时有一个问题难住了我。今天问题终于解决了。由于在解决问题中#xff0c;在网上也查了很多资料都没有一个完整的实例可以参考。所以本着无私分享的目的记录一下完整的解决过程和实例。 需求#xff1a;做一个统一日志系统可以查看日志列表和一个可… 最近在做一个公司的日志组件时有一个问题难住了我。今天问题终于解决了。由于在解决问题中在网上也查了很多资料都没有一个完整的实例可以参考。所以本着无私分享的目的记录一下完整的解决过程和实例。 需求做一个统一日志系统可以查看日志列表和一个可以订阅最新日志的页面。通过提供一个封装好日志记录方法的sdk文件将日志统一收集。 通过上面的需求进行我们使用RabbitMongodb来实现系统。 使用#封装一个大家都会这里就不说了。#连接Rabbit示例代码也是一堆堆的也没什么好说的。下面重点说一下网页端如何使用JS去订阅Rabbit收到的最新日志信息。 后端都是使用Rabbit的协议而前端要求在网页HTML上显示数据。我们选择了使用协议从Rabbit中订阅数据。 具体步骤
、先准备好相关JS库。有一个叫browserMqtt.js看名字就知道是为浏览器提供的JS库。还有一个封装了操作MQ的JS库 mqfactory.js。最后还要一个jquery.js文件。这样工具就准备好了。JS文件下载
、端代码。
script typetext/javascript src~/js/MqJs/jquery.js/script
script typetext/javascript src~/js/MqJs/browserMqtt.min.js/script
script typetext/javascript src~/js/MqJs/mqfactory.js/script
bodydivlableHost: /lableinput idtxtHost placeholder192.168.1.88 value10.1.0.7 /br /lablePort: /lableinput idtxtPort placeholder15675 value15675 /br /labelUserName: /labelinput idtxtUserName placeholderusername valueadmin /br /labelPassword: /labelinput idtxtPassword placeholderpassword valueadmin /br /labelProtocol: /labelinput idtxtProtocol placeholderws valuews /br /input idbtnConnect typebutton valueConnect RabbitMQ //divdivinput idbtnSubscribe typebutton valueSubscribe /input idbtnPublish typebutton valuePublish /br /input idbtnSSHuanjing typebutton valueSubscribe Huanjing /input idhdnIsSubscribed typehidden value /input idbtnPubHuanjing typebutton valuePublish Huanjingbr /路由:input idbtnRoutingKey typetext valueDcon/Logs/Clientbr /input idtxtMessage typetext placeholderPlease enter message //divdivlabellog:/labelbr /ul idlstLog/ulinput idbtnClearLog typebutton valueClear Log //div
/body
script typetext/javascript$(function () {var mqclient;//var routingKey Dcon.Logs.ServerWebShow;var message;$(#btnSubscribe).attr(disabled, disabled);$(#btnPublish).attr(disabled, disabled);$(#btnSSHuanjing).attr(disabled, disabled);$(#btnPubHuanjing).attr(disabled, disabled);$(#btnConnect).click(function () {var mqttOpts {host: (() $(#txtHost).val())(),port: (() $(#txtPort).val())(),username: (() $(#txtUserName).val())(),password: (() $(#txtPassword).val())(),//transformWsUrl方法用于在浏览器中使用MQTT的场景默认情况下,MQTT自动生成的url为ws://ip:port形式//然而服务器要求的格式是ws://ip:port/ws所以MQTT提供了此接口用于在生成url时自定义url格式transformWsUrl: (url, opts, client) { return opts.protocol opts.protocol ws ? url ws : url; },clientId: (() { return mqttjs_ Math.random().toString(16).substr(2, 8); })()};var biz {huanjing: function (handler, isOn) {if (isOn ! false) {this.ss(this.topics.huanjing, handler);} else {this.sus(this.topics.huanjing, handler);}},topics: {huanjing: /hyj/huanjing/monitor}};//系统初始化时注入连接选项mqfactory.inject(mqttOpts, biz);//创建mqclient单例 mqclient mqfactory.create();//注册mqclient的连接成功事件mqclient.on(connect, mqconnected);});$(#btnSubscribe).click(function () {if ($(this).val() Subscribe) {//订阅成功后仅注册一次事件(要考虑每次注册事件时事件处理器调用的次数如果仅用一次就用once方法)//routingKey $(#btnRoutingKey).val();mqclient.once(onss, mqSubscribeSuccess);//简单订阅mqclient.ss($(#btnRoutingKey).val());} else {mqclient.once(onsus, mqUnsubscribeSuccess)mqclient.sus($(#btnRoutingKey).val());}});$(#btnPublish).click(function () {var msg $(#txtMessage).val().length 0 ? $(#txtMessage).val() : guid();if (message msg) {msg guid();}message msg;$(#txtMessage).val(message);//发送消息mqclient.pub($(#btnRoutingKey).val(), message);$(#lstLog).append(liSend Message: message /li);});$(#btnSSHuanjing).click(function () {if ($(this).val() Subscribe Huanjing) {mqclient.once(onss, mqHJSubscribeSuccess);mqclient.huanjing(onHuanjingMessageArrived);} else {mqclient.once(onsus, mqHJUnsubscribeSuccess);mqclient.huanjing(onHuanjingMessageArrived, false);}});$(#btnPubHuanjing).click(function () {var msg $(#txtMessage).val().length 0 ? $(#txtMessage).val() : guid();if (message msg) {msg guid();}message msg;$(#txtMessage).val(message);//发送消息mqclient.pub(mqclient.topics.huanjing, message);$(#lstLog).append(liSend Huanjing Message: message /li);});$(#btnClearLog).click(function () {$(#lstLog).empty();});function mqconnected() {//alert(mqconnected);$(#btnSubscribe).removeAttr(disabled);$(#btnPublish).removeAttr(disabled);$(#btnSSHuanjing).removeAttr(disabled);$(#btnPubHuanjing).removeAttr(disabled);$(#lstLog).append(limqclient connected/li);}function mqSubscribeSuccess() {//订阅成功就注册接受消息的方法此处要接收多次因此使用了onmqclient.on($(#btnRoutingKey).val(), onMessageArrived);$(#btnSubscribe).val(Unsubscribe);$(#lstLog).append(liSubscribe successful. $(#btnRoutingKey).val()/li);}function mqUnsubscribeSuccess() {//注销订阅所以将事件处理器解除绑定mqclient.off($(#btnRoutingKey).val(), onMessageArrived);$(#btnSubscribe).val(Subscribe);$(#lstLog).append(liUnsubscribe successful/li);}function mqHJSubscribeSuccess() {$(#btnSSHuanjing).val(Unsubscribe Huanjing);$(#lstLog).append(liHanjing Subscribe successful/li);}function mqHJUnsubscribeSuccess() {$(#btnSSHuanjing).val(Subscribe Huanjing);$(#lstLog).append(liHuanjing Unsubscribe successful/li);}function onMessageArrived(message) {$(#lstLog).append(liReceive message: new Date().toString() message.toString() /li);}function onHuanjingMessageArrived(message) {$(#lstLog).append(liReceive Huanjing message: new Date().toString() message.toString() /li);}function guid() {function s4() {return Math.floor((1 Math.random()) * 0x10000).toString(16).substring(1);}return s4() s4() - s4() - s4() - s4() - s4() s4() s4();}});
/script
.后端代码
.客户端sdk代码
/// summary/// 写日志/// /summary/// param namemodel/parampublic static void Write(LogModel model){//判断写入的日志级别if (model ! null model.LogLevel LogLevel){try{var mqMsg new MqMessage(){MessageBody JSON.Serialize(model),MessageRouter SystemConst.RoutingKeyTopic.LogTopic_Producer};//MQHelper.Instance.ProducerMessage_Fanout(mqMsg);MQHelper.Instance.ProducerMessage_Topic(mqMsg);}catch (Exception ex){var errorLog string.Format(Ip:{0},LogHelper.Write方法异常,{1}, IpHelper.LocalHostIp, ex.Message);//MQHelper.Instance.ProducerMessage_Fanout(new MqMessage() { MessageBody errorLog });MQHelper.Instance.ProducerMessage_Topic(new MqMessage() { MessageBody errorLog });}}}
.后端代码
#region 主题 交换机/// summary/// 生产者 客户端调用/// /summary/// param namemsg/parampublic void ProducerMessage_Topic(MqMessage msg){try{using (var connection factory.CreateConnection()){using (var channel connection.CreateModel()){var body Encoding.UTF8.GetBytes(msg.MessageBody);channel.BasicPublish(exchange: SystemConst.MqName_LogMq_TopicDefault,routingKey: msg.MessageRouter,basicProperties: null,body: body);Console.WriteLine( [x] Sent {0}, msg.MessageBody);}}}catch (Exception ex){var exMsg ex.Message;}}/// summary/// 消费者 服务器接收并写入数据库/// 消费方法无法通过参数传入/// EventHandlerBasicDeliverEventArgs received/// /summarypublic void ConsumeMessage_Topic(params string[] routingKeys){if (routingKeys null || routingKeys.Length 0){throw new Exception(请指定接收路由);}using (var connection factory.CreateConnection()){using (var channel connection.CreateModel()){var queueName channel.QueueDeclare().QueueName;//获得已经生成的随机队列名//对列与交换机绑定foreach (var rKey in routingKeys){channel.QueueBind(queue: queueName,exchange: SystemConst.MqName_LogMq_TopicDefault,routingKey: rKey);}var consumer new EventingBasicConsumer(channel);//绑定消费方法consumer.Received consomer_Received_Topic;//绑定消费者channel.BasicConsume(queue: queueName,autoAck: true,consumer: consumer);Console.WriteLine(日志订阅服务启动成功.);Console.WriteLine( Press [enter] to exit.);Console.ReadLine();}}}/// summary/// 接收通知服务异步的推送/// /summary/// param namesender/param/// param namee/paramvoid consomer_Received_Topic(object sender, BasicDeliverEventArgs e){var body e.Body;var message Encoding.UTF8.GetString(body);Console.WriteLine( [x] {0}, message);
//这里可以增加写入数据库的代码}#endregion
.路由
/// summary/// 主题路由/// /summarypublic class RoutingKeyTopic{/// summary/// 生产者/// /summarypublic const string LogTopic_Producer Dcon.Logs.Client;/// summary/// 消息者_日志服务_保存日志/// /summarypublic const string LogTopic_Consume_Server_SaveDB Dcon.Logs.*;/// summary/// 消息者_日志服务_Web显示日志/// /summarypublic const string LogTopic_Consume_Server_WebShow Dcon.Logs#;//.Logs.Client;/// summary/// 消息者_日志服务_Web显示日志/// /summarypublic const string LogTopic_Consume_Server_WebShow_T *.Logs.Client;//.Logs.Client;/// summary/// 消息者_日志服务_ # 接收所有/// /summarypublic const string LogTopic_Consume_Server_All #;//.Logs.Client;}}
注意点
、的路由是以 / 来分割的。在Rabbit中会被转义成 . 如示例中的路由Dcon/Logs/Client会被转换成 Dcon.Logs.Client
、网页端接收时的路由要和发送端的路由一至。也就是说 后端用 Dcon.Logs.Client 来推数据前端就要使用 Dcon/Logs/Client来接收数据。
、路由不支持通配符.
、由于的库没有提供Topic交换机与路由绑定功能。所以前端接收时 不能设置订阅主题交换机名称。如果要和amqp交互只能使用amqp的默认主题交换机名称 amq.topic 运行效果图