From a85d8faf4db0a1f92f10f9c8f642afcdb78eb627 Mon Sep 17 00:00:00 2001 From: yunnysunny Date: Sat, 15 Sep 2012 22:59:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=98=BE=E7=A4=BAsq?= =?UTF-8?q?l=E8=AF=AD=E5=8F=A5=E8=AF=A6=E7=BB=86=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../druid/support/jconsole/DruidPanel.java | 98 ++---- .../druid/support/jconsole/DruidSQLPanel.java | 2 +- .../support/jconsole/DruidSqlDetailFrame.java | 313 ++++++++++++++++++ .../jconsole/util/TableDataProcessor.java | 69 +++- 4 files changed, 406 insertions(+), 76 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/support/jconsole/DruidSqlDetailFrame.java diff --git a/src/main/java/com/alibaba/druid/support/jconsole/DruidPanel.java b/src/main/java/com/alibaba/druid/support/jconsole/DruidPanel.java index a34ad8561b..945fd3eae5 100644 --- a/src/main/java/com/alibaba/druid/support/jconsole/DruidPanel.java +++ b/src/main/java/com/alibaba/druid/support/jconsole/DruidPanel.java @@ -20,11 +20,8 @@ import java.awt.event.ComponentListener; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; import javax.management.MBeanServerConnection; -import javax.management.ObjectName; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; @@ -32,9 +29,8 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.border.TitledBorder; -import com.alibaba.druid.stat.DruidStatService; import com.alibaba.druid.support.jconsole.model.DruidTableModel; -import com.alibaba.druid.support.json.JSONUtils; +import com.alibaba.druid.support.jconsole.util.TableDataProcessor; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; import com.sun.tools.jconsole.JConsoleContext; @@ -46,34 +42,31 @@ import com.sun.tools.jconsole.JConsoleContext; */ public abstract class DruidPanel extends JPanel { - private static final long serialVersionUID = 1L; - /** 成功的返回码 */ - protected static final int RESP_SUCCESS_RESULT = 1; - /** 返回码在json中的键名 */ - protected static final String RESP_JSON_RESULT_KEY = "ResultCode"; - /** 内容在json中的键名 */ - protected static final String RESP_JSON_CONTENT_KEY = "Content"; + private static final long serialVersionUID = 1L; + /** 默认面板刷新的间隔时间 */ - protected static final long DEFAULT_ACTIVE_TIME = 5 * 60 * 1000; + protected static final long DEFAULT_ACTIVE_TIME = 5 * 60 * 1000; /** 版权信息字符串 */ - private static final String COPYRIGHT_STRING = "powered by yunnysunny"; + private static final String COPYRIGHT_STRING = "powered by yunnysunny"; /** 滚动条面板 */ - protected JScrollPane scrollPane; + protected JScrollPane scrollPane; /** 表格模板 */ - protected DruidTableModel tableModel; + protected DruidTableModel tableModel; /** 表格 */ - protected JTable table; + protected JTable table; /** 版权面板 */ - protected JPanel copyrightPanel; + protected JPanel copyrightPanel; /** json请求的地址 */ - protected String url; + protected String url; /** 界面刷新的间隔时间,单位为毫秒. */ - protected long activeTime; + protected long activeTime; /** 上次刷新的时间 */ - protected long lastRefreshTime; - private final static Log LOG = LogFactory.getLog(DruidPanel.class); + protected long lastRefreshTime; + /** 与界面管理的MBeanServerConnection对象 */ + protected MBeanServerConnection conn; + private final static Log LOG = LogFactory.getLog(DruidPanel.class); /** * 根据传入的刷新时间间隔来初始化. @@ -91,53 +84,7 @@ public abstract class DruidPanel extends JPanel { activeTime = DEFAULT_ACTIVE_TIME; } - /** - * 解析调用service后得到JSON数据 - * - * @param respData 获取到的json对象 - * @return 返回解析后的数据 - */ - @SuppressWarnings("unchecked") - protected ArrayList> parseData(Object respData) { - ArrayList> data = null; - if (respData instanceof Map) { - LinkedHashMap map = (LinkedHashMap) respData; - int rv = (Integer) map.get(RESP_JSON_RESULT_KEY); - - if (rv == RESP_SUCCESS_RESULT) { - Object content = map.get(RESP_JSON_CONTENT_KEY); - if (content instanceof List) { - data = (ArrayList>) content; - } else if (content instanceof Map) { - LinkedHashMap contentEle = (LinkedHashMap) content; - data = new ArrayList>(); - data.add(contentEle); - } - } - } - return data; - } - - /** - * 调用service,返回数据 - * - * @param url service的地址 - * @param conn MBeanServerConnection对象 - * @return 调用service后返回的数据 - * @throws Exception - */ - protected Object getData(String url, MBeanServerConnection conn) throws Exception { - Object o = null; - ObjectName name = new ObjectName(DruidStatService.MBEAN_NAME); - - String result = (String) conn.invoke(name, "service", new String[] { url }, - new String[] { String.class.getName() }); - o = JSONUtils.parse(result); - if (LOG.isDebugEnabled()) { - LOG.debug(o.toString()); - } - return o; - } + /** * 调用完service之后,各个子类对于解析后的数据的具体处理 @@ -154,7 +101,7 @@ public abstract class DruidPanel extends JPanel { * @param conn MBeanServerConnection对象 * @throws Exception */ - protected void addOrRefreshTable(String url, MBeanServerConnection conn) throws Exception { + protected void addOrRefreshTable(String url) throws Exception { if (url != null) { boolean needRefresh = false; long timeNow = new Date().getTime(); @@ -211,7 +158,8 @@ public abstract class DruidPanel extends JPanel { } if (needRefresh) { LOG.debug("refresh" + timeNow); - ArrayList> data = parseData(getData(url, conn)); + ArrayList> data = TableDataProcessor.parseData(TableDataProcessor.getData(url, + conn)); if (data != null) { tableDataProcess(data); } @@ -230,9 +178,13 @@ public abstract class DruidPanel extends JPanel { } protected void doInBackground(MBeanServerConnection conn) { - + if (conn == null) { + LOG.warn("MBeanServerConnection is null"); + return; + } try { - addOrRefreshTable(url, conn); + this.conn = conn; + addOrRefreshTable(url); } catch (Exception e) { LOG.warn("", e); } diff --git a/src/main/java/com/alibaba/druid/support/jconsole/DruidSQLPanel.java b/src/main/java/com/alibaba/druid/support/jconsole/DruidSQLPanel.java index 7bb07181ba..6c65ed27c1 100644 --- a/src/main/java/com/alibaba/druid/support/jconsole/DruidSQLPanel.java +++ b/src/main/java/com/alibaba/druid/support/jconsole/DruidSQLPanel.java @@ -299,7 +299,7 @@ public class DruidSQLPanel extends DruidPanel { if (e.getClickCount() == 2) {// 点击几次,这里是双击事件 int row = table.getSelectedRow(); String id = ids.get(row); - System.out.println(id); + new DruidSqlDetailFrame(id,conn); } } }); diff --git a/src/main/java/com/alibaba/druid/support/jconsole/DruidSqlDetailFrame.java b/src/main/java/com/alibaba/druid/support/jconsole/DruidSqlDetailFrame.java new file mode 100644 index 0000000000..0b236749be --- /dev/null +++ b/src/main/java/com/alibaba/druid/support/jconsole/DruidSqlDetailFrame.java @@ -0,0 +1,313 @@ +package com.alibaba.druid.support.jconsole; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.GridLayout; +import java.awt.Toolkit; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +import javax.management.MBeanServerConnection; +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.border.TitledBorder; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableColumn; + +import com.alibaba.druid.support.jconsole.model.DruidTableCellRenderer; +import com.alibaba.druid.support.jconsole.model.DruidTableModel; +import com.alibaba.druid.support.jconsole.util.TableDataProcessor; +import com.alibaba.druid.support.jconsole.util.TableDataProcessor.ColumnData; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + +/** + * sql语句的详细信息 + * + * 调用服务地址:/sql-{id}.json + * 返回信息: + *
+ * {
+    "ResultCode": 1,
+    "Content": {
+            "ExecuteCount": 15,
+            "ReadStringLength": 0,
+            "LastSlowParameters": null,
+            "BlobOpenCount": 0,
+            "InputStreamOpenCount": 0,
+            "DbType": "mysql",
+            "DataSource": null,
+            "RunningCount": 0,
+            "parsedRelationships": "[]",
+            "ConcurrentMax": 1,
+            "LastErrorClass": null,
+            "MaxTimespan": 125,
+            "InTransactionCount": 0,
+            "ID": 3,
+            "parsedFields": "[]",
+            "EffectedRowCount": 0,
+            "BatchSizeTotal": 0,
+            "URL": null,
+            "ExecuteAndResultSetHoldTime": 0,
+            "LastErrorMessage": null,
+            "FetchRowCountHistogram": [
+                0,
+                0,
+                0,
+                0,
+                0,
+                0
+            ],
+            "FetchRowCountMax": 0,
+            "Histogram": [
+                0,
+                0,
+                13,
+                2,
+                0,
+                0,
+                0,
+                0
+            ],
+            "parsedOrderbycolumns": "[]",
+            "ErrorCount": 0,
+            "SQL": "DROP TABLE t_big",
+            "ClobOpenCount": 0,
+            "LastTime": "2012-09-14 21:35:10",
+            "File": null,
+            "LastErrorStackTrace": null,
+            "LastError": null,
+            "EffectedRowCountHistogram": [
+                15,
+                0,
+                0,
+                0,
+                0,
+                0
+            ],
+            "TotalTime": 742,
+            "formattedSql": "DROP TABLE t_big",
+            "Name": null,
+            "MaxTimespanOccurTime": "2012/09/14 09:35:00:758",
+            "parsedTable": "{t_big=Drop}",
+            "BatchSizeMax": 0,
+            "ReadBytesLength": 0,
+            "EffectedRowCountMax": 0,
+            "FetchRowCount": 0,
+            "parsedConditions": "[]",
+            "ResultSetHoldTime": 0,
+            "ReaderOpenCount": 0,
+            "ExecuteAndResultHoldTimeHistogram": [
+                0,
+                0,
+                13,
+                2,
+                0,
+                0,
+                0,
+                0
+            ],
+            "LastErrorTime": null
+        }
+    }
+ * 
+ * */ +public class DruidSqlDetailFrame extends JFrame { + + private static final long serialVersionUID = 1L; + private static final String BASE_URL = "/sql"; + private String id; + private MBeanServerConnection conn; + private static final ArrayList PARESE_TITLE_LIST = new ArrayList(){ + + private static final long serialVersionUID = 1L; + + { + add("parsedTable"); + add("parsedFields"); + add("parsedConditions"); + add("parsedRelationships"); + add("parsedOrderbycolumns"); + + } + }; + private static final ArrayList LAST_SLOW_TITLE_LIST= new ArrayList(){ + + private static final long serialVersionUID = 1L; + + { + add("MaxTimespan"); + add("MaxTimespanOccurTime"); + add("LastSlowParameters"); + } + }; + private static final ArrayList LAST_ERROR_TITLE_LIST= new ArrayList(){ + + private static final long serialVersionUID = 1L; + + { + add("LastErrorMessage"); + add("LastErrorClass"); + add("LastErrorTime"); + add("LastErrorStackTrace"); + } + }; + private static final ArrayList OTHER_ERROR_TITLE_LIST= new ArrayList(){ + + private static final long serialVersionUID = 1L; + + { + add("BatchSizeMax"); + add("BatchSizeTotal"); + add("BlobOpenCount"); + add("ClobOpenCount"); + add("ReaderOpenCount"); + add("InputStreamOpenCount"); + add("ReadStringLength"); + add("ReadBytesLength"); + } + }; + private ArrayList> parseData; + private ArrayList> lastSlowData; + private ArrayList> lastErrorData; + private ArrayList> otherData; + private int maxListLen; + private String formatSql; + private String sql; + + private static final int WIDTH = 620; + private static final int HEIGHT = 520; + private final static Log LOG = LogFactory.getLog(DruidSqlDetailFrame.class); + + public DruidSqlDetailFrame(String id, MBeanServerConnection conn) { + this.id = id; + this.conn = conn; + getMaxListLen(); + init(); + start(); + } + + private void getMaxListLen() { + maxListLen = PARESE_TITLE_LIST.size(); + int slowLen = LAST_SLOW_TITLE_LIST.size(); + int errLen = LAST_ERROR_TITLE_LIST.size(); + int otherLen = OTHER_ERROR_TITLE_LIST.size(); + if (maxListLen < slowLen) { + maxListLen = slowLen; + } + if (maxListLen < errLen) { + maxListLen = errLen; + } + if (maxListLen < otherLen) { + maxListLen = otherLen; + } + } + + private void init() { + String url = BASE_URL + "-" + id + ".json"; + + try { + ArrayList> data = TableDataProcessor.parseData(TableDataProcessor.getData(url,conn)); + if (data != null) { + LinkedHashMap contentEle = data.get(0); + formatSql = (String)contentEle.remove("formattedSql"); + int parseLen = PARESE_TITLE_LIST.size(); + int slowLen = LAST_SLOW_TITLE_LIST.size(); + int errLen = LAST_ERROR_TITLE_LIST.size(); + int otherLen = OTHER_ERROR_TITLE_LIST.size(); + LinkedHashMap parseDataEle = new LinkedHashMap(); + LinkedHashMap slowDataEle = new LinkedHashMap(); + LinkedHashMap errDataEle = new LinkedHashMap(); + LinkedHashMap otherDataEle = new LinkedHashMap(); + parseData = new ArrayList>(1); + lastSlowData = new ArrayList>(1); + lastErrorData = new ArrayList>(1); + otherData = new ArrayList>(1); + for (Iterator> it = contentEle.entrySet().iterator(); it.hasNext();) { + Entry entry = it.next(); + String key = entry.getKey(); + Object value = entry.getValue(); + for(int i=0;i> data) { + final JPanel content1 = new JPanel(); + content1.setLayout(new BorderLayout()); + content1.setBorder((TitledBorder)BorderFactory.createTitledBorder(title)); + contentPanel.add(content1); + + ColumnData colData = TableDataProcessor.row2col(data); + JTable table = new JTable(); + DruidTableModel tableModel = new DruidTableModel(colData.getDatas()); + table.setModel(tableModel); + + TableColumn col = table.getColumnModel().getColumn(0); + col.setCellRenderer(new DruidTableCellRenderer()); + + final JTableHeader header1 = table.getTableHeader(); + content1.add(header1,BorderLayout.NORTH); + content1.add(table); + } + + private void addComponentsToPane(Container pane) { + JScrollPane scrollPane = new JScrollPane(); + JPanel contentPanel = new JPanel(); + contentPanel.setLayout(new GridLayout(0,1)); + + final JTextArea sqlField = new JTextArea(formatSql,15,20); + final JScrollPane content1 = new JScrollPane (sqlField); + + content1.setBorder((TitledBorder)BorderFactory.createTitledBorder("SQL语句")); + contentPanel.add(content1); + + addTable(contentPanel,"解析信息",parseData); + addTable(contentPanel,"上次慢查询信息",lastSlowData); + addTable(contentPanel,"上次错误查询信息",lastErrorData); + addTable(contentPanel,"其他信息",otherData); + + scrollPane.setViewportView(contentPanel); + pane.add(scrollPane,BorderLayout.CENTER); + } + + private void start() { + addComponentsToPane(getContentPane()); + pack(); + setSize(WIDTH, HEIGHT); + double width = Toolkit.getDefaultToolkit().getScreenSize().getWidth(); + double height = Toolkit.getDefaultToolkit().getScreenSize().getHeight(); + + setLocation( (int) (width - getWidth()) / 2, + (int) (height - getHeight()) / 2); + setVisible(true); + } + +} diff --git a/src/main/java/com/alibaba/druid/support/jconsole/util/TableDataProcessor.java b/src/main/java/com/alibaba/druid/support/jconsole/util/TableDataProcessor.java index 57e22c9c5c..0c1a2641de 100644 --- a/src/main/java/com/alibaba/druid/support/jconsole/util/TableDataProcessor.java +++ b/src/main/java/com/alibaba/druid/support/jconsole/util/TableDataProcessor.java @@ -17,8 +17,17 @@ package com.alibaba.druid.support.jconsole.util; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import com.alibaba.druid.stat.DruidStatService; +import com.alibaba.druid.support.json.JSONUtils; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + /** * 表格数据处理类 * @@ -27,10 +36,18 @@ import java.util.Map; public final class TableDataProcessor { /** 名称列的列名. */ - private static final String COLUMN_KEY_NAME = "名称"; + private static final String COLUMN_KEY_NAME = "名称"; /** 内容列的列名. */ - private static final String COLUMN_VALUE_NAME = "值"; + private static final String COLUMN_VALUE_NAME = "值"; + + /** 返回码在json中的键名 */ + private static final String RESP_JSON_RESULT_KEY = "ResultCode"; + /** 内容在json中的键名 */ + private static final String RESP_JSON_CONTENT_KEY = "Content"; + /** 成功的返回码 */ + protected static final int RESP_SUCCESS_RESULT = 1; + private final static Log LOG = LogFactory.getLog(TableDataProcessor.class); /** * TableDataProcessor的构造函数 @@ -124,6 +141,54 @@ public final class TableDataProcessor { public static ColumnData row2col(ArrayList> rowDatas) { return row2col(rowDatas, null); } + + /** + * 解析调用service后得到JSON数据 + * + * @param respData 获取到的json对象 + * @return 返回解析后的数据 + */ + @SuppressWarnings("unchecked") + public static ArrayList> parseData(Object respData) { + ArrayList> data = null; + if (respData instanceof Map) { + LinkedHashMap map = (LinkedHashMap) respData; + int rv = (Integer) map.get(RESP_JSON_RESULT_KEY); + + if (rv == RESP_SUCCESS_RESULT) { + Object content = map.get(RESP_JSON_CONTENT_KEY); + if (content instanceof List) { + data = (ArrayList>) content; + } else if (content instanceof Map) { + LinkedHashMap contentEle = (LinkedHashMap) content; + data = new ArrayList>(); + data.add(contentEle); + } + } + } + return data; + } + + /** + * 调用service,返回数据 + * + * @param url service的地址 + * @param conn MBeanServerConnection对象 + * @return 调用service后返回的数据 + * @throws Exception + */ + public static Object getData(String url, MBeanServerConnection conn) throws Exception { + Object o = null; + ObjectName name = new ObjectName(DruidStatService.MBEAN_NAME); + + String result = (String) conn.invoke(name, "service", new String[] { url }, + new String[] { String.class.getName() }); + o = JSONUtils.parse(result); + if (LOG.isDebugEnabled()) { + LOG.debug(o.toString()); + } + return o; + } /** * The Class ColumnData.