在我的个人博客项目中,有这样的需求:利用seesion监听器统计在线人数和网站访问量情况。这个需求在我看来,应该有两种思路:
1. 直接在监听器定义四个变量存储数据
2. 在项目数据库中设计一张数据表来专门存储数据
下面我从这两个思路分别来说明一下:
直接在监听器定义四个变量存储数据
首先在session监听器中定义4个变量:
当前在线用户数(count)、总访问量(all)、今日访问量(today)、今日日期(day)
然后session监听器SessionCounter实现了HttpSessionListener接口,所以类中包含了sessionCreated以及sessionDestroyed方法, sessionCreated方法是在session创建的时候执行,而sessionDestroyed方法则是在session销毁时执行。在session创建时对当前在线用户数 (count)、总访问量(all)的值进行++操作,然后通过对比今日日期(day) 的值以及直接获取到的日期,对今日访问量(today)进行不同的操作即可。所 以具体的实现代码如下:
实现代码:
package com.pwt.utils;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.Date;
/**
* count 当前在线用户数
* all 总访问量
* today 今日访问量
* day 今日日期
*/
@Component
public class SessionCounter implements HttpSessionListener {
private static Integer count = 0;
private static long today = 0;
private static long all = 0;
private static int day = 0;
//session创建
@Override
public void sessionCreated(HttpSessionEvent arg0) {
ServletContext context = arg0.getSession().getServletContext();
count = (Integer) context.getAttribute("onlineCount");
if (count == null) {
count = new Integer(1);
} else {
int co = count.intValue();
count = new Integer(co + 1);
}
// 保存人数
context.setAttribute("onlineCount", count);
all++;
Date date=new Date();
int tday=date.getDate();
//如果日期发生变化则将today置为1,否则将today加1
if(tday!=day){
day=tday;
today=1;
}else{
today++;
}
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
ServletContext context = arg0.getSession().getServletContext();
count = (Integer) context.getAttribute("onlineCount");
int co = count.intValue();
count = new Integer(co - 1);
count = count >= 0 ? count : 0;
context.setAttribute("onlineCount", count);
}
public static Integer getCount() {
return count;
}
public long getAll(){
return all;
}
public long getToday(){
return today;
}
}
在项目数据库中设计一张数据表来专门存储数据
经过我的深思熟虑,我就想把在线人数存储在session中,而今日访问量和总访问量则存储在mysql数据库中。所以我的数据表字段设计如下:
visit_id:某天访问量的id
visit_date:访问日期
visit_count:某天的访问量
到此,数据库设计完成,你们可能会说怎么没有存储总访问量的字段呢?因为我是通过数据库的sum函数来对每条数据的visit_count字段进行求和,从而得到总的访问量。
具体代码如下:
package com.pwt.utils;
import com.pwt.model.vo.VisitTotalVo;
import com.pwt.service.IVisitTotalService;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author pwt
*/
@Component
public class SessionCounter implements HttpSessionListener {
@Autowired
private IVisitTotalService iVisitTotalService;
private static Map sessionMap = new HashMap();
public SessionCounter() {}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
ServletContext context = arg0.getSession().getServletContext();
Date date = new Date();
boolean flag = true;
for(Object key : sessionMap.keySet()){
if(key.toString().equals(arg0.getSession().getId())){
flag = false;
}
}
if(flag){
sessionMap.put(arg0.getSession().getId(), arg0.getSession());
}
context.setAttribute("onlineCount", sessionMap.size());
VisitTotalVo visitTotalVo = new VisitTotalVo();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {
visitTotalVo.setVisitDate(new java.sql.Date(sdf.parse(sdf.format(date)).getTime()));
iVisitTotalService.queryVisitTotalByVisitDate(visitTotalVo);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
boolean flag = false;
for(Object key : sessionMap.keySet()){
if(key.toString().equals(arg0.getSession().getId())){
flag = true;
}
}
if(flag){
sessionMap.remove(arg0.getSession().getId());
}
ServletContext context = arg0.getSession().getServletContext();
context.setAttribute("onlineCount", sessionMap.size());
}
}
从代码中可以看到,我直接在监听器中调用了service层的方法,如果你直接这样运行项目的话,项目会出现空指针异常,原因是监听器属于sevlet容器,不属于 Spring 框架的管理范围,拿不到spring注解注入的bean。要想让项目不会报错,我是这样解决的:
代码:
package com.pwt.utils;
import com.pwt.service.IVisitTotalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class InjectServiceUtil {
@Autowired
private IVisitTotalService iVisitTotalService;
@PostConstruct
public void init(){
InjectServiceUtil.getInstance().iVisitTotalService = this.iVisitTotalService;
}
/**
* 实现单例 start
*/
private static class SingletonHolder {
private static final InjectServiceUtil INSTANCE = new InjectServiceUtil();
}
private InjectServiceUtil (){}
public static final InjectServiceUtil getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* 实现单例 end
*/
public static IVisitTotalService getIVisitTotalService(){
return InjectServiceUtil.getInstance().iVisitTotalService;
}
}
修改监听器如下:
package com.pwt.utils;
import com.pwt.model.vo.VisitTotalVo;
import com.pwt.service.IVisitTotalService;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author pwt
*/
@Component
public class SessionCounter implements HttpSessionListener {
private static IVisitTotalService iVisitTotalService;
private static Map sessionMap = new HashMap();
public SessionCounter() {}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
ServletContext context = arg0.getSession().getServletContext();
Date date = new Date();
boolean flag = true;
for(Object key : sessionMap.keySet()){
if(key.toString().equals(arg0.getSession().getId())){
flag = false;
}
}
if(flag){
sessionMap.put(arg0.getSession().getId(), arg0.getSession());
}
context.setAttribute("onlineCount", sessionMap.size());
VisitTotalVo visitTotalVo = new VisitTotalVo();
iVisitTotalService = InjectServiceUtil.getIVisitTotalService();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
try {
visitTotalVo.setVisitDate(new java.sql.Date(sdf.parse(sdf.format(date)).getTime()));
iVisitTotalService.queryVisitTotalByVisitDate(visitTotalVo);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
boolean flag = false;
for(Object key : sessionMap.keySet()){
if(key.toString().equals(arg0.getSession().getId())){
flag = true;
}
}
if(flag){
sessionMap.remove(arg0.getSession().getId());
}
ServletContext context = arg0.getSession().getServletContext();
context.setAttribute("onlineCount", sessionMap.size());
}
}
这样项目运行就不会再出现空指针异常。最后两种思路还需要配置web.xml文件:
<listener>
<listener-class>com.pwt.utils.SessionCounter</listener-class>
</listener>
<!-- session配置过期时间 -->
<session-config>
<session-timeout>3</session-timeout>
</session-config>