这个稍微比上个版本做得完善了一点,用了JavaBean来封装用户信息,添加了一个管理踢用户的功能。
上一个的用户访问量是通过监听request来统计的,在这个实例中,我们也可以通过过滤器来实现统计网站访问量。
直接看源码吧,感觉没多少要讲的,我习惯把解释写在代码中。
部分源码
index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>在线人信息管理与统计</title>
</head>
<body>
<h2>在线人信息管理与统计</h2>
<c:if test="${empty sessionScope.user}" var="boo">
<h3>会员登录:</h3>
<form action='<c:url value='/LoginServlet'></c:url>' method="post">
姓名:<input type='text' name="name"><br /> <input type="submit"
value="注册">
</form>
</c:if>
<c:if test="${!boo}">
亲爱的${user.name}
<c:if test="${user.admin}" var="bo">
-管理员
</c:if>
<c:if test="${!bo}">
-会员
</c:if>
,欢迎来到...<br />
</c:if>
<br />
<a href="<c:url value='/servlet/ShowServlet'/>">显示所有在线用户</a>
<br />
<a href="<c:url value='/servlet/LogOutServlet'/>">安全退出</a>
<br/>网站访问量:${count}
</body>
</html>
MyServletContextListener
这个就是实现把访问量持久化的监听器实现类:
package cn.hncu.listeners;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener{
@Override
public void contextInitialized(ServletContextEvent sce) {
//从服务器硬盘把之前存储的点击量数据读取出来
ServletContext sct = sce.getServletContext();
String path = sct.getRealPath("/count.txt");
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line = br.readLine();
Integer count = Integer.valueOf(line);
sct.setAttribute("count", count);
} catch (Exception e) {
//如果出异常了,我们认为文件还不存在,服务器第一次启动
e.printStackTrace();
sct.setAttribute("count",new Integer(0));
}
}
//关闭服务器时
@Override
public void contextDestroyed(ServletContextEvent sce) {
//把当前servletContext容器中存储的点击量数据 永久化到 服务器硬盘
ServletContext sct = sce.getServletContext();
String path = sct.getRealPath("/count.txt");
try {
PrintWriter pw = new PrintWriter(path);
pw.write(""+sct.getAttribute("count"));
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
CharsetFilter
实现统计访问量和全站编码的过滤器
package cn.hncu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class CharsetFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
//获取该用户的ip,存储到它的session对象中
HttpServletRequest req = (HttpServletRequest) request;
if(req.getSession().getAttribute("ip")==null){
req.getSession().setAttribute("ip", req.getRemoteAddr());
//这里的req和request是同一个对象!!!
//所以传过去的参数还可以是request
}
//new一个线程统计访问量
new MyThread(request.getServletContext()).start();
//放行
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
class MyThread extends Thread{
private ServletContext servletContext =null;
private static Object boj = new Object();
public MyThread(ServletContext servletContext) {
this.servletContext = servletContext;
}
@Override
public void run() {
synchronized (boj) {
servletContext.setAttribute("count",(Integer)servletContext.getAttribute("count")+1);
}
}
}
LoginFilter
用户访问其他页面时进行的权限过滤:
如果你没有登陆,就不给你权限去访问除主页外的其他页面。
package cn.hncu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(req.getSession().getAttribute("user")==null){
HttpServletResponse resp = (HttpServletResponse) response;
resp.sendRedirect(req.getContextPath()+"/index.jsp");
}else{//放行
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
MySessionListener
有用户来访问时,我们就通过监听器去监听session的创建与销毁,在这里,我们认为一个session就是一个用户!
package cn.hncu.listeners;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MySessionListener implements HttpSessionListener{
@Override
public void sessionCreated(HttpSessionEvent se) {
Map<String, HttpSession> onLines = (Map<String, HttpSession>) se.getSession().getServletContext().getAttribute("onLines");
if(onLines==null){//第一个来访问的
onLines = Collections.synchronizedMap(new HashMap<String, HttpSession>() );//使用同步技术的Map
se.getSession().getServletContext().setAttribute("onLines", onLines);
}
onLines.put(se.getSession().getId(), se.getSession());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
Map<String, HttpSession> onLines = (Map<String, HttpSession>) se.getSession().getServletContext().getAttribute("onLines");
//这里也要防范好!多线程,多个管理同时踢一个人的时候,如果不防范就会出问题
if(onLines.containsKey( se.getSession().getId() )){
onLines.remove( se.getSession().getId() );
}
}
}
LoginServlet
用于判断用户登录与设置管理员的servlet。
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hncu.domain.User;
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
if(name!=null && name.trim().length()>0){
User user = new User();
user.setName(name);
//用user作为参数到后台登录,这里我们简化了,直接假设登录成功
if(true){
Random r = new Random();
int a = r.nextInt(2);
if(a%2==0){
user.setAdmin(true);
}else{
user.setAdmin(false);
}
}
request.getSession().setAttribute("user", user);
}
response.sendRedirect(request.getContextPath()+"/index.jsp");
}
}
LogOutServlet
用于用户的安全退出!
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LogOutServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//用户安全退出很简单,我们在服务器端移除用户的session就可以了
request.getSession().invalidate();
response.sendRedirect(request.getContextPath()+"/index.jsp");
}
}
ShowServlet
显示所有用户信息时的servlet,需要把信息全部封装到request这个容器中,再转发到前台jsp显示的页面。
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ShowServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Map<String, HttpSession> onLines = (Map<String, HttpSession>) getServletContext().getAttribute("onLines");
List<Map<String, Object>> lists = new ArrayList<Map<String,Object>>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//遍历onlines,针对每个session对象封装一个map(信息包含:name,createTime,lastAccessTime,ip),把该map添加到list当中
Iterator<Entry<String, HttpSession>> it = onLines.entrySet().iterator();
while(it.hasNext()){
Entry<String, HttpSession> en = it.next();
Map<String, Object> m = new HashMap<String, Object>();
m.put("id", en.getValue().getId() );
m.put("user", en.getValue().getAttribute("user"));
String creationTime = sdf.format(new Date(en.getValue().getCreationTime()));
m.put("creationTime", creationTime);
String lastAccessTime = sdf.format( new Date(en.getValue().getLastAccessedTime()) );
m.put("lastAccessTime", lastAccessTime);
//注意,该ip数据是在CharsetFilter中封装的
m.put("ip", en.getValue().getAttribute("ip"));
lists.add(m);
}
request.setAttribute("onLines", lists);
request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);
}
}
show.jsp
前台在线用户的显示页面,会员和管理员看到的页面是不同的,管理员可以踢人。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>在线人信息管理</title>
<style type="text/css">
table{
border: 1px solid red;
border-collapse: collapse;/*设置单线-线合并*/
width: 80%;
}
td{
border: 1px solid red;
padding:3px;
}
.header{
background: gray;
}
</style>
</head>
<body>
<h2>以下是所有在线用户信息</h2>
<table>
<tr class="header" >
<td>姓名</td> <td>上线时间</td> <td>最后访问时间</td> <td>IP</td> <td>操作</td>
</tr>
<c:forEach items="${requestScope.onLines}" var="map">
<tr>
<td>
<c:if test="${empty map.user}" var="boo">
游客
</c:if>
<c:if test="${!boo}">
${map.user.name}
</c:if>
</td>
<td>${map.creationTime} </td>
<td>${map.lastAccessTime}</td>
<td>${map.ip } </td>
<td>
<c:if test="${!boo&&user.admin}">
<a href="<c:url value='/servlet/KickOutServlet?id=${map.id}'/> " >踢出${map.user.name}</a>
</c:if>
</td>
</tr>
</c:forEach>
</table>
<br/>网站访问量:${count}
</body>
</html>
KickOutServlet
管理踢人时请求的servlet,在这里我们把被踢的人的session从服务器端移除就可以了。但是注意防范一下,那个被踢者是否已经被踢走了、
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class KickOutServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String id = request.getParameter("id");
Map<String, HttpSession> onLines = (Map<String, HttpSession>) getServletContext().getAttribute("onLines");
if(onLines.containsKey(id)){
HttpSession session = onLines.get(id);//得到该session
session.invalidate();//移除该session
out.println("该用户已被踢出!");
}else{
out.println("该用户已经不存在!");
}
}
}
user
JavaBean,在这里,我就是简单的封装了一个JavaBean使用了。我们的知识点并不是这里。
package cn.hncu.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class KickOutServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String id = request.getParameter("id");
Map<String, HttpSession> onLines = (Map<String, HttpSession>) getServletContext().getAttribute("onLines");
if(onLines.containsKey(id)){
HttpSession session = onLines.get(id);//得到该session
session.invalidate();//移除该session
out.println("该用户已被踢出!");
}else{
out.println("该用户已经不存在!");
}
}
}
web.xml
注意啊!无论是servlet还是监听器,过滤器!一定要记得配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<listener>
<listener-class>cn.hncu.listeners.MyServletContextListener</listener-class>
</listener>
<listener>
<listener-class>cn.hncu.listeners.MySessionListener</listener-class>
</listener>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.hncu.servlet.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>LogOutServlet</servlet-name>
<servlet-class>cn.hncu.servlet.LogOutServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>ShowServlet</servlet-name>
<servlet-class>cn.hncu.servlet.ShowServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>KickOutServlet</servlet-name>
<servlet-class>cn.hncu.servlet.KickOutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LogOutServlet</servlet-name>
<url-pattern>/servlet/LogOutServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ShowServlet</servlet-name>
<url-pattern>/servlet/ShowServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>KickOutServlet</servlet-name>
<url-pattern>/servlet/KickOutServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>charset</filter-name>
<filter-class>cn.hncu.filter.CharsetFilter</filter-class>
</filter>
<filter>
<filter-name>login</filter-name>
<filter-class>cn.hncu.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>login</filter-name>
<url-pattern>/servlet/*</url-pattern>
<url-pattern>/jsps/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>charset</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
演示结果:
登录之前显示的主页:
未登录的时候,是无法进入显示所有在线用户的,用过滤器拦截了。
登录之后显示的主页:
管理员登录后显示的在线人信息
如果不是管理员登录后,最后的操作时不会显示的。
完整的项目链接:
https://github.com/chenhaoxiang/Java/tree/master/myOnlinesWeb2
myOnlinesWeb2.zip压缩文件