天天看點

javaEE之--------統計網站線上人數,安全登入等(觀察者設計模式)

總體介紹下: 

監聽器:監聽器-就是一個實作待定接口的普通Java程式,此程式專門用于監聽别一個類的方法調用。都是使用觀察者設計模式。

javaEE之--------統計網站線上人數,安全登入等(觀察者設計模式)

小弟剛接觸這個,做了些簡單的介紹,大神請繞道

javaEE之--------統計網站線上人數,安全登入等(觀察者設計模式)

,技術隻是一點點,友善以後遇到問題可以看這些能解決一些問題。同時希望和大家一起分享下自己寫的小小示例

在servlet中事件源:

事件源:HttpSession

HttpSessionListener  - 

HttpSessionAttributeListener

HttpSessionEvent

事件源:ServletRequest

ServletRequestListenr

ServletRequestAttributeListener

ServletRequestEvent

事件源:ServletContext

ServletContextListener

ServletContextAttributeListener

ServletContextEvent

在我們這個項目中用到知識點:

HttpSessionListener,監聽HttpSession的建立和銷毀。

sessionCreated

sessionDestroyed

Session的預設有效時間為30分。可以通過配置的方式修改它的值。

可以調用session.invalidate方法銷毀目前Session.

主要作用是記錄目前所有線上人數,無論是使用者還是遊客。·

上面是我們做這個執行個體用到的知識,下面具體介紹:

執行個體需求:

1、使用HttpSessionListener記錄線上人數。

2、使用HttpSessionAttributeListener記錄登入人數。

3、 将使用者踢出系統。

一:記錄線上人數,我們需要用到HttpSessionListener 觀察者設計模式

每一個使用者通路網站都會有一個seesion的建立,是以我們從建立session的統計即可

寫一個類,實作HttpSessionListener接口

sessionCreated 函數和 sessionDestroyed ,我們隻用到建立sessionCreated 

把建立的session全部放在一個map集合中,目前台需要擷取的時候,直接從context中擷取,進行其他操作。其實 sessionCreated 用到集合上鎖,api自帶,解決多線程問題。

public class MySessionListener implements HttpSessionListener {

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		//我們把建立的session封裝在一個map中
		Map<String, HttpSession> map =(Map<String, HttpSession>) se.getSession().getServletContext().getAttribute("onLines");
		if(map==null){//說明這是第一次通路是,需要自己new 一個對象
			map=Collections.synchronizedMap(new HashMap<String, HttpSession>());//采用集合上鎖,采用java 自帶的上鎖函數
			se.getSession().getServletContext().setAttribute("onLines", map);
		}
//		System.out.println("listener添加一個了");
		map.put(se.getSession().getId(), se.getSession());//以session 的id為key,session對象為value存在map中
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
	}}
           

二,前台顯示頁面

我們采用登入前後,都在一個頁面顯示,采用jstl表達式進行差別就可以。

其中,我們用到當登入成功之後,我們就直接采用設定session,讓其差別就可以,當我們采用安全登入也是采用這個session裡面是都存在值。

<body>
  <!-- 需求:做一個能夠允許遊客通路,允許登入,可以檢視目前使用者(包括遊客),
  	資訊-----name,ip,createTime,lastTime,需要一個權限是都可以踢人(使session失效)
  	就是講session建立的時候,存一個list中去,然後相關的資訊從session中回去就可以  -->
  
  <h2>這是使用者登入界面</h2>
  
	<c:if test="${empty sessionScope.user}" var="boo">
		  <form action="<c:url value='/LoginServlet'/>" method="post">
			NAME:<input type="text" name="name"/><br/>
			PWD :<input type="text" name="pwd"/><br/>
			<input  type="submit" value="送出資訊"/>
		  </form>
  </c:if>
  <c:if test="${!boo }">
  		歡迎您。${sessionScope.user.name}
  		<a href="<c:url value='/servlet/ShowLoginServet'/>" target="_blank" rel="external nofollow"  >顯示目前通路數量</a>
  		<a href="<c:url  value='/servlet/LoginoutServlet'/>" target="_blank" rel="external nofollow" >退出</a>
  </c:if>
  <hr/>
	  <a href="<c:url  value='/jsps/show.jsp'/>" target="_blank" rel="external nofollow" >這是真實使用者能通路的使用者</a>
 	 <a href="<c:url  value='/open/open.jsp'/>" target="_blank" rel="external nofollow" >遊客能通路的内容</a>
  
  </body>
           

