Java - 用户在线的数据库实现方法和内存实现方法

一,数据库实现方法:(实现思路:基于Struts2.0的拦截器)
0,流程:struts.xml ->  ApplicationContext.xml  ->  LoginInterceptor.java ->  OnlineAction.java ->  Online.ftl
1,
struts.xml:
        <action name="index" class="indexAction">
            <result name="success" type="freemarker">/WEB-INF/ftl/OnLine.ftl</result>
        </action>
2,
ApplicationContext.xml:
    <bean id="indexAction" class="cn.company.OnlineAction">
        <property name="configService" ref="configService" />
        <property name="onlineService" ref="onlineService" />
    </bean>
 

    <!-- 定期清理过期的在线用户 -->
    <bean id="onlineClear" class="cn.
company.OnLineClearTimerTask">
        <property name="onlineService" ref="onlineService" />
    </bean>
    <bean id="onlineClearTimerTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
        <property name="delay">
            <value>10800000</value><!-- 3小时 * 60分钟 * 60秒 * 1000毫秒 = 10800000毫秒 -->
        </property>
        <property name="period">
            <value>10800000</value>
        </property>
        <property name="timerTask">
            <ref local="onlineClear" />
        </property>
    </bean>
    <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
        <property name="scheduledTimerTasks">
            <list>
                <ref local="onlineClearTimerTask" />
            </list>
        </property>
    </bean>

3,
LoginInterceptor.java
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        Object action = actionInvocation.getAction();
        // log.info("登录拦截器将拦截:" + action.getClass().getName().substring(24));
        ActionContext ac = actionInvocation.getInvocationContext();        
        ServletContext servletContext = (ServletContext) ac.get(ServletActionContext.SERVLET_CONTEXT);
        WebApplicationContext wc = WebApplicationContextUtils.getWebApplicationContext(servletContext);        
        if (wc == null) {
            log.error("找不到Spring的配置文件:ApplicationContext.xml");
        } else {
            String username = "";
             UserSession us = (UserSession) ac.getSession().get(Constant.USER_SESSION_KEY);            
            if (ac.getSession().get(User.SESSION_LOGIN_NAME_KEY) == null) {
                if (us == null) {
                    username = (String) ac.getSession().get(User.SESSION_LOGIN_NAME_KEY);
                    // log.info("当前用户第一次进来:" + username);
                } else {
                    username = ((UserSession) ac.getSession().get(Constant.USER_SESSION_KEY)).getUserName();
                    // log.info("当前登录用户:" + username);
                }
            }            
            if (us == null) {
                 OnLineService onlineService = (OnLineService) wc.getBean("onlineService");
                long nowTime = System.currentTimeMillis();
                // log.info("添加一个游客:Guest@" + nowTime + "(" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS:%1$tL", nowTime) + ")");
                 UserOnLine userOnLine = new UserOnLine();
                userOnLine.setUserId(0);
                userOnLine.setUserName("Guest@" + nowTime);
                userOnLine.setOnlineTime(nowTime);
                onlineService.saveUserOnLine(userOnLine);
                // 加入UserSession
                us = new UserSession();
                us.setUserName(userOnLine.getUserName());
                us.setLastActiveTime(nowTime);
                ac.getSession().put(Constant.USER_SESSION_KEY, us);
            } else {
                OnLineService onlineService = (OnLineService) wc.getBean("onlineService");
                if (ac.getSession().get(User.SESSION_LOGIN_NAME_KEY) == null) {
                    username = ((UserSession) ac.getSession().get(Constant.USER_SESSION_KEY)).getUserName();
                } else {
                    username = (String) ac.getSession().get(User.SESSION_LOGIN_NAME_KEY);
                }
                UserOnLine userOnLine = onlineService.findUserOnLineByUserName(username);
                if (userOnLine != null) {
                    //log.info("OnlineTime:" + userOnLine.getOnlineTime());
                }
            }
        }        
        // 继续执行 Action
        return actionInvocation.invoke();
    }
4, OnlineAction.java:
public class OnlineAction extends ManageBaseAction {
    /** 配置服务 */
    private ConfigService configService;
    /** 在线服务 */
    private OnLineService onlineService;
    /** 在线用户统计服务 */
    private StatService statService;
    /** 在线用户列表 */
    private List<UserOnLine> onlineList = new ArrayList<UserOnLine>();
    /** 在线会员数 */
    private long onlineUserNum = 0;
    /** 在线游客数 */
    private long onlineGuestNum = 0;
    /** 最高在线人数 */
    private String onlineHighest;
    /** 最高在线人数的出现时间 */
    private String onlineAppear;

