tomcat集群时,原来通过HttpSessionListener实现类监听session的创建和销毁来统计在线人数的方法不再有效,因为不是每个人登陆都会在同一个tomcat服务器上,而在另一台tomcat上登陆的人的session是通过session复制创建的,而复制过程不会调用HttpSessionListener接口的方法,也一直没找着如何监听session复制的方法,所以就没法统计在线人了。

今天突然回想起tomcat下的manager应用上面就能看到session数和session的内容,于是本文的实现原理就是,做一个类似这样的servlet,此servlet把tomcat上负责管理应用的对象保存下来,供我任意使用。在tomcat上看应用的信息时,使用的是http://localhost:8080/manager/html/list这个路径,页面信息见下图:

  于是把源码下来看看 (apache-tomcat-6.0.39-src),细看tomcat下webapps/manager/WEB-INF/web.xml文件配置,发现原来tomcat是通过org.apache.catalina.manager.ManagerServlet这个类来提供以上服务的,跟踪此类doGet方法代码

  1. // --------------------------------------------------------- Public Methods
  2.  
  3. /**
  4. * Process a GET request for the specified resource.
  5. *
  6. * @param request
  7. * The servlet request we are processing
  8. * @param response
  9. * The servlet response we are creating
  10. *
  11. * @exception IOException
  12. * if an input/output error occurs
  13. * @exception ServletException
  14. * if a servlet-specified error occurs
  15. */
  16. public void doGet(HttpServletRequest request, HttpServletResponse response)
  17. throws IOException, ServletException {
  18.  
  19. // Identify the request parameters that we need
  20. // 取得访问路径,
  21. String command = request.getPathInfo();
  22.  
  23. String path = request.getParameter("path");
  24. String deployPath = request.getParameter("deployPath");
  25. String deployConfig = request.getParameter("deployConfig");
  26. String deployWar = request.getParameter("deployWar");
  27.  
  28. // Prepare our output writer to generate the response message
  29. response.setContentType("text/html; charset=" + Constants.CHARSET);
  30.  
  31. String message = "";
  32. // Process the requested command
  33. if (command == null || command.equals("/")) {
  34. } else if (command.equals("/deploy")) {
  35. message = deployInternal(deployConfig, deployPath, deployWar);
  36. // 找到了,就是这个路径,往下看list方法
  37. } else if (command.equals("/list")) {
  38. } else if (command.equals("/reload")) {
  39. message = reload(path);
  40. } else if (command.equals("/undeploy")) {
  41. message = undeploy(path);
  42. } else if (command.equals("/expire")) {
  43. message = expireSessions(path, request);
  44. } else if (command.equals("/sessions")) {
  45. try {
  46. doSessions(path, request, response);
  47. return;
  48. } catch (Exception e) {
  49. log("HTMLManagerServlet.sessions[" + path + "]", e);
  50. message = sm
  51. .getString("managerServlet.exception", e.toString());
  52. }
  53. } else if (command.equals("/start")) {
  54. message = start(path);
  55. } else if (command.equals("/stop")) {
  56. message = stop(path);
  57. } else if (command.equals("/findleaks")) {
  58. message = findleaks();
  59. } else {
  60. message = sm.getString("managerServlet.unknownCommand", command);
  61. }
  62. // 就是这个方法生成上面的那个页面
  63. list(request, response, message);
  64. }