三,登入之後處理

在是否登入,我們簡單的模拟下

成功之後我們就設定一個session的值傳給前台處理

<span style="font-size:18px;">	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//接收參數的編碼問題已經通過 過濾器設定好
		String name=request.getParameter("name");
		String pwd =request.getParameter("pwd");
		
		//獲得參數之後,開始封裝資料
		User user =new User();
		user.setName(name);
		user.setPwd(pwd);
		user.setAdmin(true);
		//封裝資料之後,調用service層,通路資料庫,簡單的模拟 當name和pwd相等就判斷登入成功
		if(name!=null && !name.trim().equals("") && pwd != null && pwd.trim().length()>0 ){
			if(name.endsWith(pwd)){//模拟下,相等就是登入成功
				request.getSession().setAttribute("user", user);
			}
		}
		response.sendRedirect(request.getContextPath()+"/index.jsp");//重定向到首頁
	}</span>
           

四,檢視線上使用者

<span style="font-size:14px;">  <body>
	<h2>這是使用者登入擁有的資源</h2>
	<!-- 前台最後采用list<map《》>的封裝資訊 -->
	  <!-- 顯示界面,需要知道session裡面的資訊,采用監聽器 要監聽遊客,和 使用者,采用httpSession-->
  	歡迎您。。${user.name }<br/>
  		<table >
  			<tr>
  				<td>姓名</td>
  				<td>IP</td>
  				<td>建立時間</td>
  				<td>最近通路時間</td>
  				<td>操作</td>
			</tr>
  		<c:forEach items="${requestScope.list }" 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.ip }
  			</td>
  			
  			<td>
  				<fmt:formatDate value="${map.createTime }" pattern="yyyy-MM-dd HH-mm-ss"/>
  			</td>
  			
  			<td>
  				<fmt:formatDate value="${map.LastAccessedTime }" pattern="yyyy-MM-dd HH-mm-ss"/>
  			
  			</td>
  			
  			<td>
  				<c:if test="${!boo && map.user.admin }">
  					<!--  <a href="<c:url value='/servlet/KitLogin'/>?id=${map.id }&&user=${user.name}" target="_blank" rel="external nofollow" >踢人</a> -->
  					
  					<a href="/onlineWeb/servlet/KitLogin?id=${map.id }&&user=${user.name}" target="_blank" rel="external nofollow" >踢人</a>
  				</c:if>
  			</td>
  			
  		</tr>
  		</c:forEach>
  			
  		</table>  </span>
           

檢視目前使用者線上人數,我們直接收集參數:

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//在這裡,我們需要将前台需要的資訊在這裡封裝
		
		//從onLines《sessionID,session對象中》拿到整個session集合,提取其中的資訊
		//然後把這個資訊封裝起來轉給前台顯示
		List<Map<String, Object>> list=new ArrayList<Map<String,Object>>();//采用list裝資料
		Map<String, HttpSession> onLines=(Map<String, HttpSession>) request.getSession().getServletContext().getAttribute("onLines");
//		System.out.println(onLines);
		Iterator<Map.Entry<String, HttpSession>> it= onLines.entrySet().iterator();
		while(it.hasNext()){
			Entry<String, HttpSession> entry=it.next();
			HttpSession sess=entry.getValue();//拿到單個的session對象了
			Map<String, Object> mm =new HashMap<String, Object>();//采用map封裝一行資料,然後放在list 中去,就是一個表的資料
			mm.put("id", sess.getId());//擷取session的id
			mm.put("createTime",new Date(sess.getCreationTime()));//建立的時間.傳過去的是date類型我們前台進行解析,顯示出來
			mm.put("LastAccessedTime", new Date(sess.getLastAccessedTime()));//上次通路的時間
			mm.put("user", sess.getAttribute("user"));
			mm.put("ip", sess.getAttribute("ip"));
			//前台需要的資訊補全,背景去使用
			list.add(mm);			
		}
		request.setAttribute("list", list);
		request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);//呆着list對象跳轉的顯示頁面
	}
           

