Listener
监听器
-
监听某一个时间,状态的改变。
-
监听器的内部机制就是接口回调
接口回调
- 需求
案例:
//老程序
public class A {
public void println(PrintListener listener) {//传递接口实例
for(int i = 0; i < 10; i++) {
System.out.println("老程序循环到了" + i);
if(5 == i) {
System.out.println("老程序可以通知调用者");
listener.print();
}
}
}
}
接口:
public interface PrintListener {
void print();
}
新程序:
//谁调用老程序,谁实现这个接口
public class B implements PrintListener{
public void printFive() {
System.out.println("老的程序A已经循环到了5,B执行这个方法");
}
@Override
public void print() {
this.printFive();
}
}
测试:
public static void main(String[] args) {
A a = new A();
a.println(new B());
}
web监听器
- 总共有8个,分三种类型
监听三个作用域创建和销毁
pageContext
request httpServletRequest
session httpSession
application servletContext
(1)ServletContextListener
ServletContext的创建:
启动Tomcat服务器的时候
ServletContext的销毁
关闭服务器,从服务器移除出去
xml中的配置:
<listener>
<listener-class>com.lxr.MyServletContextListener</listener-class>
</listener>
ServletContextListener 作用:
在ServletContextListener创建的时候
完成自己想要初始化的工作;
执行自定义任务调度
(2)ServletRequestListener
request的创建:
访问服务器上任何资源的时候都会有请求
html、jsp、servlet
request的销毁:
服务器已经对该请求做出来响应
(3)HttpSessionListener
session的创建:
只要调用getSession();
HTML 不会
jsp、servlet会
session的销毁:
超时(30min)
正常关闭服务器序列化
非正常关闭销毁
HttpSessionListener作用:
统计在线人数
监听三个作用域属性状态变更
request ServletRequestAttributeListener
session HttpSessionAttributeListener
servletContext ServletContextAttributeListener
监听作用域中属性的添加、移除、替换
<body>
<%
session.setAttribute("name", "zahngsan");//属性添加
session.setAttribute("name", "lisi");//属性替换
session.removeAttribute("name");//属性移除
%>
</body>
监听HttpSession里面存值的状态变更
不用注册
- HttpSessionBindingListener
让Javabean实现该接口
public class Bean1 implements HttpSessionBindingListener{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void valueBound(HttpSessionBindingEvent arg0) {
System.out.println("值被绑定");
}
@Override
public void valueUnbound(HttpSessionBindingEvent arg0) {
System.out.println("解除绑定");
}
}
jsp部分:
Bean1 b = new Bean1();
b.setName("zhangsan");
session.setAttribute("bean", b);
session.removeAttribute("bean");
结果:
值被绑定
session属性被添加
解除绑定
session属性被移除
- HttpSessionActivationListener
用于监听session的值是钝化(序列化)还是活化(反序列化)
-
钝化(序列化)
把内存中数据存放在硬盘上
-
活化(反序列化)
把硬盘上的数据读取到内存里
- session的钝化活化的意义:
session中的值可能很多,有很长时间一直没用内存中这个值,内存有压力,我们考虑把session的值存放在硬盘上,等下一次再使用,再从硬盘提取出来(活化) - 让session值在一定时间内钝化:
做配置:
- 在Tomcat里的conf/context.xml中做配置
对所有运行在这个服务器的项目生效
- 在conf\Catalina\localhost中做配置
对localhost生效
- 在web项目下的META-INF中context.xml配置
只对当前工程生效
<context> <!-- maxIdleSwap表示1分钟不用后就钝化, directory是钝化后的文件存放的目录位置--> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="lxrContent"/> </Manager>
Filter
过滤器就是对客户端发来的请求过滤。浏览器发出,servlet处理,filter在这中间进行过滤拦截。
作用:
1. 对敏感词汇过滤
2. 统一设置编码
3. 自动登录等
如何使用Filter
- 定义一个类实现Filter
public class FilterDemo implements Filter {
public FilterDemo() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("来到过滤器了");
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
- 注册过滤器
在web.xml中注册,方法与servlet类似
<filter>
<display-name>filterDemo</display-name>
<filter-name>filterDemo</filter-name>
<filter-class>com.lxr.FilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>filterDemo</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
有关Filter的细节
- <url-pattern>/*</url-pattern>类似servlet
- 全路径匹配,以/开始
/login - 以目录匹配 /开始,*结束
/demo1/* - 以后缀名匹配,*开始,后缀名结束
*.jsp、*.html
- init方法的参数FilterConfig获取Filter在注册时候的名字和初始化参数
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("过滤器创建");
System.out.println("Filter在注册时的名字:" + fConfig.getFilterName());
System.out.println("初始化的参数" + fConfig.getInitParameterNames());
}
-
针对dispatcher的设置
REQUEST 只要是请求过来都拦截,默认就是REQUEST FORWARD 只要是转发都拦截 ERROR 页面出错发生跳转 INCLUDE 包含页面的时候就跳转
Filter生命周期
-
Filter的创建
在服务器启动时创建
-
Filter的销毁
Filter执行顺序
过滤器1:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("来到过滤器1了before");
//如果想放行,就使用chain参数
chain.doFilter(request, response);
System.out.println("来到过滤器1了after");
}
过滤器2:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("来到过滤器2 before");
chain.doFilter(request, response);
System.out.println("来到过滤器2了 after");
}
结果:
来到过滤器1了before
来到过滤器2 before
来到过滤器2了 after
来到过滤器1了after
自动登录范例
准备好JDBCUtils和c3p0-config.xml,以及必要的jar包
- 搭建数据库
public class UserDaoImpl implements UserDao{
@Override
public UserBean login(UserBean user) throws SQLException{
QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
String sql = "select * from tb_user where username=? and password=?";
return (UserBean) runner.query(sql, new BeanHandler<UserBean>(UserBean.class), user.getUsername(), user.getPassword());
}
}
- UserBean:
private String username;
private String password;
- LoginServlet:
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String autoLogin = req.getParameter("autoLogin");//自动登录是否勾选
UserBean user = new UserBean();
user.setPassword(password);
user.setUsername(username);
UserDao dao = new UserDaoImpl();
try {
UserBean userBean = dao.login(user);
if(null != userBean) {//用户名密码正确
//选择自动登录
if("on".equals(autoLogin)) {//勾选了自动登录,需要让服务器生成cookie
//发送cookie给客户端
Cookie cookie = new Cookie("autoLogin", username + "#" + password);
cookie.setMaxAge(60 * 60 * 24 * 7);//一周有效
cookie.setPath(req.getContextPath());//针对当前这个项目有效
resp.addCookie(cookie);
}
HttpSession session = req.getSession();
session.setAttribute("userBean", user);
req.getRequestDispatcher("index.jsp").forward(req, resp);
}else {//用户名或密码错误重新登陆
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- CookieUtils:
public class CookieUtils {//从众多cookie中找到需要的cookie
public static Cookie findCookie(Cookie[] cookies, String name) {
if(null != cookies) {
for (Cookie cookie : cookies) {
if(name.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
}
- AutoLoginFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
UserBean userBean = (UserBean) req.getSession().getAttribute("userBean");
if(null != userBean) {//没有过期,直接放行,不考虑自动登录
chain.doFilter(request, response);
}else {//过期了
Cookie[] cookies = req.getCookies();
Cookie cookie = CookieUtils.findCookie(cookies, "autoLogin");
if(null == cookie) {//第一次来,放行,让它去登录
chain.doFilter(request, response);
}else {//勾选了自动登录,且没有失效
String value = cookie.getValue();
String username = value.split("#")[0];
String password = value.split("#")[1];
UserBean user = new UserBean();
user.setUsername(username);
user.setPassword(password);
UserDao dao = new UserDaoImpl();
try {
userBean = dao.login(user);
req.getSession().setAttribute("userBean", userBean);
} catch (Exception e) {
e.printStackTrace();
}
chain.doFilter(request, response);
}
}
}
- index.jsp:
<body>
<c:if test="${not empty userBean }">
<h1>这是首页,欢迎用户${userBean.username }登陆</h1>
</c:if>
<c:if test="${empty userBean }">
<h1>你好,请先登录再访问</h1>
</c:if>
</body>