Swing应用开发实战系列之五:后台日志信息前台监控器

作为一个程序设计人员,我们深知日志的重要性,对于日志的监控,我们通常不外乎采用以下两种方式:日志文件方式和后台打印方式,常规情况下,这两种日志监控方式完全可以满足我们对日志监控的需要。但是,当我们用Swing进行前台开发时,常常想能不能把后台服务运行日志实时地显示在前台窗口中,或者只是将某类我们比较关心的日志信息(譬如异常日志等)实时动态地显示在前台窗口中,这样方便我们及时监控和处理。这个设想我们称之为“后台日志信息前台监控器”。

设计这样一个“后台日志信息前台监控器”,有两个难点,第一个是,当我们捕捉到后台日志信息时,如何将日志信息传递给前台监控器,实现实时传递。第二个是,当前台监控器收到日志信息后,如何实时显示。总结起来,就是一个“实时”的问题:实时传递和显示日志信息。

对于如何将后台日志信息实时传递到前台进行监控显示,我们采用了自定义事件机制,通过事件触发机制,监控日志内容的变更。思路是这样的,在LogMonitor类中,用StringBuilder实例化一个变量logs,用来存储日志信息,通过addLog和clearLogs方法来添加和删除日志信息,并在这两个方法体内监控日志信息的变更,当日志信息发生变更时,触发事件变更事件,最后在此事件内实时刷新前台监控区域。

  • 日志信息变更事件类
/**
 * Description:日志信息事件<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 *
 * @author shangbingbing 2015-01-01编写
 * @version 1.0
 */
public class LogChangedEvent extends java.util.EventObject {
    private static final long serialVersionUID = 7573194493258326711L;
    public LogChangedEvent(Object source) {
        super(source);
    }
}
  • 日志信息变更监听器类
/**
 * Description:日志信息变更监听器<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 *
 * @author shangbingbing 2015-01-01编写
 * @version 1.0
 */
public class LogChangedListener implements java.util.EventListener {
    public void EventActivated(LogChangedEvent me) {

    }
}
  • 日志信息监听器类
/**
 * Description:日志信息监听器类<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-01-01编写
 * @version 1.0
 */
public class LogMonitor implements Serializable {
    private static final long serialVersionUID = 1L;
    private static StringBuilder logs = new StringBuilder();
    /**
     * 获取日志信息
     * @return
     */
    public static StringBuilder getLogs() {
        return logs;
    }
    /**
     * 新增日志信息
     * @param log
     */
    public static void addLog(String log) {
        if(StringUtils.isBlank(log)) {
            logs.append("\r\n");
        } else {
            log = String.format("%s    %s\r\n", new Date().toString(), log);
            logs.append(log);
        }
        activateLogChangedEvent();
    }
    /**
     * 清除日志信息
     */
    public static void clearLogs() {
        logs = new StringBuilder();
        activateLogChangedEvent();
    }
    private static Vector<LogChangedListener> vectorListeners = new Vector<LogChangedListener>();
    public static synchronized void addLogChangedListener(LogChangedListener listener) {
        vectorListeners.addElement(listener);
    }
    public static synchronized void removeLogChangedListener(LogChangedListener listener) {
        vectorListeners.removeElement(listener);
    }
    public static void activateLogChangedEvent() {
        Vector<LogChangedListener> tempVector = null;
        LogChangedEvent e = new LogChangedEvent(LogMonitor.class);
        synchronized(LogMonitor.class) {
            tempVector = (Vector<LogChangedListener>)vectorListeners.clone();
            for(int i=0;i<tempVector.size();i++) {
                LogChangedListener listener = tempVector.elementAt(i);
                listener.EventActivated(e);
            }
        }
    }
}
  • 日志信息前台监控窗口
import javax.swing.JDialog;
import javax.swing.UIManager;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
 * Description:日志信息监听窗口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-01-01编写
 * @version 1.0
 */