效果圖:

javaEE之--------統計網站線上人數,安全登入等(觀察者設計模式)

五,管理者踢人

這裡全部設定為管理者,可以在值對象裡面修改

主要是在點選踢人時,将該對象的id傳過來,踢人就是把使用者的session.invalidate,設定相同的使用者名,不能踢。

踢人時,我們不僅僅隻是改session。還需要将map對象裡面的session移除。

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		PrintWriter pw =response.getWriter();
		String id=request.getParameter("id");
		String username=request.getParameter("user");//目前頁的user
		Map<String, HttpSession> map=(Map<String, HttpSession>) request.getServletContext().getAttribute("onLines");
		HttpSession se=map.get(id);//通過id 得到session對象
		User user= (User) se.getAttribute("user"); //通過session對象可以得到user對象
		System.out.println("username傳過來的www"+username);
		System.out.println("本地直接獲得的www"+user.getName());
		if(!user.getName().equals(username)){//不能删除和自己同名的使用者
			if(map.containsKey(id)){
				System.out.println("已經删除");
				HttpSession ss=	map.get(id);
				map.remove(id);//從context裡面移除
				ss.invalidate();//讓session失效
				pw.write("成功删除使用者");
			}else{
				pw.write("該使用者已被删除");
			}
			request.getRequestDispatcher("/jsps/show.jsp");
		}else{
			pw.write("使用者不能踢自己");
		}
		pw.write("<a href='/onlineWeb/index.jsp'>傳回</a>");
	}
           

六,主動退出

       直接将自己的session移除,和把自己的從map中移除

public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Map<String, HttpSession> map =(Map<String, HttpSession>) request.getServletContext().getAttribute("onLines");
		String id=request.getSession().getId();
		map.remove(id);//通過id來删除,context大容器中的session對象
		request.getSession().invalidate();
		response.sendRedirect(request.getContextPath()+"/index.jsp");
	}
           

七 ,安全登入

 以前我們寫得示例,隻要正确輸入了路徑和通路的項目,我們就能直接通路,沒有安全性可言,但是現在我們可以利用

過濾器來實作這個功能。

我們的依據是我們登入成功之後,我們将session裡面設定值,然後我們就可以根據這個來過濾了,目前我們知道,之前的全站壓縮和過濾敏感詞等,都是需要配置過濾器路徑,是以我們在配置路徑是需要注意,登入界面和處理登入界面的結果是不能被過濾的。是以一般這兩個都是直接放在根目錄下的。

public class SafeLoginrFilter 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;
		HttpServletResponse resp=(HttpServletResponse) response;
		if(req.getSession().getAttribute("user")==null){//這是過濾非法使用者使用的,隻有登入的使用者才能進入使用者權限
			resp.sendRedirect(req.getContextPath()+"/index.jsp");
		}else{
			chain.doFilter(req, resp);
		}
	
	}

	@Override
	public void destroy() {
	}
           

根據上面的這個,我們可以設定一些目錄可以讓遊客通路,就是不用通過過濾器的頁面,單獨寫一個檔案夾都可以。

攔截路徑在web.xml中配置:

<filter-mapping>
	  	<filter-name>safeLogin</filter-name>
  		<url-pattern>/servlet/*</url-pattern>
  		<url-pattern>/jsps/*</url-pattern>
  </filter-mapping>
           
javaEE之--------統計網站線上人數,安全登入等(觀察者設計模式)

總結:在示例中,我們隻需要知道,用HttpSessionListener,我們用它可以實作建立了多少session對象了,将他放到一個map容器中,需要的時候取出來就行了,當然,session中也存在很多有價值的,如id,通路時間,最後一次通路時間等。其餘的都是以前常用的知識。