实现“CSDN学生大本营”的限制连续发帖功能

        昨天晚上连续发了几篇帖子,发现"csdn学生大本营"有限制用户连续发帖的功能,也就是服务器会存储用户上次发帖的时间,当用户再次请求发帖时检测两次时间间隔是否过短,如果是,则提示用户等待一定的时间。

       不知道csdn是怎么实现的,我用的是java,实现思路,环境和具体步奏如下:

思路

          服务器使用一个HashMap来存储发表过帖子的用户,key为session的id,value为发帖时间,这里使用HashMap的理由是查找速度是恒定不变的,也就是说即使HashMap里面有999999个数据,其查询速度也和只有1个数据时一样。

          我们还需要一个清理HashMap的线程,清除那些已经达到合法间隔时间的数据,否则这个HashMap会膨胀的很大。

环境

          服务器依然选择我熟悉的Tomcat6,集成开发环境MyEclipse705,浏览器选择FireFox

具体步骤

          1.配置文件config.properties

Code:
  1. #清理间隔时间(毫秒)  
  2. interval=600000  
  3. #发帖所需间隔时间(毫秒)  
  4. issueInterval=60000  

         2基本信息类Config.java

Code:
  1. package com.jackyan.practice.util;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.util.Properties;  
  6.   
  7. public class Config {  
  8.     private static long interval=0;  
  9.     private static long issueInterval=0;  
  10.     private static String configName="config.properties";  
  11.     private static String intervalName="interval";  
  12.     private static String issueIntervalName="issueInterval";  
  13.     //默认的清扫间隔时间  
  14.     private static long defaultInterval=1000*60*60;  
  15.     //默认的合法发帖间隔时间  
  16.     private static long dufalutIssueInterval=1000*60;  
  17.     static{  
  18.         Properties prop=new Properties();  
  19.         InputStream is=Config.class.getResourceAsStream(configName);  
  20.         try {  
  21.             prop.load(is);  
  22.             interval=Long.parseLong(prop.getProperty(intervalName));  
  23.             issueInterval=Long.parseLong(prop.getProperty(issueIntervalName));  
  24.         } catch(Exception e){   
  25.             interval=defaultInterval;  
  26.             issueInterval=dufalutIssueInterval;  
  27.         }  
  28.     }  
  29.     public static long getInterval() {  
  30.         return interval;  
  31.     }  
  32.     public static long getIssueInterval() {  
  33.         return issueInterval;  
  34.     }  
  35. }  

               3.常量类Constants.java

Code:
  1. package com.jackyan.practice.util;  
  2.   
  3. public class Constants {  
  4.     public static final String PRIVIEW_LIST_BEAN="priviewListBean";  
  5. }  

              4.事件bean类:PriviewListBean.java(有点难听。。。。)

Code:
  1. package com.jackyan.practice.bean;  
  2.   
  3. import java.util.HashMap;  
  4.   
  5. import com.jackyan.practice.util.Config;  
  6.   
  7. public class PriviewListBean {  
  8.     private HashMap<String, Long> map=null;  
  9.     public PriviewListBean(){  
  10.           
  11.     }  
  12.     public PriviewListBean(HashMap<String,Long> map){  
  13.         this.map=map;  
  14.     }  
  15.     public void setMap(HashMap<String, Long> map) {  
  16.         this.map=map;  
  17.     }  
  18.     //向HashMap中添加新的数据  
  19.     public void addItem(String key){  
  20.         synchronized(map){  
  21.             map.put(key, System.currentTimeMillis());  
  22.         }  
  23.     }  
  24.     //从HashMap中删除指定数据  
  25.     public void removeItem(String key){  
  26.         synchronized(map){  
  27.             map.remove(key);  
  28.         }  
  29.     }  
  30.     //HashMap中是否存在指定的数据  
  31.     public boolean isItemExist(String key){  
  32.         synchronized(map){  
  33.             return map.containsKey(key);  
  34.         }  
  35.     }  
  36.     //更新HashMap中数据的值  
  37.     public void updateItem(String key){  
  38.         synchronized(map){  
  39.             addItem(key);  
  40.         }  
  41.     }  
  42.     //HashMap中指定的数据是否已经准备好(也就是这个用户发帖的冷却时间到没到)  
  43.     public boolean isReady(String key){  
  44.         synchronized(map){  
  45.             if((System.currentTimeMillis()-map.get(key).longValue())>=Config.getIssueInterval()){  
  46.                 return true;  
  47.             }  
  48.             return false;  
  49.         }  
  50.     }  
  51.     //HashMao中,指定用户的发帖冷却时间还剩多少  
  52.     public long needTime(String key){  
  53.         synchronized(map){  
  54.             return (Config.getIssueInterval()-System.currentTimeMillis()+map.get(key).longValue())/1000;  
  55.         }  
  56.     }  
  57. }  

               5.清扫HaspMap的类CleanPriviewListThread.java