public class DialogLogMonitor extends JDialog {
    private static final long serialVersionUID = 1L;
    private JTextArea txtLogInfo;
    public static void main(String[] args) {
        try {
            //设置系统观感器
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            DialogLogMonitor dialog = new DialogLogMonitor();
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 日志信息变更监听处理(关键点)
     */
    private void init() {
        LogMonitor.addLogChangedListener(new LogChangedListener() {
            @Override
            public void EventActivated(LogChangedEvent me) {
                txtLogInfo.setText(LogMonitor.getLogs().toString());
                txtLogInfo.setCaretPosition(txtLogInfo.getText().length());
                txtLogInfo.paintImmediately(txtLogInfo.getBounds());
            }
        });
    }
    public DialogLogMonitor() {
        setResizable(false);
        setTitle("\u540E\u53F0\u65E5\u5FD7\u76D1\u63A7\u5668");
        setBounds(100, 100, 439, 274);
        JScrollPane scrollPane = new JScrollPane();
        GroupLayout groupLayout = new GroupLayout(getContentPane());
        groupLayout.setHorizontalGroup(
            groupLayout.createParallelGroup(Alignment.LEADING)
                .addGroup(groupLayout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(scrollPane)
                    .addContainerGap())
        );
        groupLayout.setVerticalGroup(
            groupLayout.createParallelGroup(Alignment.LEADING)
                .addGroup(groupLayout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 230, Short.MAX_VALUE)
                    .addContainerGap())
        );
        txtLogInfo = new JTextArea();
        txtLogInfo.setEditable(false);
        txtLogInfo.setLineWrap(true);
        scrollPane.setViewportView(txtLogInfo);
        getContentPane().setLayout(groupLayout);
        this.init();
    }
}
  • 后台日志模拟生成窗口

我们设计了一个后台日志模拟生成窗口,来测试日志信息的监控效果。窗口源代码如下:

import javax.swing.JDialog;
import javax.swing.UIManager;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/**
 * Description:后台日志信息模拟生成窗口<br>
 * Copyright: Copyright (c) 2015<br>
 * Company: 河南电力科学研究院智能电网所<br>
 * @author shangbingbing 2015-01-01编写
 * @version 1.0
 */
public class DialogLogGenerator extends JDialog {
    private static final long serialVersionUID = 1L;
    private JTextArea txtLogInfo;
    public static void main(String[] args) {
        try {
            //设置系统观感器
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            DialogLogGenerator dialog = new DialogLogGenerator();
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.setVisible(true);

            DialogLogMonitor dialogLogMonitor = new DialogLogMonitor();
            dialogLogMonitor.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialogLogMonitor.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void generatorLog() {
        LogMonitor.addLog(this.txtLogInfo.getText());
        this.txtLogInfo.setText("");
    }
    public DialogLogGenerator() {
        setResizable(false);
    setTitle("\u540E\u53F0\u65E5\u5FD7\u6A21\u62DF\u751F\u6210\u6D4B\u8BD5\u7A97\u53E3");
        setBounds(100, 100, 439, 278);
        JLabel lblNewLabel = new JLabel("\u8BF7\u8F93\u5165\u6A21\u62DF\u65E5\u5FD7\u4FE1\u606F\uFF1A");
        JScrollPane scrollPane = new JScrollPane();
        JButton btnCreateLog = new JButton("\u4F20\u9012\u6A21\u62DF\u65E5\u5FD7");
        btnCreateLog.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                generatorLog();
            }
        });
        GroupLayout groupLayout = new GroupLayout(getContentPane());
        groupLayout.setHorizontalGroup(
            groupLayout.createParallelGroup(Alignment.LEADING)
                .addGroup(groupLayout.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
                        .addGroup(groupLayout.createSequentialGroup()
                            .addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE)
                            .addContainerGap())
                        .addGroup(groupLayout.createSequentialGroup()
                            .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
                                .addComponent(btnCreateLog, GroupLayout.PREFERRED_SIZE, 131, GroupLayout.PREFERRED_SIZE)
                                .addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE, 170, GroupLayout.PREFERRED_SIZE))
                            .addGap(253))))
        );
        groupLayout.setVerticalGroup(
            groupLayout.createParallelGroup(Alignment.LEADING)
                .addGroup(groupLayout.createSequentialGroup()
                    .addGap(18)
                    .addComponent(lblNewLabel)
                    .addPreferredGap(ComponentPlacement.UNRELATED)
                    .addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 131, GroupLayout.PREFERRED_SIZE)
                    .addGap(18)
                    .addComponent(btnCreateLog, GroupLayout.PREFERRED_SIZE, 41, GroupLayout.PREFERRED_SIZE)
                    .addContainerGap(17, Short.MAX_VALUE))
        );
        txtLogInfo = new JTextArea();
        scrollPane.setViewportView(txtLogInfo);
        getContentPane().setLayout(groupLayout);
    }
}
  • 运行测试

启动运行DialogLogGenerator窗口,会同时显示DialogLogMonitor窗口,在日志模拟窗口输入一些日志信息,然后点击“传递模拟日志”按钮,你将可以在DialogLogMonitor监控区域看到模拟的日志信息。运行效果图如下所示:

运行程序打包下载 hnepri-log-monitor.jar


作者:商兵兵

单位:河南省电力科学研究院智能电网所

QQ:52190634

主页:http://www.cnblogs.com/shangbingbing

空间:http://shangbingbing.qzone.qq.com

时间: 2024-10-07 22:26:07

Swing应用开发实战系列之五:后台日志信息前台监控器的相关文章

Swing应用开发实战系列之三:动态信息提示窗口

  这里所说的"动态信息提示窗口"可不同于JOptionPane中的Message窗口和Confirm窗口,它们都是静态的模态的,更重要的是线程阻塞的,迫使你必须选择某个动作才能继续执行.我们接下来要分享的这个动态信息提示窗口,重点就是信息是动态的且实时刷新显示的,我们设想这样一个应用场景,当我们要向数据库中写入10000条记录时,这肯定是一个颇为耗时的工作,很有必要在前台界面中实时地告知用户数据写入进度,并在写入完成后,自动隐藏提示窗口. 首先,设计信息提示窗体,调整到适当大小,并将

