过滤器概念
过滤器: 过筛子,符号条件的过去,不符号条件不能过去.
比喻: 安检,检查安全的人物通过
程序: 客户端需要访问的目标资源,在客户端和资源之间设置过滤器,
符号要求放行
实现过滤器程序
实现步骤
- 定义类,实现接口Filter
- 重写抽象方法
- web.xml配置 (注解)
要执行/servlet1,先经过(执行)过滤器1就行,因为过滤器2只过滤/servlet2,过了过滤器1才执行/servlet1。要执行/servlet2。先过过滤器1(它所有都要过滤),它放行了,再过过滤器2,过滤器2放行后才执行,/servlet2。
执行过程图片表示如下:
原先直接到servlet2,现在需要过滤器层层过滤。
过滤器的生命周期
-
过滤器对象的创建,是Tomcat服务器启动
-
init(FilterConfig config)过滤器对象被创建的时候调用,FilterConfig 对象tomcat引擎创建
-
-
过滤器执行过滤的方法,过滤被访问资源的时候,必须是被过滤器过滤器的资源
-
doFilter(request,response)
-
-
过滤器对象销毁的方法,销毁之前调用,服务器关闭
-
destroy()
-
过滤器的配置
- 完全匹配(一般不用,不可能一个资源配置一个过滤器)
<!--
过滤资源,只有Servlet2
绝对匹配 <url-pattern/servlet2></url-pattern>
只能过滤指定的资源
-->
<url-pattern>/servlet2</url-pattern>
- 目录匹配(使用比较多)
<!--
目录匹配,过滤器中最常见
/abc/* 过滤abc目录下的所有资源
一次过滤一片资源
过滤后台资源 /admin/*
-->
<url-pattern>/abc/*</url-pattern>
- 后缀名匹配(一般不使用)
<!--
后缀名匹配,一般不使用
*.jsp 访问所有jsp文件
-->
注解配置过滤器
@WebFilter(urlPatterns="/过滤资源")
过滤器的执行顺序
- web.xml配置
和配置文件的编写顺序决定运行的顺序,准确的说法是,根据mapping的顺序决定
- 注解开发
注解开发没有配置文件的
按照类名的自然顺序决定: A-B-C
如果存在配置文件,配置文件优先
过滤器处理中文乱码
监听器
监听器监听某个组件变化的对象. 事件源是固定的,主要是request,session,servletcontext域对象
监听的是域对象变化, 对象的创建和销毁, 域对象中存储的数据变化
第一个维度划分: 监听的域对象request,session,servletcontext
第二个维度划分: 监听的域对象的状态
ServletContext监听器入门
实现步骤
- 创建类实现监听器接口 ServletContextListener
- 重写抽象方法
- web.xml配置(注解)
package com.itheima.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
/**
* ServletContext对象,被创建,调用
* ServletContextEvent方法参数: 域对象的事件对象
* 此对象有tomcat引擎创建ServletContext
* servletContextEvent方法: 获取到被监听的事件源
* Object getSource() 获取到被监听的事件源
* ServletContext getServletContext()获取到被监听的事件源
* 除了返回值外,功能实现是一致的
* 设计目的为了通用性
* 其他的监听器事件对象,共同的方法 getSource()
*/
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext context = (ServletContext) servletContextEvent.getSource();
System.out.println(context);
ServletContext servletContext = servletContextEvent.getServletContext();
System.out.println(servletContext);
System.out.println("ServletContext域对象创建");
}
@Override
/**
* ServletContext对象,被销毁前调用
*/
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("ServletContext域对象销毁");
}
}
配置文件:
<listener>
<listener-class>com.itheima.listener.MyServletContextListener</listener-class>
</listener>
Servlet抽取
对于一个商品数据,基本的功能4个,增删改查询
问题: Servlet会越来越多
处理Servlet过多的问题,代码量少,维护性增强
如果一个功能写一个servlet,即登录功能一个servlet,注册功能一个servlet,这样太过于繁琐。
所以选择通过网页传递的所要使用方法的名称参数,根据参数选择指定的功能,将这些功能写在同一个servlet中。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
a:link{color: black}
a:visited{color: black}
a:hover{color: red}
a:active{color: aqua}
</style>
</head>
<body>
<!--
超链接,服务器提交
请求地址上 ? 拼接参数
-->
<a href="${pageContext.request.contextPath}/product?method=addProduct">添加商品</a>
<a href="${pageContext.request.contextPath}/product?method=updateProduct">修改商品</a>
<a href="${pageContext.request.contextPath}/product?method=delProduct">删除商品</a>
</body>
</html>
根据参数选择在servlet中对应的方法
//获取提交的参数
String md = request.getParameter("method");
//判断参数,调用不同的方法
if("login".equals(md)){
login(request,response);
}else if("register".equals(md)){
register(request,response);
}else if("updatePassword".equals(md)){
updatePassword(request,response);
}else if("loginOut".equals(md)){
loginOut(request,response);
}
以上方法还是不够简洁,下面选择用反射进行优化。