list

  1. /**
  2. * Render a HTML list of the currently active Contexts in our virtual host,
  3. * and memory and server status information.
  4. *
  5. * @param request
  6. * The request
  7. * @param response
  8. * The response
  9. * @param message
  10. * a message to display
  11. */
  12. public void list(HttpServletRequest request, HttpServletResponse response,
  13. String message) throws IOException {
  14.  
  15. if (debug >= 1)
  16. log("list: Listing contexts for virtual host '" + host.getName()
  17. + "'");
  18.  
  19. PrintWriter writer = response.getWriter();
  20.  
  21. // HTML Header Section
  22. writer.print(Constants.HTML_HEADER_SECTION);
  23.  
  24. // Body Header Section
  25. Object[] args = new Object[2];
  26. args[0] = request.getContextPath();
  27. args[1] = sm.getString("htmlManagerServlet.title");
  28. writer.print(MessageFormat.format(Constants.BODY_HEADER_SECTION, args));
  29.  
  30. // Message Section
  31. args = new Object[3];
  32. args[0] = sm.getString("htmlManagerServlet.messageLabel");
  33. if (message == null || message.length() == 0) {
  34. args[1] = "OK";
  35. } else {
  36. args[1] = RequestUtil.filter(message);
  37. }
  38. writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args));
  39.  
  40. // Manager Section
  41. args = new Object[9];
  42. args[0] = sm.getString("htmlManagerServlet.manager");
  43. args[1] = response.encodeURL(request.getContextPath() + "/html/list");
  44. args[2] = sm.getString("htmlManagerServlet.list");
  45. args[3] = response.encodeURL(request.getContextPath() + "/"
  46. + sm.getString("htmlManagerServlet.helpHtmlManagerFile"));
  47. args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
  48. args[5] = response.encodeURL(request.getContextPath() + "/"
  49. + sm.getString("htmlManagerServlet.helpManagerFile"));
  50. args[6] = sm.getString("htmlManagerServlet.helpManager");
  51. args[7] = response.encodeURL(request.getContextPath() + "/status");
  52. args[8] = sm.getString("statusServlet.title");
  53. writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args));
  54.  
  55. // Apps Header Section
  56. args = new Object[6];
  57. args[0] = sm.getString("htmlManagerServlet.appsTitle");
  58. args[1] = sm.getString("htmlManagerServlet.appsPath");
  59. args[2] = sm.getString("htmlManagerServlet.appsName");
  60. args[3] = sm.getString("htmlManagerServlet.appsAvailable");
  61. args[4] = sm.getString("htmlManagerServlet.appsSessions");
  62. args[5] = sm.getString("htmlManagerServlet.appsTasks");
  63. writer.print(MessageFormat.format(APPS_HEADER_SECTION, args));
  64.  
  65. // Apps Row Section
  66. // Create sorted map of deployed applications context paths.
  67.  
  68. // host就当是当前的tomcat吧,那么contexts就此tomcat下的所有应用
  69. Container children[] = host.findChildren();
  70. String contextPaths[] = new String[children.length];
  71. // 循环每个应用
  72. for (int i = 0; i < children.length; i++)
  73. // 应用名称
  74. contextPaths[i] = children[i].getName();
  75.  
  76. TreeMap sortedContextPathsMap = new TreeMap();
  77.  
  78. for (int i = 0; i < contextPaths.length; i++) {
  79. // 应用部署路径
  80. String displayPath = contextPaths[i];
  81. sortedContextPathsMap.put(displayPath, contextPaths[i]);
  82. }
  83.  
  84. String appsStart = sm.getString("htmlManagerServlet.appsStart");
  85. String appsStop = sm.getString("htmlManagerServlet.appsStop");
  86. String appsReload = sm.getString("htmlManagerServlet.appsReload");
  87. String appsUndeploy = sm.getString("htmlManagerServlet.appsUndeploy");
  88. String appsExpire = sm.getString("htmlManagerServlet.appsExpire");
  89.  
  90. Iterator iterator = sortedContextPathsMap.entrySet().iterator();
  91. boolean isHighlighted = true;
  92. boolean isDeployed = true;
  93. String highlightColor = null;
  94.  
  95. while (iterator.hasNext()) {
  96. // Bugzilla 34818, alternating row colors
  97. isHighlighted = !isHighlighted;
  98. if (isHighlighted) {
  99. highlightColor = "#C3F3C3";
  100. } else {
  101. highlightColor = "#FFFFFF";
  102. }
  103.  
  104. Map.Entry entry = (Map.Entry) iterator.next();
  105. String displayPath = (String) entry.getKey();
  106. String contextPath = (String) entry.getValue();
  107. Context context = (Context) host.findChild(contextPath);
  108. if (displayPath.equals("")) {
  109. displayPath = "/";
  110. }
  111.  
  112. if (context != null) {
  113. try {
  114. isDeployed = isDeployed(contextPath);
  115. } catch (Exception e) {
  116. // Assume false on failure for safety
  117. isDeployed = false;
  118. }
  119.  
  120. args = new Object[7];
  121. args[0] = URL_ENCODER.encode(contextPath + "/");
  122. args[1] = RequestUtil.filter(displayPath);
  123. if (context.getDisplayName() == null) {
  124. args[2] = "&nbsp;";
  125. } else {
  126. args[2] = RequestUtil.filter(context.getDisplayName());
  127. }
  128. managerServlet
  129. // 应用是否已启动
  130. args[3] = new Boolean(context.getAvailable());
  131. args[4] = response.encodeURL(request.getContextPath()
  132. + "/html/sessions?path="
  133. + URL_ENCODER.encode(displayPath));
  134. if (context.getManager() != null) {
  135. args[5] = new Integer(context.getManager()
  136. .getActiveSessions());
  137. } else {
  138. args[5] = new Integer(0);
  139. }
  140.  
  141. args[6] = highlightColor;
  142. //打印出一行关于此应用的信息,应用的URL,当前状态,session数等,具体见上图
  143. writer.print(MessageFormat.format(APPS_ROW_DETAILS_SECTION,
  144. args));
  145.  
  146. args = new Object[14];
  147. args[0] = response
  148. .encodeURL(request.getContextPath()
  149. + "/html/start?path="
  150. + URL_ENCODER.encode(displayPath));
  151. args[1] = appsStart;
  152. args[2] = response.encodeURL(request.getContextPath()
  153. + "/html/stop?path=" + URL_ENCODER.encode(displayPath));
  154. args[3] = appsStop;
  155. args[4] = response.encodeURL(request.getContextPath()
  156. + "/html/reload?path="
  157. + URL_ENCODER.encode(displayPath));
  158. args[5] = appsReload;
  159. args[6] = response.encodeURL(request.getContextPath()
  160. + "/html/undeploy?path="
  161. + URL_ENCODER.encode(displayPath));
  162. args[7] = appsUndeploy;
  163.  
  164. args[8] = response.encodeURL(request.getContextPath()
  165. + "/html/expire?path="
  166. + URL_ENCODER.encode(displayPath));
  167. args[9] = appsExpire;
  168. args[10] = sm.getString("htmlManagerServlet.expire.explain");
  169. Manager manager = context.getManager();
  170. if (manager == null) {
  171. args[11] = sm.getString("htmlManagerServlet.noManager");
  172. } else {
  173. args[11] = new Integer(context.getManager()
  174. .getMaxInactiveInterval() / 60);
  175. }
  176. args[12] = sm.getString("htmlManagerServlet.expire.unit");
  177.  
  178. args[13] = highlightColor;
  179.  
  180. if (context.getPath().equals(this.context.getPath())) {
  181. writer.print(MessageFormat.format(
  182. MANAGER_APP_ROW_BUTTON_SECTION, args));
  183. } else if (context.getAvailable() && isDeployed) {
  184. writer.print(MessageFormat.format(
  185. STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  186. } else if (context.getAvailable() && !isDeployed) {
  187. writer.print(MessageFormat.format(
  188. STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  189. } else if (!context.getAvailable() && isDeployed) {
  190. writer.print(MessageFormat.format(
  191. STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  192. } else {
  193. writer.print(MessageFormat.format(
  194. STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  195. }
  196.  
  197. }
  198. }
  199.  
  200. // Deploy Section
  201. args = new Object[7];
  202. args[0] = sm.getString("htmlManagerServlet.deployTitle");
  203. args[1] = sm.getString("htmlManagerServlet.deployServer");
  204. args[2] = response.encodeURL(request.getContextPath() + "/html/deploy");
  205. args[3] = sm.getString("htmlManagerServlet.deployPath");
  206. args[4] = sm.getString("htmlManagerServlet.deployConfig");
  207. args[5] = sm.getString("htmlManagerServlet.deployWar");
  208. args[6] = sm.getString("htmlManagerServlet.deployButton");
  209. writer.print(MessageFormat.format(DEPLOY_SECTION, args));
  210.  
  211. args = new Object[4];
  212. args[0] = sm.getString("htmlManagerServlet.deployUpload");
  213. args[1] = response.encodeURL(request.getContextPath() + "/html/upload");
  214. args[2] = sm.getString("htmlManagerServlet.deployUploadFile");
  215. args[3] = sm.getString("htmlManagerServlet.deployButton");
  216. writer.print(MessageFormat.format(UPLOAD_SECTION, args));
  217.  
  218. // Diagnostics section
  219. args = new Object[5];
  220. args[0] = sm.getString("htmlManagerServlet.diagnosticsTitle");
  221. args[1] = sm.getString("htmlManagerServlet.diagnosticsLeak");
  222. args[2] = response.encodeURL(request.getContextPath()
  223. + "/html/findleaks");
  224. args[3] = sm.getString("htmlManagerServlet.diagnosticsLeakWarning");
  225. args[4] = sm.getString("htmlManagerServlet.diagnosticsLeakButton");
  226. writer.print(MessageFormat.format(DIAGNOSTICS_SECTION, args));
  227.  
  228. // Server Header Section
  229. args = new Object[7];
  230. args[0] = sm.getString("htmlManagerServlet.serverTitle");
  231. args[1] = sm.getString("htmlManagerServlet.serverVersion");
  232. args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
  233. args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
  234. args[4] = sm.getString("htmlManagerServlet.serverOSName");
  235. args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
  236. args[6] = sm.getString("htmlManagerServlet.serverOSArch");
  237. writer.print(MessageFormat
  238. .format(Constants.SERVER_HEADER_SECTION, args));
  239.  
  240. // Server Row Section
  241. args = new Object[6];
  242. args[0] = ServerInfo.getServerInfo();
  243. args[1] = System.getProperty("java.runtime.version");
  244. args[2] = System.getProperty("java.vm.vendor");
  245. args[3] = System.getProperty("os.name");
  246. args[4] = System.getProperty("os.version");
  247. args[5] = System.getProperty("os.arch");
  248. writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args));
  249.  
  250. // HTML Tail Section
  251. writer.print(Constants.HTML_TAIL_SECTION);
  252.  
  253. // Finish up the response
  254. writer.flush();
  255. writer.close();
  256. }

  注意:context.getManager().findSessions()可以取得所有session,但这是个org.apache.catalina.Session[]数组,不是HttpSession[]数组,但这个Session接口里面有个getSession方法,返回结果正是HttpSession类型,没错,就是循环这个数组并调用其getSession方法就可以取得所有在线用户了

上面的Session[]数组是从context对象里面来的,而context是从host对象来的,host是个初始值为NULL的成员变量,是什么时候赋上值的?是在init方法执行前,setWrapper方法执行时赋的值,请看setWrapper方法代码

public class HostManagerServlet
extends HttpServlet implements ContainerServlet

  1. /**
  2. * Set the Wrapper with which we are associated.
  3. *
  4. * @param wrapper The new wrapper
  5. */
  6. public void setWrapper(Wrapper wrapper) {
  7.  
  8. //这里所有需要的对象都有了,其实下面我们需要拿到wrapper就够了
  9. this.wrapper = wrapper;
  10. if (wrapper == null) {
  11. context = null;
  12. host = null;
  13. engine = null;
  14. } else {
  15. context = (Context) wrapper.getParent();
  16. host = (Host) context.getParent();
  17. engine = (Engine) host.getParent();
  18. }
  19.  
  20. // Retrieve the MBean server
  21. mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
  22.  
  23. }

  setWrapper会在初始化时被调用,怎么实现的,首先看web.xml中对此servlet的配置,没什么特别,我们可以发散一下思维,struts2里面action如何能自动注入request对象?Spring如何让service监听事件?答案是一样的,那就是让你的类实现某个接口,你要的东西就给你了,对的,这里也一样,此servlet实现了ContainerServlet接口,初始的时候setWrapper方法才会被调用。

  是JAVA新手的看这里,我提出上面这些问题,不是想卖什么关子,只是想启发JAVA初学者们,当某天你们做设计时,可以参考这种方法,一句概括就是:只要你实现我的接口,我就可以让你做某事,而不需要任何额外的配置。当然这种设计的缺点就是入侵、偶合。举个简单的应用场景:每天晚上,我用一个定时器通过Spring搜索所有实现了“GarbageCleaner”接口的service bean,并调用其clean方法清理对应模块的垃圾数据,那么任何模块的service只要实现了此接口,就会被调用。

回到正题,我也自已写个servlet并且实ContainerServlet接口吧,使用静态方法取得所有的session,具体代码如下:

  1. package manager.session.http.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.util.LinkedHashMap;
  5. import java.util.Map;
  6.  
  7. import javax.servlet.ServletException;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import javax.servlet.http.HttpSession;
  12.  
  13. import org.apache.catalina.ContainerServlet;
  14. import org.apache.catalina.Context;
  15. import org.apache.catalina.Session;
  16. import org.apache.catalina.Wrapper;
  17.  
  18. public class TomcatWrapperServlet extends HttpServlet implements
  19. ContainerServlet {
  20. private static final long serialVersionUID = 1L;
  21.  
  22. // 弄个静态变量,初始化后就记下来,以备随时使用
  23. private static Wrapper wrapper = null;
  24.  
  25. public Wrapper getWrapper() {
  26. return wrapper;
  27. }
  28.  
  29. public void setWrapper(Wrapper wrapper) {
  30. TomcatWrapperServlet.wrapper = wrapper;
  31. }
  32.  
  33. // doGet不做任何事情,只需要接收第一次请求,触发初始动作就完成它的使命了
  34. @Override
  35. protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  36. throws ServletException, IOException {
  37. resp.getWriter().println("Hello world!");
  38. resp.getWriter().flush();
  39. resp.getWriter().close();
  40. }
  41.  
  42. // 初始化后可通过此静态方法取得所有session
  43. public static Map<String, HttpSession> fillSessions() {
  44. if (wrapper == null) {// 没有初始化
  45. throw new RuntimeException(
  46. "本servlet未被初始化,您必须先通过URL访问本servlet后,才可以调用这个方法");
  47. }
  48. Map<String, HttpSession> sessions = new LinkedHashMap<String, HttpSession>();
  49.  
  50. // 取得本应用
  51. Context context = (Context) wrapper.getParent();
  52. // 取得Session[]数组
  53. Session[] temps = context.getManager().findSessions();
  54. if (temps != null && temps.length > 0) {
  55. for (int j = 0; j < temps.length; j++) {
  56. // Map<sessionId,session>
  57. sessions.put(temps[j].getSession().getId(), temps[j]
  58. .getSession());
  59. }
  60. }
  61. return sessions;
  62. }
  63.  
  64. }

 

 在web.xml配置一下,然后启动应用,访问之,结果出现异常,是一个安全异常:TomcatWrapperServlet is privileged and cannot be loaded by this web application(想想如下),说我的类是个特权类,不能被普通的web应用加载,为何manager这个应用又可以呢?把manager/META-INF/context.xml复制到我的应用,再加载,再访问,一切搞定,此文件内容只有一句

  Xml代码

  1. <Context antiResourceLocking="false" privileged="true" />

HTTP Status 500 - Error allocating a servlet instance


type Exception report

message Error allocating a servlet instance

description The server encountered an internal error that prevented it from fulfilling this request.

exception

  1. javax.servlet.ServletException: Error allocating a servlet instance
  2. org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
  3. org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
  4. org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:879)
  5. org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:617)
  6. org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1760)
  7. java.lang.Thread.run(Thread.java:722)

root cause

  1. java.lang.SecurityException: Servlet of class manager.session.http.servlet.TomcatWrapperServlet is privileged and cannot be loaded by this web application
  2. org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
  3. org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
  4. org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:879)
  5. org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:617)
  6. org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1760)
  7. java.lang.Thread.run(Thread.java:722)

