过滤器
- 过滤器Filter就像一个一个哨卡,用户的请求需要经过Filter,并且可以有多个过滤器
编写
package filter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
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 FirstFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
//类型强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//获取来路用户的ip地址
String ip = request.getRemoteAddr();
//获取用户访问的页面地址
String url = request.getRequestURL().toString();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = new Date();
String date = sdf.format(d);
System.out.printf("%s %s 访问了 %s%n", date, ip, url);
//过滤器放行,表示继续运行下一个过滤器,或者最终访问的某个servlet,jsp,html等等
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
//与Servlet需要配置自启动才会随着tomcat的启动而执行init()方法不一样。
//Filter一定会随着tomcat的启动自启动。
System.out.println("First Filter init()");
}
}
web.xml
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- Filter是web应用非常重要的一个环节,如果Filter启动失败,或者本身有编译错误,不仅这个Filter不能使用,整个web应用会启动失败,导致用户无法访问页面
- 在启动tomcat过程中,也会看到这样的字样:
严重: Context [] startup failed due to previous errors
这常常用于提示Filter启动失败了
中文处理
package filter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
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 EncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
登录验证
package filter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
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 AuthFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String uri = request.getRequestURI();
if (uri.endsWith("login.html") || uri.endsWith("login") || uri.endsWith(".css") || uri.endsWith(".js") || uri.endsWith(".jpg")) {
chain.doFilter(request, response);
return;
}
String userName = (String) request.getSession().getAttribute("userName");
if (null == userName) {
response.sendRedirect("login.html");
return;
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>filter.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
监听器
- Listener 的作用是用于监听 web应用的创建和销毁,以及在其上attribute发生的变化。
- web应用即ServletContext对象(jsp的隐式对象application)
- 除了对web应用的监听外,还能监听session和request的生命周期,以及他们的attribute发生的变化。
context
- 对Context的监听分生命周期的监听,和Context上Attribute变化的监听两种。
- 编写 ContextListener
package listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextListener implements ServletContextListener {
//对应当前web应用的销毁
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("web 应用销毁 ");
}
//对应当前web应用的初始化
@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("web 应用初始化 ");
}
}
- 配置 web.xml
<listener>
<listener-class>listener.ContextListener</listener-class>
</listener>
在启动tomcat以及当前web应用重载的时候可以观察到
web应用的自动重载需要如下前提:
1. 配置: server.xml中对应的<context配置 的属性 @reloadable="true"
2. 某个servlet 发生了变化,导致这个web应用自动重启
- 编写 ContextAttributeListener
package listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
public class ContextAttributeListener implements ServletContextAttributeListener {
//监听属性的增加
@Override
public void attributeAdded(ServletContextAttributeEvent e) {
System.out.println("增加属性 ");
System.out.println("属性是" + e.getName());
System.out.println("值是" + e.getValue());
}
//监听属性的移除
@Override
public void attributeRemoved(ServletContextAttributeEvent e) {
// TODO Auto-generated method stub
System.out.println("移除属性 ");
}
//监听属性的替换
@Override
public void attributeReplaced(ServletContextAttributeEvent e) {
// TODO Auto-generated method stub
System.out.println("替换属性");
}
}
<listener>
<listener-class>listener.ContextAttributeListener</listener-class>
</listener>
-
测试
-
testContext.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
application.setAttribute("test", 1);
application.setAttribute("test", 2);
application.removeAttribute("test");
%>
session
- 对Session的监听分生命周期的监听,和Session上Attribute变化的监听两种。
- 编写 SessionListener
package listener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class SessionListener implements HttpSessionListener {
//表示session创建的时候执行
@Override
public void sessionCreated(HttpSessionEvent e) {
System.out.println("监听到 session 创建, sessionid 是: " + e.getSession().getId());
}
//表示session销毁的时候执行
@Override
public void sessionDestroyed(HttpSessionEvent e) {
System.out.println("监听到 session 销毁, sessionid 是: " + e.getSession().getId());
}
}
- 配置web.xml
<listener>
<listener-class>listener.SessionListener</listener-class>
</listener>
- 测试
- 编写 SessionAttributeListener
package listener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class SessionAttributeListener implements HttpSessionAttributeListener {
//当在session中增加属性时触发
@Override
public void attributeAdded(HttpSessionBindingEvent e) {
System.out.println("session 增加属性 ");
System.out.println("属性是" + e.getName());
System.out.println("值是" + e.getValue());
}
//当在session中移除属性时触发
@Override
public void attributeRemoved(HttpSessionBindingEvent e) {
// TODO Auto-generated method stub
System.out.println("session 移除属性 ");
}
//当替换session中的属性时触发
@Override
public void attributeReplaced(HttpSessionBindingEvent e) {
// TODO Auto-generated method stub
System.out.println("session 替换属性 ");
}
}
<listener>
<listener-class>listener.SessionAttributeListener</listener-class>
</listener>
- testSession.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
session.setAttribute("test", 1);
session.setAttribute("test", 2);
session.removeAttribute("test");
%>
- 测试
request
- 对Request的监听分生命周期的监听,和Request上Attribute变化的监听两部分。
- 编写 RequestListener
package listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class RequestListener implements ServletRequestListener, ServletRequestAttributeListener {
//当本次请求结束的时候触发
@Override
public void requestDestroyed(ServletRequestEvent arg0) {
System.out.println("销毁了一个Request ");
}
/**
当新创建了一个Request的时候触发,只要访问了服务端的资源,就会创建一个Request,无论是jsp,servlet还 是html
*/
@Override
public void requestInitialized(ServletRequestEvent arg0) {
System.out.println("创建了一个Request ");
}
//当有新增属性时触发
@Override
public void attributeAdded(ServletRequestAttributeEvent e) {
System.out.println("request 增加属性 ");
System.out.println("属性是" + e.getName());
System.out.println("值是" + e.getValue());
}
//当有移除属性时触发
@Override
public void attributeRemoved(ServletRequestAttributeEvent arg0) {
System.out.println("request 移除属性 ");
}
//当有替换属性时触发
@Override
public void attributeReplaced(ServletRequestAttributeEvent arg0) {
System.out.println("request 替换属性 ");
}
}
<listener>
<listener-class>listener.RequestListener</listener-class>
</listener>
- testRequest.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setAttribute("test", 1);
request.setAttribute("test", 2);
request.removeAttribute("test");
%>
- 测试
在线人数
- HTTP协议是短链接的,所以无法在服务端根据建立了多少连接来统计当前有多少人在线
- 不过可以通过统计session有多少来估计在线人数
- 一旦一个用户访问服务器,就会创建一个session. 如果该用户持续访问,那么该session会持续有效。
- 如果经历了30分钟,该用户也没有做任何操作,就表示该用户“下线” 了,其对应的session也会被销毁。
- 所以可以通过统计有多少session被保留来估计当前在线人数。
- 编写 OnlineNumberListener
package listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class OnlineNumberListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent e) {
ServletContext application = e.getSession().getServletContext();
Integer online_number = (Integer) application.getAttribute("online_number");
if (null == online_number)
online_number = 0;
online_number++;
application.setAttribute("online_number", online_number);
System.out.println("新增一位在线用户");
}
@Override
public void sessionDestroyed(HttpSessionEvent e) {
ServletContext application = e.getSession().getServletContext();
Integer online_number = (Integer) application.getAttribute("online_number");
if(null==online_number){
online_number = 0;
}
else
online_number--;
application.setAttribute("online_number", online_number);
System.out.println("一位用户离线");
}
}
- 配置web.xml
<listener>
<listener-class>listener.OnlineNumberListener</listener-class>
</listener>
- checkOnlineNumber.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
当前 在线人数 : ${online_number}
- 测试