proxool默认提供了org.logicalcobwebs.proxool.admin.servlet.AdminServlet类,为用户提供页面查看连接池情况,包括连接池的配置信息、连接池连接的使用情况等。唯一缺陷是没有访问控制,人人都可访问(或许有,而我不知道)。本例重写AdminServlet类增加登录控制,并且增加Servlet3.0的@WebServlet注解。为简单起见,登录所用的用户名/密码直接写入AdminServlet类中。
为方便AppMain类启动时扫描到,将该类放在AppMain类所在的com.zweixhxu.springboot包的子包proxool里
AdminServlet.java
package com.zweixhxu.springboot.proxool; import org.logicalcobwebs.proxool.*; import org.logicalcobwebs.proxool.admin.SnapshotIF; import org.logicalcobwebs.proxool.admin.StatisticsIF; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebInitParam; import java.io.IOException; import java.io.PrintWriter; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.Properties; @WebServlet(urlPatterns="/proxoolPool", initParams={ @WebInitParam(name= AdminServlet.PARAM_USER_NAME, value="proxool"), @WebInitParam(name= AdminServlet.PARAM_LOGIN_PASS, value= "proxool@123"), }) public class AdminServlet extends HttpServlet { protected static final Logger LOG = LoggerFactory.getLogger(AdminServlet.class); private static final String[] STATUS_CLASSES = {"null", "available", "active", "offline"}; public static final String OUTPUT_FULL = "full"; public static final String OUTPUT_SIMPLE = "simple"; private String output; private String cssFile; private static final String STATISTIC = "statistic"; private static final String CORE_PROPERTY = "core-property"; private static final String STANDARD_PROPERTY = "standard-property"; private static final String DELEGATED_PROPERTY = "delegated-property"; protected static final String PARAM_REQ_ID = "requestId"; protected static final String PARAM_OP_TYPE = "opType"; public static final String PARAM_USER_NAME = "userName"; public static final String PARAM_LOGIN_PASS = "loginPass"; protected static final String OP_TYPE_LOGIN = "login"; private static final String SNAPSHOT = "snapshot"; private static String loginName = "proxool"; private static String loginPass = "proxool@123456"; public void init(ServletConfig servletConfig) throws ServletException { super.init(servletConfig); // Get output parameter. Default to OUTPUT_FULL. output = servletConfig.getInitParameter("output"); if (output != null) { if (output.equalsIgnoreCase(OUTPUT_FULL)) { output = OUTPUT_FULL; } else if (output.equalsIgnoreCase(OUTPUT_SIMPLE)) { output = OUTPUT_SIMPLE; } else { LOG.warn("Unrecognised output parameter for {}. Expected: {} or {}", this.getClass().getName(), OUTPUT_FULL, OUTPUT_SIMPLE); output = null; } } if (output == null) { output = OUTPUT_FULL; } loginName = servletConfig.getInitParameter(PARAM_USER_NAME); loginPass = servletConfig.getInitParameter(PARAM_LOGIN_PASS); cssFile = servletConfig.getInitParameter("cssFile"); } private static final DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final DateFormat DATE_FORMAT_M = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00"); private static final String DETAIL = "detail"; private static final String DETAIL_MORE = "more"; private static final String DETAIL_LESS = "less"; /** * The request parameter name that defines: **
*/ private static final String TAB = "tab"; /** * @see #TAB */ private static final String TAB_DEFINITION = "definition"; /** * @see #TAB */ private static final String TAB_SNAPSHOT = "snapshot"; /** * @see #TAB */ private static final String TAB_STATISTICS = "statistics"; /** * The request parameter name that defines the pool */ private static final String ALIAS = "alias"; /** * If we are drilling down into a connection (on the {@link #TAB_SNAPSHOT snapshot} tab then * this points to the {@link org.logicalcobwebs.proxool.ProxyConnection#getId() ID} we are * getting detailed information for. */ private static final String CONNECTION_ID = "id"; protected static final String LOGIN_SESSION_KEY = "dbPoolLoginUser"; protected boolean checkNotLogin(HttpServletRequest request, HttpServletResponse response, String requestId){ return request.getSession().getAttribute(LOGIN_SESSION_KEY)==null; } protected boolean doLogin(HttpServletRequest request, HttpServletResponse response){ String userName = request.getParameter(PARAM_USER_NAME); String pwd = request.getParameter(PARAM_LOGIN_PASS); if (!loginName.equals(userName) || !loginPass.equals(pwd)){ LOG.error("用户{}登录失败,用户名或密码失败", userName); return false; } doLoginSuccess(request, response, userName+"="+pwd); return true; } protected void doLoginSuccess(HttpServletRequest request, HttpServletResponse response, Object result){ request.getSession().setAttribute(LOGIN_SESSION_KEY, result); } protected void doLogout(HttpServletRequest request, HttpServletResponse response){ request.getSession().removeAttribute(LOGIN_SESSION_KEY); } /** * Delegate to {@link #doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)} */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } /** * Show the details for a pool. */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Pragma", "no-cache"); PrintWriter out = response.getWriter(); String link = request.getRequestURI(); String opType = request.getParameter(PARAM_OP_TYPE); String requestId = request.getParameter(PARAM_REQ_ID); LOG.debug("ProxoolAdmin>opType={}, \"{}\".equals(opType) => {}", opType, OP_TYPE_LOGIN, OP_TYPE_LOGIN.equals(opType)); if (OP_TYPE_LOGIN.equals(opType)){ try{ if (doLogin(request, response)){ requestId = request.getSession().getId(); }else{ failedAndDispalyLoginPage("用户名或密码错误,登录失败", response, out, link); return; } }catch(Exception e){ failedAndDispalyLoginPage("系统异常:" + e.toString(), response, out, link); return; } } if ("logout".equals(opType)){ doLogout(request, response); } if (requestId==null || checkNotLogin(request, response, requestId)){ failedAndDispalyLoginPage("", response, out, link); return; } // Check the alias and if not defined and there is only one // then use that. String alias = request.getParameter(ALIAS); // Check we can find the pool. ConnectionPoolDefinitionIF def = null; if (alias != null) { try { def = ProxoolFacade.getConnectionPoolDefinition(alias); } catch (ProxoolException e) { alias = null; } } String[] aliases = ProxoolFacade.getAliases(); if (alias == null) { if (aliases.length > 0) { alias = aliases[0]; } } if (def == null && alias != null) { try { def = ProxoolFacade.getConnectionPoolDefinition(alias); } catch (ProxoolException e) { throw new ServletException("Couldn't find pool with alias " + alias); } } String tab = request.getParameter(TAB); if (tab == null) { tab = TAB_DEFINITION; } // If we are showing the snapshot, are we showing it in detail or not? String snapshotDetail = request.getParameter(DETAIL); // If we are showing the snapshot, are we drilling down into a connection? String snapshotConnectionId = request.getParameter(CONNECTION_ID); try { if (output.equals(OUTPUT_FULL)) { response.setContentType("text/html"); openHtml(out); } out.println("- {@link #TAB_DEFINITION} (default)
*- {@link #TAB_SNAPSHOT}
*- {@link #TAB_STATISTICS}
*Proxool " + Version.getVersion() + " 退出登录"); out.println(""); doList(out, alias, tab, link); // Skip everything if there aren't any pools if (aliases != null && aliases.length > 0) { StatisticsIF[] statisticsArray = ProxoolFacade.getStatistics(alias); final boolean statisticsAvailable = (statisticsArray != null && statisticsArray.length > 0); final boolean statisticsComingSoon = def.getStatistics() != null; // We can't be on the statistics tab if there are no statistics if (!statisticsComingSoon && tab.equals(TAB_STATISTICS)) { tab = TAB_DEFINITION; } doTabs(out, alias, link, requestId, tab, statisticsAvailable, statisticsComingSoon); if (tab.equals(TAB_DEFINITION)) { doDefinition(out, def); } else if (tab.equals(TAB_SNAPSHOT)) { doSnapshot(out, def, link, snapshotDetail, snapshotConnectionId, requestId); } else if (tab.equals(TAB_STATISTICS)) { doStatistics(out, statisticsArray, def); } else { throw new ServletException("Unrecognised tab '" + tab + "'"); } } } catch (ProxoolException e) { throw new ServletException("Problem serving Proxool Admin", e); } if (output.equals(OUTPUT_FULL)) { closeHtml(out); } } private void failedAndDispalyLoginPage(String failMsg, HttpServletResponse response, PrintWriter out, String link) throws IOException{ response.setContentType("text/html"); openHtml(out); displayLoginForm(out, link); out.println("" + failMsg +""); closeHtml(out); } private void doTabs(PrintWriter out, String alias, String link, String requestId, String tab, boolean statisticsAvailable, boolean statisticsComingSoon) throws IOException { out.println("
- ");
out.println("
- Definition "); out.println("
- Snapshot "); if (statisticsAvailable) { out.println("
- Statistics "); } else if (statisticsComingSoon) { out.println("
- Statistics "); } out.println("
"); String[] colours = {"0000ff", "eeeeee"}; int[] lengths = {activityLevel, 100 - activityLevel}; drawBarChart(activityLevelBuffer, colours, lengths); printDefinitionEntry(out, "Activity level", activityLevelBuffer.toString(), STATISTIC); closeTable(out); } } private void drawBarChart(StringBuffer out, String[] colours, int[] lengths) { out.append("
"); } } out.append(" |
"); String[] colours = {"ff9999", "66cc66", "cccccc"}; int[] lengths = {snapshot.getActiveConnectionCount(), snapshot.getAvailableConnectionCount(), snapshot.getMaximumConnectionCount() - snapshot.getActiveConnectionCount() - snapshot.getAvailableConnectionCount()}; drawBarChart(connectionsBuffer, colours, lengths); printDefinitionEntry(out, "Connections", connectionsBuffer.toString(), SNAPSHOT); // servedCount printDefinitionEntry(out, "Served", String.valueOf(snapshot.getServedCount()), SNAPSHOT); // refusedCount printDefinitionEntry(out, "Refused", String.valueOf(snapshot.getRefusedCount()), SNAPSHOT); if (!detail) { out.println("
(click ID to drill down)"); out.println("
# | "); out.print("born | "); out.print("last start | "); out.print("last stop | "); out.print("lap (ms) | "); out.print("thread | "); out.print("
"); out.print(connectionInfo.getId()); } else { out.print("border: 1px solid transparent;"); out.print("\">"); out.print(connectionInfo.getId()); out.print(""); } out.print(" | "); // birth out.print(""); out.print(DATE_FORMAT.format(connectionInfo.getBirthDate())); out.print(" | "); // started out.print(""); out.print(connectionInfo.getTimeLastStartActive() > 0 ? DATE_FORMAT_M.format(new Date(connectionInfo.getTimeLastStartActive())) : "-"); out.print(" | "); // stop out.print(""); out.print(connectionInfo.getTimeLastStopActive() > 0 ? DATE_FORMAT_M.format(new Date(connectionInfo.getTimeLastStopActive())) : "-"); out.print(" | "); // active out.print(""); String active = " "; if (connectionInfo.getTimeLastStopActive() > 0) { active = String.valueOf((int) (connectionInfo.getTimeLastStopActive() - connectionInfo.getTimeLastStartActive())); } else if (connectionInfo.getTimeLastStartActive() > 0) { active = String.valueOf((int) (snapshot.getSnapshotDate().getTime() - connectionInfo.getTimeLastStartActive())); } out.print(active); out.print(" | "); // requester out.print(""); out.print(connectionInfo.getRequester() != null ? connectionInfo.getRequester() : "-"); out.print(" | "); out.println("
");
out.print("sql = ");
out.print(sqlCall);
out.print("
");
}
// proxy
out.print("");
out.print("proxy = ");
out.print(drillDownConnection.getProxyHashcode());
out.print("
");
// delegate
out.print("");
out.print("delegate = ");
out.print(drillDownConnection.getDelegateHashcode());
out.print("
");
// url
out.print("");
out.print("url = ");
out.print(drillDownConnection.getDelegateUrl());
out.print("
");
}
private void openHtml(PrintWriter out) throws IOException {
out.println(""); } private void printDefinitionEntry(PrintWriter out, String name, String value, String type) throws IOException { out.println("
No pools have been registered.
"); } else if (aliases.length == 1) { // Don't bother listing. Just show it. } else { out.println(""); } } /** * Express time in an easy to read HH:mm:ss format * * @param time in milliseconds * @return time (e.g. 180000 = 00:30:00) * @see #TIME_FORMAT */ private String formatMilliseconds(long time) { if (time > Integer.MAX_VALUE) { return time + "ms"; } else { Calendar c = Calendar.getInstance(); c.clear(); c.add(Calendar.MILLISECOND, (int) time); return TIME_FORMAT.format(c.getTime()); } } private void displayLoginForm(PrintWriter out, String link){ out.println(""); out.println(""); } }
启动应用后,访问http://localhost:18081/proxoolPool显示登录页面,输入用户名/密码,就是@WebServlet注解里initParam配置的用户名密码登录即可