note The full stack trace of the root cause is available in the Apache Tomcat/6.0.37 logs.


Apache Tomcat/6.0.37

来自:http://www.jspspace.com/ResearchTopics/Art-1757-17.html

tomcat集群时统计session与在线人数的更多相关文章

  1. Tomcat集群环境下session共享方案 通过memcached 方法实现

    对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...

  2. Nginx+tomcat集群中,session的共享

    nginx,tomcat集群后多个session分配到同一个应用 单节点低负荷的情况下,我们通常把一个WEB应用打成WAR包放WEB应用服务器,如TOMCAT下运行就行了(如图1).但随着用户量的增加 ...

  3. 用redis实现TOMCAT集群下的session共享

    上篇实现了 LINUX中NGINX反向代理下的TOMCAT集群(http://www.cnblogs.com/yuanjava/p/6850764.html) 这次我们在上篇的基础上实现session ...

  4. nginx整合tomcat集群并做session共享----测试案例

    最近出于好奇心,研究了一下tomcat集群配置,并整合nginx,实现负载均衡,session共享,写篇记录,防止遗忘.---------菜鸡的自我修炼. 说明:博主采用一个web项目同时部署到两台t ...

  5. Tomcat 集群中 实现session 共享的三种方法

    前两种均需要使用 memcached 或 redis 存储 session ,最后一种使用 terracotta 服务器共享. 建议使用 redis ,不仅仅因为它可以将缓存的内容持久化,还因为它支持 ...

  6. tomcat 集群配置,Session复制共享

    本配置在tomcat7上验证通过.通过此方法配置的集群,session信息将会被自动复制到各个节点. 1.配置Server.xml 在Server.xml中,找到被注释<Cluster/> ...

  7. Nginx+tomcat集群redis共享session应用方案

    部署环境 主机 软件版本 192.168.88.1 nginx-1.12.2+redis-3.2.11 192.168.88.2 apache-tomcat-7.0.79 + jdk1.8 192.1 ...

  8. Tomcat 集群模式下 Session 更新 Bug (redis memcached 及tomcat自已的集群)

    从 excel 中导入数据入系统,我们用的是先上传文件至服务器再分析所上传的文件逐行导入. 就是执行了一循环,在当前循环位置标识一下客户端就知道执行的进度了,以前的方式 是用 session.setA ...

  9. TOMCAT 集群之 PERSISTENT SESSION

    tomcat的session保存在数据库中,不是很复杂,写下来供大家参考. 准备工作: 两架Ubuntu Server 12.04 64位,确定两级服务器可以互相ping的通并属于同一个网段 安装jd ...

随机推荐

  1. html5 之 canvas 相关知识(三)API-strokeStyle-shadow相关

    strokeStyle定义和用法 strokeStyle 属性设置或返回用于笔触的颜色.渐变或模式. context.strokeStyle=color|gradient|pattern;//指示绘图 ...

  2. 实现类似 QQ音乐网页版 的单页面总结

    最近需要对创业团队的网站进行改版,而我负责前端设计和实现. 下面是一些总结与体会: 当设计完成之前,我就跟和我配合的Java 后台说用iframe实现,结果说麻烦不肯,到最后突然对我说还是用ifram ...

  3. 在虚拟机中安装Linux

    安装CentOS 6.4教程(详细步骤) CentOS是RHEL的克隆版本,功能上是一模一样的,另外重新编译之后还修复了一些后者的bug.主要区别就是CentOS免费,但没有官方的技术支持,而RHEL ...

  4. 也说border-box盒模型

    border-box是css3的一个新属性,使用这个属性,和以往的content-box比起来,会有诸多便利之处,bootstrap3也使用的是这个border-box,甚至很多人认为,border- ...

  5. Linux 命令 - df: 报告磁盘空间的占用情况

    df 命令列出指定的文件名所在的文件系统上可用磁盘空间的数量. 如果没有指定文件名,则显示当前所有使用中的文件系统.默认情况下,磁盘空间以 1K 为一块显示,如果设置了环境变量 POSIXLY_COR ...

  6. ASP.NET MVC Partial页输出JS

    很多情况Partial是需要引用到JS的,通常做法是吧JS在引用Partial的页面中加入JS文件或者JS代码. 前阵子网上看到一段代码可以在Partial页面中添加JS,输出道引用页面. publi ...

  7. AjaxForm

    近乎的Ajax控件介绍,代码下载:http://www.jinhusns.com/Products/Download?type=whp AjaxForm 概述 功能说明 基于 ajaxForm 插件进 ...

  8. 基于AspectJ自定义注解

    package com.aspectj.demo.aspect; import java.lang.annotation.ElementType; import java.lang.annotatio ...

  9. 让 Putty 保存密码,自动登陆的四种方法

    Putty 基本是我在紧急时候用来登陆 Linux/Unix 终端的不二之先,因其小,开源,界面也非常实用.可是当你要在私有的机器上,经常性的要登陆很多机器的时候就觉得烦琐了,不光打开一堆的窗口,还要 ...

  10. [GeekBand] C++11~14

    一.关键字decltype 由对象得到对象的数据类型,例如 Complex  a(1,  2);     decltype(a)  b(3,  4);     declare type是让编译器去找到 ...