网站用于记录浏览数的源码

包括软件、新闻和话题以及代码在内的信息,用户访问过一次就会给访问次数字段增1。这个操作是异步的,访问的时候只是将数据在内存中保存,每隔固定时间将这些数据写入数据库。 有两个注意实现(详看代码中的注释): 1. 当tomcat停止时而且尚未达到运行周期时将剩余数据写回 2. 必须显式关闭数据库连接,因为线程的运行不受Filter控制,无法自动关闭连接,如果不关闭会导致连接泄漏 这个类提供了一个main方法可直接运行,需要用到此类的时候,只需要将自己的写数据库逻辑填充上即可。 具体使用方法请看 main 函数。
package net.oschina.service;

import java.util.*;
import java.util.concurrent.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 访问统计服务
 * @author Winter Lau
 * @date 2011-1-6 下午03:49:40
 */
public class VisitStatService extends TimerTask {

	private final static Log log = LogFactory.getLog(VisitStatService.class);
	private static boolean start = false;
	private static VisitStatService daemon;
	private static Timer click_timer;
	private final static long INTERVAL = 60 * 1000;
	
	/**
	 * 支持统计的对象类型
	 */
	private final static byte[] TYPES = new byte[]{
		0x01,0x02,0x03,0x04,0x05
	};
	
	//内存队列
	private final static ConcurrentHashMap<Byte, ConcurrentHashMap<Long, Integer>> queues = 
		new ConcurrentHashMap<Byte, ConcurrentHashMap<Long, Integer>>(){{
			for(byte type : TYPES)
				put(type, new ConcurrentHashMap<Long, Integer>());
		}};

	/**
	 * 记录访问统计
	 * @param type
	 * @param obj_id
	 */
	public static void record(byte type, long obj_id) {
		ConcurrentHashMap<Long, Integer> queue = queues.get(type);
		if(queue != null){
			Integer nCount = queue.get(obj_id);
			nCount = (nCount==null)?1:nCount+1;
			queue.put(obj_id, nCount.intValue());
			System.out.printf("record (type=%d,id=%d,count=%d)\n",type,obj_id,nCount);
		}
	}

	/**
	 * 启动统计数据写入定时器
	 * @param ctx
	 */
	public static void start() {
		if(!start){
			daemon = new VisitStatService();
			click_timer = new Timer("VisitStatService", true);
			click_timer.schedule(daemon, INTERVAL, INTERVAL);//运行间隔1分钟
			start = true;
		}
		log.info("VisitStatService started.");
	}

	/**
	 * 释放Service
	 */
	public static void destroy(){
		if(start){
			click_timer.cancel();
			start = false;
		}
		log.info("VisitStatService stopped.");
	}
	
	@Override
	public void run() {
		for(byte type : TYPES){
			ConcurrentHashMap<Long, Integer> queue = queues.remove(type);
			queues.put(type, new ConcurrentHashMap<Long, Integer>());
			try{
				_flush(type, queue);
			}catch(Throwable t){
				log.fatal("Failed to flush click stat data.", t);
				//此处发送异常报告
			}finally{
				//此处关闭数据库连接
			}
		}
	}
	
	@Override
	public boolean cancel() {
		boolean b = super.cancel();
		//写回剩余数据,Tomcat停止时不会丢失数据
		this.run();
		return b;
	}
	
	/**
	 * 写访问统计数据到数据库
	 * @param type
	 * @param queue
	 */
	private void _flush(byte type, ConcurrentHashMap<Long, Integer> queue){
		if(queue.size()==0)
			return ;
		switch(type){
			//数据写入数据库....
		}
		System.out.printf("Flush to database: type=%d\n", type);
	}

	/**
	 * 测试
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		start();
		for(int i=0;i<10;i++)
			new Timer("OfferTask_"+(i+1), false).schedule(
					new TimerTask(){
						private Random rnd = new Random(System.currentTimeMillis());			
						@Override
						public void run() {
							record(TYPES[rnd.nextInt(TYPES.length)],rnd.nextInt(10));
						}		
					}, 
				0, 1000
			);
	}
	
}

转载于:https://my.oschina.net/u/265943/blog/292856

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值