    @Override
    protected String execute(String cmd) throws Exception {
        // 从游客变成注册用户
        String username = "";
        HttpSession session = request.getSession();
        if (session.getAttribute(User.SESSION_LOGIN_NAME_KEY) == null) {
            username = ((UserSession) session.getAttribute(Constant.USER_SESSION_KEY)).getUserName();
        } else {
            String guestName = ((UserSession) session.getAttribute(Constant.USER_SESSION_KEY)).getUserName();
            // log.info("登录前的游客名:" + guestName);
            if (guestName != null && !"".equals(guestName)) {
                UserOnLine userOnLine = onlineService.findUserOnLineByUserName(guestName);
                onlineService.removeUserOnLine(userOnLine);
            }
            username = (String) session.getAttribute(User.SESSION_LOGIN_NAME_KEY);
        }
        // log.info("当前在首页的用户:" + username);
        long optTime = System.currentTimeMillis() - getTime();
        // log.info("前五分钟:" + optTime + "(" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS:%1$tL", optTime) + ")");
        onlineUserNum = onlineService.getOnLineUesrNum(optTime);
        // log.info("在线会员:" + onlineUserNum);
        onlineGuestNum = onlineService.getOnLineGuestNum(optTime);
        // log.info("在线游客:" + onlineGuestNum);
        long tmpHighest = onlineUserNum + onlineGuestNum;
        // log.info("当前最高在线人数:" + tmpHighest);
        int _h = Integer.valueOf(String.valueOf(tmpHighest));        
        UserOnLineStat userOnLineStat = statService.getUserOnLineStat();
        // log.info("系统中的最高在线人数:" + userOnLineStat.getHighest());        
        if (tmpHighest > userOnLineStat.getHighest()) {
            userOnLineStat.setHighest(_h);
            userOnLineStat.setAppearTime(String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", new Date()));
            statService.updateUserOnLineStat(userOnLineStat);
            // 从更新的数据库中取最新的数据
            onlineHighest = String.valueOf(userOnLineStat.getHighest());
            // log.info("最高在线:" + onlineHighest);
            onlineAppear = userOnLineStat.getAppearTime();
            // log.info("出现时间:" + onlineAppear);    
        } else {
            onlineHighest = String.valueOf(userOnLineStat.getHighest());
            // log.info("最高在线:" + onlineHighest);
            onlineAppear = userOnLineStat.getAppearTime();
            // log.info("出现时间:" + onlineAppear);
        }
        // 当前在线用户列表
        onlineList = onlineService.findOnLineUser(optTime);
        /*
        SimpleMailMessage msg = new SimpleMailMessage(this.message);
        msg.setTo("[email protected]");
        msg.setSentDate(new Date());
        msg.setText("当前在线用户:" + username + " [" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS:%1$tL", new Date()) + "]" + "[" + request.getRemoteAddr() + "]");
        try {
            mailSender.send(msg);
        } catch(MailException ex) {
            log.error(ex.getMessage());
            log.info("邮件发送失败!");
        }*/
        return SUCCESS;
    }

    /**
     * 获取系统配置的超时时间
     * 
     * @return
     */
    private long getTime() {
        return Integer.valueOf(getConfigValue("site.user.online.time")) * 1 * 60 * 1000; // 5 * 1分钟 * 60秒 1000毫秒 = 300000毫秒 = 5分钟
    }    
    /**
     * 根据配置 Name 得到相应的 Value
     */
    private String getConfigValue(String string) {
        return (String) this.configService.getConfigure().getValue(string);
    }
    /** 配置服务的set方法 */
    public void setConfigService(ConfigService configService) {
        this.configService = configService;
    }
    /** 在线服务的set方法 */
    public void setOnlineService(OnLineService onlineService) {
        this.onlineService = onlineService;
    }
    /** 在线用户统计服务的set方法 */
    public void setStatService(StatService statService) {
        this.statService = statService;
    }
    public List<UserOnLine> getOnlineList() {
        return onlineList;
    }
    public long getOnlineUserNum() {
        return onlineUserNum;
    }
    public long getOnlineGuestNum() {
        return onlineGuestNum;
    }
    public String getOnlineHighest() {
        return onlineHighest;
    }
    public String getOnlineAppear() {
        return onlineAppear;
    }
}
5, Online.ftl
<div>
    注册用户: ${onlineUserNum!0},游客: ${onlineGuestNum!0},最高在线人数: ${onlineHighest!0},发生在: ${onlineAppear!?html}</div>
</div>
<div>
    <#if onlineList??>
        <#list onlineList as online>
            <#assign u = Util.userById(online.userId)>
            <a href="${SiteUrl}go.py?loginName=${u.loginName!}">${u.trueName!}</a>
        </#list> 
    </#if>
</div>
6,Util.userById:
    public class UserById implements TemplateMethodModel {
        public Object exec(List args) throws TemplateModelException {
            if (args == null || args.size() == 0)
                throw new TemplateModelException("userById 需要 1 个整数型参数");
            String idstr = args.get(0).toString();
            if (ParamUtil.isInteger(idstr) == false)
                throw new TemplateModelException("userById 需要 1 个整数型参数");
            // 得到用户标识参数
            int id = Integer.parseInt(idstr);
            User u = jtar_ctxt.getUserService().getUserById(id);
            return u == null ? NOTHING : u;
        }
    }
7,OnlineDaoHibernate.java
    public UserOnLine findUserOnLineByUserName(String userName) {
        List<UserOnLine> list = this.getSession().createQuery(FIND_USERONLINE_BY_USERNAME).setString(0, userName).list();
        return (null == list || list.isEmpty()) ? null : (UserOnline) list.get(0);
    }
8,Constant.java
public class Constant {
    public static final String USER_SESSION_KEY = "user_session";
}
9,UserSession
public class UserSession implements Serializable {
    /** 用户名 */
    private String userName;
    /** 上次活动时间 (具体的时间格式) */
    private long lastActiveTime = 0;    
    /** 已经活动时间 (当前系统时间-上次活动时间=差值) */
    private long addedOnlineTime = 0;    
    /**
     * Default Constructor
     */
    public UserSession () {
        // 
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public long getLastActiveTime() {
        return lastActiveTime;
    }
    public void setLastActiveTime(long lastActiveTime) {
        this.lastActiveTime = lastActiveTime;
    }
    public long getAddedOnlineTime() {
        return addedOnlineTime;
    }
    public void setAddedOnlineTime(long addedOnlineTime) {
        this.addedOnlineTime = addedOnlineTime;
    }    
}
10,UserOnLine.java
public class UserOnLine implements Serializable {
    // 对象标识
    private int Id;    
    // 用户Id,如为游客,则可以为空
    private Integer userId;    
    // 用户名,如为游客,则可以为:Guest
    private String userName;    
    // 时间的毫秒数
    private long onlineTime;    

