application对象作为JSP的9大内置对象之一,实现了用户间数据的共享,可存放全局变量。它开始于服务器的启动,直到服务器的关闭,在此期间,此对象将一直存在;这样在用户的前后连接或不同用户之间的连接中,可以对此对象的同一属性进行操作;在任何地方对此对象属性的操作,都将影响到其他用户对此的访问。服务器的启动和关闭决定了application对象的生命。它是ServletContext类的实例。
基于上述理由,将点击量作为全局变量,存在application对象中,统计全网的点击量。
1、在web.xml中自定义监听器
xxx.xxx.web.listener.InitListener
2、在xxx.xxx.web.listener.InitListener的contextInitialized()方法中设置全局变量,用来存点击量,存入ServletContext域对象(application)中,在contextDestroyed()方法中更新数据库中的点击量字段,并移除全局变量。
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* @ClassName: MyServletContextListener
* @Description:InitListener类实现了ServletContextListener接口,
* 因此可以对ServletContext对象的创建和销毁这两个动作进行监听。
*/
public class InitListener implements ServletContextListener {
private static ApplicationContext applicationContext = null;
public void contextInitialized(ServletContextEvent sce) {
//System.out.println("ServletContext对象创建");
//初始化 ApplicationContext 对象
applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext());
//设置点击量
sce.getServletContext().setAttribute("increaseCountMap",newConcurrentHashMap());
}
public void contextDestroyed(ServletContextEvent sce) {
//System.out.println("ServletContext对象销毁");
WebApplicationContext webApplicationContext= ContextLoader.getCurrentWebApplicationContext();
//获取业务层service Bean
CourseServiceImpl courserService = (CourseServiceImpl)webApplicationContext.getBean("CourseServiceImpl");
courserService.updateRateUtilization();//更新点击量
sce.getServletContext().removeAttribute("increaseCountMap");//移除全局变量--点击量
}
//用于那些非控制层中使用直接获取到的Spring Bean的获取,如接口
public static ApplicationContext getApplicatonContext(){
returnapplicationContext ;
}
}
3、在CourseController.java控制器中:
private static Object obj = new Object();
static
ConcurrentHashMap
increaseCountMap= new
ConcurrentHashMap();
@RequestMapping(value="/showCourseDetail.do",method=RequestMethod.GET)
public ModelAndView showCourseDetail(HttpServletRequest request){
//其他内容忽略,至关注点击量的业务处理
String courseId = null;
synchronized(obj){//加锁防止并发
courseId = request.getParameter("courseId");
calClickRate(request,courseId );
}
//............
return new ModelAndView("/page/courseDetail.jsp");
}
private void calClickRate(HttpServletRequest request,String courseIdStr){
Integer courseId = Integer.valueOf(courseIdStr);
increaseCountMap = (ConcurrentHashMap)request.getSession().getServletContext().
getAttribute("increaseCountMap");
Iterator it =increaseCountMap.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer,AtomicInteger> me = (Map.Entry<Integer,AtomicInteger>)it.next();
if(me.getKey().intValue() == courseId.intValue()){
increaseCountMap.putIfAbsent(courseId,new AtomicInteger(me.getValue().getAndIncrement()));
}else{
increaseCountMap.putIfAbsent(courseId,new AtomicInteger(1));
}
}
if(!it.hasNext()){
increaseCountMap.putIfAbsent(courseId,new
AtomicInteger
(1));
}
request.getSession().getServletContext().setAttribute("increaseCountMap",increaseCountMap);
}
4、在CourseServiceImpl.java中 更新点击量
public void updateRateUtilization(){
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
ConcurrentHashMap countMap =(ConcurrentHashMap)
webApplicationContext .getServletContext().getAttribute("increaseCountMap");
Iterator it =countMap.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer,AtomicInteger> me = (Map.Entry<Integer,AtomicInteger>)it.next();
courseMapper.updateCourseClickRate(me.getKey(),me.getValue().intValue());//更新数据库
}
webApplicationContext.getServletContext().setAttribute("increaseCountMap",
new ConcurrentHashMap());
}
//======================
updateCourseClickRate()对应的sql:
update t_course set click_rate = #{clickRate} + IFNULL(click_rate,0) where id = #{courseId}
5、最后使用定时任务,每10分钟一次,更新点击量
CourseServiceImpl.java-->updateRateUtilization()