Swing应用开发实战系列之一:自定义JdbcTemplate

  笔者本人真正意义上接触编程开发是在2004年,最早用的就是VB,然后是Delphi等,后来转到.Net,中间断断续续还用过PowerBuilder等,无一例外,所研发设计的项目或系统都是WinForm应用程序,基于C/S模式的窗口应用程序开发那个时候还是正道,而Web开发还没有现在这么红火,技术也没有现在这么多姿多彩. 后来,B/S技术日渐成熟起来,jquery.node.js.flex.spring.structs.hibernate等技术框架相继涌现出来,进行Web开发的门槛降了下来,开

Swing应用开发实战系列之二:设计日期选择面板窗口

  Swing本身没有提供什么华丽丽的日期时间选择控件,所以笔者就在网上搜了个第三方的jar包jdatepicker-1.3.2.jar,基于此设计了个很轻量的日期选择面板,很简单的.效果图如下所示: 代码如下: import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.SimpleDateFormat; import java.util.Date; import javax

SCCM2012 R2实战系列之五:发现方法

打开SCCM2012的控制台 点击左侧栏的"管理"选项,然后展开"层次结构配置",点击"发现方法"来配置客户端发现. 勾选"启用Active Directory林发现"."发现Active Directory站点边界时自动创建这些站点边界"和"发现IP子网时自动创建这些子网的IP地址范围边界",并设置运行间隔时间,然后点击"应用".(我这里是实验环境,为了更快的看到效

WCF 开发实战系列 (一)

也许有读者会说,为什么要谈 WCF?近期不是 Web API 比较热门?在这个手机.Devices 当道的现在,究竟有什么地方会需要使用到 WCF 呢? 的确,现在访间你能找到的课程,或者您可能参与某项目的实践 (网页应用程序.手机 APP 也好),你需要的通常也都是提供 Services 层,而这个 Services 层通常也就是 Web API.那么,难道 WCF 就无用武之地?其实也不是,看什么情况用什么技术,有一些地方是 Web API 无法做到的 前言 也许有读者会说,为什么要谈 WC

大数据开发实战系列之电信客服(1)

大数据实战开发系列,以实战为主,辅以一些基础知识,关于电信客服,在网上也有很多的资料,这里我自然会去参考网上的资料,程序的整体设计是在今天开始的,老夫尽量在本周末钱结束这个电信客服的程序编写.因为我也是一个学习者,所以在程序编写过程中难免会存在问题,有问题还请大家指出,有则改之,无则加勉.大家共同进步.本教程适合接触大数据开发不久或者还没接触大数据开发,或者小萌新.老鸟就多提意见吧,我改. 博客原文地址:大数据开发实战系列之电信客服(1) 项目背景 关于项目背景,我就照搬网上的了.通信运营商每时

跨平台开发实战系列篇-开篇

本系列文章将带着你从React Native入门到精通React Native开发,包括大型电商项目实战.大型新闻项目实战(一套代码运行在iOS平台和Android平台).持续更新中...... 一.前言 React Native于F8大会开源,在短短不到一年的时间里,它成为手机端必不可少的开发模式之一. 它充分利用了Facebook现有的业务轮子, 其核心设计理念:既拥有Native的用户体验.又保留React的开发效率, 也就是"learn once,write everywhere&quo

程序员入门必备的大数据开发实战系列丛书

想要入行大数据却不知从哪里开始?作为入行十年的码农为大家推荐一套"一站式实战型大数据应用开发学习指导"丛书,帮助读者踏上由开发入门到大数据实战的"互联网+大数据"开发之旅! 此套丛书以实用性.案例丰富见长.由国内知名的IT教育机构课工场创始人肖睿主编,人民邮电出版社出版.编撰此书时为满足企业对人才的技能需求,课工场大数据开发教研团队,通过对数百位BAT一线技术专家进行访谈.上千家企业人力资源情况进行调研.上万上企业招聘岗位进行需求分析,在此基础上,整合了大量案例说明

在线客服系统 开发实战系列(一:需求分析及技术方案初步选型)

在这个系列的文章里,我将尝试一步一步开发一套功能完备的在线客服系统,并最终将其开源在 Git 上,欢迎关注. 鉴于水平限制,难免有所疏漏,欢迎批评指正. 文章将分为几个部分 一.需求分析及技术方案初步选型 二.技术方案选型,验证 三.底层框架设计,开发 四.服务器设计开发 五.客户端设计开发 六.Web端设计开发 在这个系列的文章中,您将了解并学习到以下技术知识: MSMQ.YUI.WebSocket.WinForms 如果这些技术对您有用,还请您 推荐 一下本文章,谢谢! 首先我们大概看看什么