Code:
  1. package com.jackyan.practice.util;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Iterator;  
  5. import java.util.Map;  
  6. import com.jackyan.practice.bean.PriviewListBean;  
  7.   
  8. public class CleanPriviewListThread implements Runnable {  
  9.     private HashMap<String, Long> map=null;  
  10.     private PriviewListBean plb=null;  
  11.     public CleanPriviewListThread(HashMap<String, Long> map,PriviewListBean plb){  
  12.         this.map=map;  
  13.         this.plb=plb;  
  14.     }  
  15.     @Override  
  16.     public void run() {  
  17.         Map.Entry<String, Long> temp=null;
  18.         Iterator<Map.Entry<String,Long>> vector=null;
  19.         while(true){  
  20.             try{  
  21.                 Thread.sleep(Config.getInterval());  
  22.             }catch(Exception e ){  
  23.                 e.printStackTrace();  
  24.                 System.exit(0);  
  25.             }  
  26.             synchronized(map){  
  27.                 for(vector=map.entrySet().iterator();vector.hasNext();){  
  28.                     temp=vector.next();  
  29.                     //方便从控制台观察  
  30.                     System.out.println("正在检测"+temp.getKey());  
  31.                     if(plb.isReady(temp.getKey())){  
  32.                         plb.removeItem(temp.getKey());  
  33.                         //方便从控制台观察  
  34.                         System.out.println("移除了"+temp.getKey());  
  35.                     }  
  36.                 }  
  37.             }  
  38.         }  
  39.     }  
  40. }  

                6.Web应用监听器类PriviewListListener.java

Code:
  1. package com.jackyan.practice.listener;  
  2.   
  3. import java.util.HashMap;  
  4. import javax.servlet.ServletContextEvent;  
  5. import javax.servlet.ServletContextListener;  
  6. import com.jackyan.practice.bean.PriviewListBean;  
  7. import com.jackyan.practice.util.CleanPriviewListThread;  
  8. import com.jackyan.practice.util.Constants;  
  9.   
  10. public class PriviewListListener implements ServletContextListener {  
  11.   
  12.     @Override  
  13.     public void contextDestroyed(ServletContextEvent arg0) {  
  14.         arg0.getServletContext().removeAttribute(Constants.PRIVIEW_LIST_BEAN);  
  15.     }  
  16.   
  17.     @Override  
  18.     public void contextInitialized(ServletContextEvent arg0) {  
  19.         HashMap<String, Long> map=new HashMap<String, Long>();  
  20.         PriviewListBean plb=new PriviewListBean(map);  
  21.         arg0.getServletContext().setAttribute(Constants.PRIVIEW_LIST_BEAN, plb);  
  22.         new Thread(new CleanPriviewListThread(map,plb),"cleanPriviesListThread").start();  
  23.     }  
  24. }  

                 7.响应用户发帖请求的Servlet              CheckIssueTime.java

Code:
  1. package com.jackyan.practice.servlet;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9. import javax.servlet.http.HttpSession;  
  10. import com.jackyan.practice.bean.PriviewListBean;  
  11. import com.jackyan.practice.util.Constants;  
  12.   
  13. public class CheckIssueTime extends HttpServlet {  
  14.     private PriviewListBean plb=null;  
  15.     public void init() throws ServletException {  
  16.         plb=(PriviewListBean)getServletContext().getAttribute(Constants.PRIVIEW_LIST_BEAN);  
  17.     }  
  18.   
  19.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  20.             throws ServletException, IOException {  
  21.         response.setContentType("text/xml;charset=utf-8");  
  22.         PrintWriter out=response.getWriter();  
  23.         HttpSession session=request.getSession(true);  
  24.         session.setMaxInactiveInterval(600);  
  25.         String sessionId=session.getId();  
  26.         if(!plb.isItemExist(sessionId)){  
  27.             plb.addItem(sessionId);  
  28.             out.print("<success>允许发帖</success>");  
  29.             out.close();  
  30.             return;  
  31.         }  
  32.         if(!plb.isReady(sessionId)){  
  33.             out.print("<failure>距离下次发帖还有"+plb.needTime(sessionId)+"秒</failure>");  
  34.             out.close();  
  35.             return;  
  36.         }  
  37.         out.println("<success>允许发帖</success>");  
  38.         out.close();  
  39.     }  
  40. }  

                    8.响应用户提交帖子内容的servlet              Issue.java