    /** Default Construct */
    public UserOnLine() {
        // 
    }

    public int getId() {
        return Id;
    }
    public void setId(int id) {
        Id = id;
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public long getOnlineTime() {
        return onlineTime;
    }
    public void setOnlineTime(long onlineTime) {
        this.onlineTime = onlineTime;
    }    
}


二,内存实现方法:(实现思路:基于 Session Application 的作用范围)
1,web.xml:
    <!-- 监听 session 中的在线用户 -->
    <listener>
        <listener-class>cn.company.OnlineListener</listener-class>
    </listener>
2,
OnlineListener.java:
public class OnlineListener implements HttpSessionListener {
    @Override
    // 监听 Session 的创建
    public void sessionCreated(HttpSessionEvent se) {
        // Do Nothing
    }
    @Override
    // 监听 Session 的销毁,在 session.invalidate() 时自动触发
    public void sessionDestroyed(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        UserSession us = (UserSession) session.getAttribute(Constant.USER_SESSION_KEY);
        // session.getServletContext() 是全局的 Application
,这个是重点!
        List onlineList = (List) session.getServletContext().getAttribute("onlineList");
        if (null != onlineList && 0 < onlineList.size() && us != null) {
            onlineList.remove(us);
        }
    }
}

3,
LoginInterceptor.java
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        Object action = actionInvocation.getAction();
        String sessionId = ServletActionContext.getRequest().getSession().getId();
        
        // 不拦截 AdminStatAction
        if (action instanceof AdminStatAction) {
            return actionInvocation.invoke();
        }

        ActionContext ac = actionInvocation.getInvocationContext();        
        UserSession us = (UserSession) ac.getSession().get(Constant.USER_SESSION_KEY);
        
        if (null == us) {
            long nowTime = System.currentTimeMillis();
            // 往用户Session对象中放入一个游客对象
            us = new UserSession();
            us.setSessionId(sessionId);
            us.setUsername("_" + nowTime);
            ac.getSession().put(Constant.USER_SESSION_KEY, us);
        } else {
            // 系统中的用户名
            String username = "";
            if (null == ac.getSession().get(User.SESSION_LOGIN_NAME_KEY)) {
                // 如果没有从Session中获取到用户名(几乎不可能),直接将游客Session赋给用户名
                username = us.getUsername();
            } else {
                username = (String) ac.getSession().get(User.SESSION_LOGIN_NAME_KEY);
            }
            // 从游客变成注册用户
            // 删除之前的游客session,如果还是游客、或已登录用户再次访问首页的就不必重复删除
            us.setUsername(username);
        }        
        // 继续执行 Action
        return actionInvocation.invoke();
    }
4,OnlineAction.java:
public class OnlineAction extends ManageBaseAction {    
    // 游客列表
    private ArrayList guestList = new ArrayList();    
    // 注册用户列表
    private ArrayList userList = new ArrayList();

