过滤器
作用
拦截请求与响应
image.png
优点
解决代码冗余,如果每个资源都需要处理同一个操作,那么这个处理操作就可以放在过滤器集中处理。
应用场景
1.解决post提交中文乱码应用场景
2.登录权限控制
开发方式
1.配置XML文件
2.注解(推荐)
方式1-手动XML配置实现过滤器
实现步骤:
- 创建一个目标资源Demo1Servlet处理请求与响应
- 创建一个类Demo1Filter并实现Filter接口,重写拦截请求与响应的方法doFilter
- 在web.xml中配置过滤器拦截目标资源url(因为拦截资源,每个资源都是通过url访问的)
- 部署项目测试运行,观察是否进行拦截请求与响应
代码实现×3:
Servlet:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "_01Demo1Servlet", urlPatterns = "/_01Demo1Servlet")
public class _01Demo1Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//输出一句信息
System.out.println("执行了_01Demo1Servlet代码");
}
}
过滤器Filter:
import javax.servlet.*;
import java.io.IOException;
public class _01Demo1Filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
//doFilter是拦截请求与响应的方法
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//1.拦截请求
System.out.println("==执行了_01Demo1Filter拦截请求的代码==");
//2.放行,给目标资源去执行【有这句代码就放行,没有就不放行,不放行导致目标资源不执行】
filterChain.doFilter(request,response);//本质就是转发跳转到目标资源
//3.拦截响应
System.out.println("==执行了_01Demo1Filter拦截响应的代码==");
}
@Override
public void destroy() {
}
}
web.xml代码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--目标:建立Demo1Filter拦截Demo1Servlet
1.定义过滤器全名,使用<filter>标签
2.给这个过滤器配置拦截的url,(url就是Demo1Servlet的访问路径),使用<filter-mapping>标签
-->
<filter>
<filter-name>_01Demo1Filter</filter-name>
<filter-class>com.itheima.filter._01Demo1Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>_01Demo1Filter</filter-name>
<url-pattern>/_01Demo1Servlet</url-pattern>
</filter-mapping>
</web-app>
访问地址:
http://localhost:8080/day29_01_filter_war_exploded/_01Demo1Servlet
tips:
1.实现过滤器的接口
javax.servlet.Filter
2.过滤器拦截请求与响应的方法
doFilter方法
方式2-模板向导注解实现过滤器
实现步骤:
- 创建一个Demo2Servlet处理请求与响应
- 根据模板向导创建过滤器,重写doFilter方法进行拦截请求与响应
- 设置注解配置拦截的资源地址
过滤器Filter代码:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*
* @WebFilter 用于配置过滤器的注解
* filterName = "_02Demo2Filter", 功能与xml中<filter-name>标签功能一样,可有可无
* urlPatterns = "/_02Demo1Servlet",功能与xml中<url-pattern>标签功能一样,必须有参数
* */
@WebFilter(filterName = "_02Demo2Filter",urlPatterns = "/_02Demo2Servlet")
public class _02Demo2Filter implements Filter {
public void destroy() {
}
//重写拦截请求与响应的方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//1.拦截请求
System.out.println("==执行了_02Demo2Filter拦截请求的代码==");
//2.放行,给目标资源去执行
filterChain.doFilter(request,response);
//3.拦截响应
System.out.println("==执行了_02Demo2Filter拦截响应的代码==");
}
public void init(FilterConfig config) throws ServletException {
}
}
Servlet:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "_02Demo2Servlet", urlPatterns = "/_02Demo2Servlet")
public class _02Demo2Servlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//输出一句信息
System.out.println("执行了_02Demo2Servlet代码");
}
}
tips:
1.注解实现代码
@WebFilter(fileName="过滤器名字",urlPatterns="拦截的资源路径")
2.注解配置与xml配置出现冲突,谁的优先级高?
xml优先级高于注解
过滤器执行流程(原理)
执行流程(时序图)
image.png
tips:
1.过滤器对象在服务器启动的时候创建,全局唯一。
2.过滤器对象在服务器关闭的时候销毁
过滤路径映射配置介绍
拦截路径配置方式有2种:
第一种:
精确匹配,配置的路径与资源访问的路径要一模一样就可以拦截
任何资源路径都是可以的
urlPatterns = "/img/3.jpg",
urlPatterns = "/index.jsp"
第二种:
模糊匹配,只能使用一个“”号通配符操作,代表0~多个字符
1.前缀匹配,匹配开头一致的
要求:以“/”开头,以"/"结尾
例子:
/abc/,拦截资源访问路径以/abc开头的所有资源
/,拦截所有资源
2.后缀匹配,匹配结尾一致的
要求:以“*”开头,以“.扩展名”方式结尾
例子:
*.action,拦截资源访问路径以.action为结尾的所有资源
*.do,拦截资源访问路径以.do为结尾的所有资源
注意:
1.urlPatterns = "/abc//abc",这是精确匹配
2.在过滤器里面可以使用“/”或“/”,但是在Servlet里面不可以,否则静态资源无法访问
过滤器代码:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*
* 路径的配置通过urlPatterns属性完成的,这个属性有2中写法
* 方式1:拦截一个路径,urlPatterns = "/url"
* 方式2:拦截多个路径,urlPatterns = {"/url1","/url2",...}
* */
@WebFilter(filterName = "_04URLFilter",urlPatterns = {
//精确匹配
"/img/6.jpg","/index.jsp","/index.html",
//模糊匹配
"/abc/*","*.do"
})
public class _04URLFilter implements Filter {
public void destroy() {
}
//重写拦截请求与响应的方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//1.拦截请求
System.out.println("==执行了_02Demo2Filter拦截请求的代码==");
//2.放行,给目标资源去执行
filterChain.doFilter(request,response);
//3.拦截响应
System.out.println("==执行了_02Demo2Filter拦截响应的代码==");
}
public void init(FilterConfig config) throws ServletException {
}
}
拦截方式
拦截方式介绍
拦截方式
是指过滤器根据浏览器访问的资源方式的不同进行不同的拦截。
浏览器访问资源方式
第一种:浏览器直接url访问目标资源(重定向也属于直接url访问资源)
第二种:浏览器访问一个资源服务器内部请求转发跳转到另一个目标资源
拦截方式就是根据不同访问资源的方式进行不同的拦截,默认过滤器只会拦截第一种直接url访问资源
拦截方式类型
image.png
注解方式拦截方式的语法
image.png
扩展web.xml配置过滤器修改拦截方式设置
image.png过滤链
同一个资源可以被多个过滤器进行拦截强求与响应——过滤链
执行顺序分析
image.png
案例1-解决全站乱码
分析
项目应用程序乱码的地方:
- post提交中文请求
- response输出中文数据
实现步骤
- 准备一个表单数据提交post中文请求
- 新建一个EncodingServlet处理请求接收中文数据并使用response输出
- 创建一个过滤器EncodingFilter拦截所有资源解决全站乱码
Form.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="encoding" method="post">
<input type="text" name="name"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
EncodingServlet代码
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "_09EncodingServlet", urlPatterns = "/encoding")
public class _09EncodingServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//目标:接收数据并输出数据
//1.获取post提交中文的数据
String name = request.getParameter("name");
//2.控制台打印接收的数据
System.out.println(name);
//3.输出中文数据到浏览器'
response.getWriter().write(name);
}
}
EncodingFilter代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
* 目标:拦截所有资源“/*”, 处理乱码
* */
@WebFilter(filterName = "_09EncodingFilter",urlPatterns = "/*")
public class _09EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.将req,resp父接口转换为子接口
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//2.处理post提交中文乱码
//获取提交数据的方法类型
String method = request.getMethod();
//判断提交数据访问为post请求才处理乱码
if("post".equalsIgnoreCase(method)){
request.setCharacterEncoding("utf8");
}
//3.处理response输出中文乱码
response.setContentType("text/html;charset=utf8");
//4.放行
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
tips:
过滤器拦截所有资源:
urlPatterns="/*"
案例2-登录权限控制1-环境搭建与登录功能
需求
image.png
实现分析
- 创建一个项目
- 导入页面素材("资料\原型")
- 实现登录
搭建环境结构
image.pngLoginServlet代码:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "LoginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*目标:模拟处理登录功能*/
//1.获取用户名与密码
String user = request.getParameter("user");
String password = request.getParameter("password");
//2.判断用户名必须为admin,密码必须为123,代表登录成功
if("admin".equals(user) && "123".equals(password)){
//登录成功,将用户名写入session,以后用于判断是否登登录的依据
request.getSession().setAttribute("loginUser",user);
//登录成功后跳转/list.jsp
response.sendRedirect(request.getContextPath()+"/list.jsp");
}else {
//3.校验失败,登录失败
//将错误信息存储到请求域中
request.setAttribute("errorMsg","用户名或密码错误");
//转发跳转到登录页面,使用el显示错误信息
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
}
案例2-登录权限控制2-实现登录控制
使用过滤器实现登录权限控制
过滤器代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*目标:拦截admin目录下资源的所有访问*/
@WebFilter(filterName = "LoginFilter",urlPatterns = "/admin/*")
public class LoginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.将父接口转换为子接口
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//2.获取session中的登录数据“loginUser”
String loginUser = (String) request.getSession().getAttribute("loginUser");
//3.判断登录数据是否有效,有效放行
if(loginUser!=null){
//放行
chain.doFilter(request, response);
}else {
//4.无效返回登录页面
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
}
public void init(FilterConfig config) throws ServletException {
}
}
监听器
tomcat服务器内存数据(三大域对象)发生变化了,使用监听器在内存数据改变的时候做一些业务控制。
作用:获取域对象改变的时间点,让我们在对应的时间点进行业务逻辑控制
监听器分类
image.pngServletContextListener介绍
获取域对象改变的时间点,让我们在对应的时间点进行业务逻辑控制
ServletContextListener监听对象创建与销毁
实现步骤——
- 创建一个类实现ServletContextListener接口,重写2个方法
- 配置注解将当前类交给服务器去管理
注解方式代码:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/*
* servletContext对象什么时候创建?什么时候销毁?
* 答:servletContext对象是服务器启动时最早最先创建的对象,比过滤器早;服务器关闭的时候。
* */
@WebListener //注解含义:将当前监听器类交给服务器管理
public class MyServletContextListener implements ServletContextListener {
//当服务器创建servletContext上下文域对象的时候触发调用的方法
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("==servletContext对象被创建了==");
}
//当服务器销毁servletContext上下文域对象的时候触发调用的方法
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("==servletContext对象被销毁了==");
}
}
web.xml方式配置将监听器交给服务器管理
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--配置监听器-->
<listener>
<listener-class>com.itheima.listener.MyServletContextListener</listener-class>
</listener>
</web-app>
ServletContextListener的作用
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.Timer;
import java.util.TimerTask;
/*
* servletContext对象什么时候创建?什么时候销毁?
* 答:servletContext对象是服务器启动时最早最先创建的对象,比过滤器早;服务器关闭的时候。
* */
@WebListener //注解含义:将当前监听器类交给服务器管理
public class MyServletContextListener implements ServletContextListener {
//当服务器创建servletContext上下文域对象的时候触发调用的方法
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("==servletContext对象被创建了==");
/*
* 获取到servletContext创建的时间点有什么用?ServletContextListener的作用?
* 答:我们因为上下文域对象的创建是最早的时间点,通常可以做如下2个操作:
* 1.加载自定义配置文件数据,spring框架的配置文件就是使用这个监听器进行加载的
* 2.开启定时器任务运行
* 定时器任务:按照指定的时间执行任务
* js的定时器语法:setInterval()或setTimeout()
* */
//目标:java的jdk定时器
//1.创建定时器类Timer
Timer timer = new Timer();
//2.订制定时任务计划
//方式1:timer.schedule(TimerTask,long,long);
// 参数1:TimerTask,任务接口,编写任务代码
// 参数2:long,设置距离第一次执行的毫秒数
// 参数3:long,每一次执行的间隔毫秒数
//方式2:timer.schedule(TimerTask,Date,long);
// 参数1:TimerTask,任务接口,编写任务代码
// 参数2:Date,设置第一次执行的时间
// 参数3:long,每一次执行的间隔毫秒数
/*需求:每3秒输出一次hello world*/
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("hello world");
}
},0,3000);
}
//当服务器销毁servletContext上下文域对象的时候触发调用的方法
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("==servletContext对象被销毁了==");
}
}
web项目的路径讲解
路径配置方式有2种
1.相对路径(静态页面上推荐,因为静态页面无法动态获取部署资源目录路径):
格式:url="相对资源路径"
含义:相对于当前的静态页面的路径
例子:<form action="login" method="post"> login是相对路径
2.全路径(服务器端java代码推荐):
格式1:url="/资源路径" 服务器内部使用,当前"/"代表当前项目内
例子:
request.getRequestDispatcher("/demo").forward(request,response);
格式2:url="/web项目资源部署目录名字/资源路径" 浏览器去执行,重定向和jsp使用
例子:
response.sendRedirect(request.getContextPath()+"/demo");
网友评论