Code:
  1. package com.jackyan.practice.servlet;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9. import javax.servlet.http.HttpSession;  
  10. import com.jackyan.practice.bean.PriviewListBean;  
  11. import com.jackyan.practice.util.Constants;  
  12.   
  13. public class Issue extends HttpServlet {  
  14.     private PriviewListBean plb=null;  
  15.     public void init() throws ServletException {  
  16.         plb=(PriviewListBean)getServletContext().getAttribute(Constants.PRIVIEW_LIST_BEAN);  
  17.     }  
  18.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  19.             throws ServletException, IOException {  
  20.         response.setContentType("text/xml;charset=utf-8");  
  21.         PrintWriter out=response.getWriter();  
  22.         HttpSession session=request.getSession(false);  
  23.         if(session==null){  
  24.             out.println("<message>非法操作</message>");  
  25.             out.close();  
  26.             return;  
  27.         }  
  28.         String sessionId=session.getId();  
  29.         plb.updateItem(sessionId);  
  30.         out.println("<message>发表成功</message>");  
  31.         out.close();  
  32.     }  
  33. }  

                         9web.xml中的内容

Code:
  1. <servlet>  
  2.   <servlet-name>CheckIssueTime</servlet-name>  
  3.   <servlet-class>com.jackyan.practice.servlet.CheckIssueTime</servlet-class>  
  4. </servlet>  
  5. <servlet>  
  6.   <servlet-name>Issue</servlet-name>  
  7.   <servlet-class>com.jackyan.practice.servlet.Issue</servlet-class>  
  8. </servlet>  
  9.   
  10.   
  11.   
  12. <servlet-mapping>  
  13.   <servlet-name>CheckIssueTime</servlet-name>  
  14.   <url-pattern>/servlet/CheckIssueTime</url-pattern>  
  15. </servlet-mapping>  
  16. <servlet-mapping>  
  17.   <servlet-name>Issue</servlet-name>  
  18.   <url-pattern>/servlet/Issue</url-pattern>  
  19. </servlet-mapping>  
  20.   
  21. <listener>  
  22.     <listener-class>com.jackyan.practice.listener.PriviewListListener</listener-class>  
  23. </listener>  

                        10.显示用的html页面Issue.html

Code:
  1. <html>  
  2.   <head>  
  3.     <title>发表帖子</title>  
  4.     <meta http-equiv="content-type" content="text/html; charset=UTF-8">  
  5.     <script type="text/javascript" src="../js/jquery.js"></script>  
  6.     <script type="text/javascript" src="../js/issue.js"></script>  
  7.     <base href="http://localhost:8080/ControlIssue/">  
  8.   </head>  
  9.     
  10.   <body>  
  11.     <div align="center" ><button onclick="issue();" >发帖</button><span id="wantIM" ></span></div>  
  12.     <div align="center" ><button onclick="submit();" >提交</button><span id="issueM" ></span></div>  
  13.   </body>  
  14. </html>  

                    11脚本文件issue.js

Code:
  1. function issue(){  
  2.     $.ajax({  
  3.         type : "POST" ,  
  4.         url : "servlet/CheckIssueTime",  
  5.         dataType:"xml",  
  6.         success:function(msg){  
  7.             $("#wantIM").text($(msg).children().text());  
  8.         }  
  9.     });  
  10. }  
  11. function submit(){  
  12.     $.ajax({  
  13.         type : "POST" ,  
  14.         url : "servlet/Issue",  
  15.         dataType:"xml",  
  16.         success:function(msg){  
  17.             $("#issueM").text($(msg).children().text());  
  18.         }  
  19.     });  
  20. }  

测试运行:没问题(真的是一次成功,我也不敢相信。。看来还是熟能生巧啊,想当年。。。)

贴几张截图吧:。。。怎么不能加图片了。。。

PS:真的想做一个详细的说明文档,但是实在是没有时间,一会还得学英语。。。如果有不同意见的地方可一定要告诉我,我会及时改正,免得误人子弟。

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值