    /* (non-Javadoc)
     * 
     * @see cn.edustar.jitar.action.ManageBaseAction#execute(java.lang.String)
     */
    @Override
    protected String execute(String cmd) throws Exception {
        HttpSession session = request.getSession();
        UserSession us = (UserSession) session.getAttribute(Constant.USER_SESSION_KEY);        
        // session.getServletContext() 是全局的 Application,这个是重点!
        List onlineList = (List) session.getServletContext().getAttribute("onlineList");
        if (null == onlineList) {
            onlineList = new ArrayList();
            session.getServletContext().setAttribute("onlineList", onlineList);
        } else {
            // 游客session不为空,因为可能是已登录用户再次访问首页
            if (null != us) {
                onlineList.remove(us);
            }
        }
        onlineList.add(us);

        guestList.clear();
        userList.clear();
//        for (Iterator iterator = onlineList.iterator(); iterator.hasNext();) {
//            UserSession _us = (UserSession) iterator.next();
//            if (null != _us) {
//                if (_us.getUsername().startsWith("_")) {
//                    guestList.add(_us.getUsername());
//                } else {
//                    userList.add(_us.getUsername());
//                }
//            }
//        }        
        for (Object object : onlineList) {
            UserSession u = (UserSession) object;
            if (null != u) {
                if (u.getUsername().startsWith("_")) {
                    guestList.add(u.getUsername());
                } else {
                    userList.add(u.getUsername());
                }
            }
        }        
        return SUCCESS;
    }

    public ArrayList getGuestList() {
        return guestList;
    }
    public ArrayList getUserList() {
        return userList;
    }
}
5,Online.ftl:
<div>
    <#assign onlineStat = Util.getUserOnLineStat(userList?size + guestList?size)>
    当前在线总人数:${userList?size + guestList?size}
    注册用户:${userList?size!0}
    游客:${guestList?size!0}
    最高在线总人数:${onlineStat.highest!0}
    发生在:${onlineStat.appearTime!?html}
</div>
<#if userList??>
    <#list userList as user>
            <#assign u = Util.userByName(user)>
            <a href="${SiteUrl}go.py?loginName=${u.loginName!}">${u.trueName!}</a>
    </#list> 
</#if>
6,Util.userByName:
    public class UserByName implements TemplateMethodModel {
        @SuppressWarnings("unchecked")
        public Object exec(List args) throws TemplateModelException {
            // 判断参数.
            if (args == null || args.size() == 0)
                throw new TemplateModelException("userByName 需要 1 个字符串参数");            
            String loginName = args.get(0).toString();
            User u = getUserService().getUserByLoginName(loginName);
            return u == null ? NOTHING : u;
        }
    }
7,Util.getUserOnLineStat:
    public class getUserOnLineStat implements TemplateMethodModel {
        @SuppressWarnings("rawtypes")
        public Object exec(List args) throws TemplateModelException {
            int count = 0;
            // 判断参数
            if (null == args || 0 == args.size()) {
                count = 1;
            } else {
                count = Integer.valueOf((String) args.get(0));
            }
            // System.out.println("当前在线人数:" + count);
            UserOnLineStat us = (UserOnLineStat) jtar_ctxt.getCacheProvider().getCache("online").get("online");
            OnlineManage onlineManage = jtar_ctxt.getOnlineManage();
            if (null == us) {
                us = onlineManage.getUserOnLineStat();
                // 放入缓存
                jtar_ctxt.getCacheProvider().getCache("online").put("online", us);
            } else {
                // 如果当前在线人数大于数据库(此刻是缓存)中的人数,则更新数据库,并更新缓存
                if (count > us.getHighest()) {
                    // 更新数据库
                    onlineManage.updateOnLineStat(count);
                    // 更新缓存
                    jtar_ctxt.getCacheProvider().getCache("online").put("online", onlineManage.getUserOnLineStat());
                }
            }
            return us;
        }
    }
8,ehcache.xml:
  <cache name="online" maxElementsInMemory="1024" eternal="false" timeToIdleSeconds="600"  timeToLiveSeconds="3600" overflowToDisk="true" />
9,系统启动的时候将统计信息放到缓存中:cacheService.put("online", getUserOnLineStat());

    public UserOnLineStat getUserOnLineStat() {
        List<UserOnLineStat> list = this.getSession().createQuery("FROM UserOnLineStat").list();
        if (null == list || list.isEmpty()) {
            return new UserOnLineStat();
        } else {
            return ((UserOnLineStat) list.get(0));
        }
    }

10,更新数据库:
    public void updateOnLineStat(int count) {
        String hql = "UPDATE UserOnLineStat SET highest = ?, appearTime = '" + String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", new Date()) + "' WHERE id = 1";
        this.getSession().createQuery(hql).setInteger(0, count).executeUpdate();    
        this.getSession().flush();
    }

你可能感兴趣的:(Java - 用户在线的数据库实现方法和内存实现方法)