1、Filter 什么是过滤器
1、Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
2、Filter 过滤器它是 JavaEE 的规范。也就是接口
3、Filter 过滤器它的作用是:拦截请求,过滤响应。
拦截请求常见的应用场景有:
1、权限检查
2、日记操作
3、事务管理
……等等
2、Filter 的初体验
要求:在你的 web 工程下,有一个 admin 目录。这个 admin 目录下的所有资源(html 页面、jpg 图片、jsp 文件、等等)都必 须是用户登录之后才允许访问。
思考:根据之前我们学过内容。我们知道,用户登录之后都会把用户登录的信息保存到 Session 域中。所以要检查用户是否登录,可以判断 Session 中否包含有用户登录的信息即可!!!
<%Object user = session.getAttribute("user");if (user==null){request.getRequestDispatcher("/login.jsp").forward(request,response);return;}%>
Filter 的工作流程图:
注意是:import javax.servlet.*;中的Filter接口
package com.atguigu.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import java.io.IOException;public class AdminFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}/*** doFilter方法,专门用来拦截请求。可以做权限检查* @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;HttpSession session = httpServletRequest.getSession();Object user = session.getAttribute("user");// 如果等于 null,说明还没有登录if (user==null) {servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);return;}else {// 让程序继续往下访问用户的目标资源,很重要,不能省略!!!filterChain.doFilter(servletRequest,servletResponse);}}@Overridepublic void destroy() {}}
<!--filter 标签用于配置一个 Filter 过滤器--><filter><!--给 filter 起一个别名--><filter-name>AdminFilter</filter-name><!--配置 filter 的全类名--><filter-class>com.atguigu.filter.AdminFilter</filter-class></filter><!--filter-mapping 配置 Filter 过滤器的拦截路径--><filter-mapping><!--filter-name 表示当前的拦截路径给哪个 filter 使用--><filter-name>AdminFilter</filter-name><!--url-pattern 配置拦截路径/ 表示请求地址为:http://ip:port/工程路径/ 映射到 IDEA 的 web 目录/admin/* 表示请求地址为:http://ip:port/工程路径/admin/**表示全部--><url-pattern>/admin/*</url-pattern></filter-mapping>
Filter 过滤器的使用步骤:
1、编写一个类去实现 Filter 接口
2、实现过滤方法 doFilter()
3、到 web.xml 中去配置 Filter 的拦截路径
3、Filter 的生命周期
Filter 的生命周期包含几个方法
1、构造器方法
2、init 初始化方法
第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
3、doFilter 过滤方法
第 3 步,每次拦截到请求,就会执行
4、destroy 销毁
第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)
4、FilterConfig 类
FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
1、获取 Filter 的名称 filter-name 的内容
2、获取在 Filter 中配置的 init-param 初始化参数
3、获取 ServletContext 对象
5、FilterChain 过滤器链
Filter 过滤器
Chain 链,链条
FilterChain 就是过滤器链(多个过滤器如何一起工作)
6、Filter 的拦截路径
—精确匹配
<url-pattern>/target.jsp</url-pattern>
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp
—目录匹配
<url-pattern>/admin/</url-pattern>
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/
—后缀名匹配
<url-pattern>.html</*url-pattern>
以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
<url-pattern>.do</*url-pattern>
以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
<url-pattern>.action</*url-pattern>
以上配置的路径,表示请求地址必须以.action 结尾才会拦截到
Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在!!!
7、书城第八阶段:
1、使用 Filter 过滤器拦截/pages/manager/所有内容,实
现权限检查
<filter><filter-name>ManagerFilter</filter-name><filter-class>com.atguigu.filter.ManagerFilter</filter-class></filter><filter-mapping><filter-name>ManagerFilter</filter-name><url-pattern>/pages/manager/*</url-pattern><url-pattern>/manager/bookServlet</url-pattern></filter-mapping>
2、ThreadLocal 的使用
ThreadLocal 的作用,它可以解决多线程的数据安全问题。
ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
ThreadLocal 的特点:
1、ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)
2、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据, 就 需要使用多个ThreadLocal 对象实例。
3、每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型
4、ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放。
深挖ThreadLocal
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。所以ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
数据隔离的秘诀其实是这样的,Thread有个TheadLocalMap类型的属性,叫做threadLocals,该属性用来保存该线程本地变量。这样每个线程都有自己的数据,就做到了不同线程间数据的隔离,保证了数据安全。
package com.atguigu.threadlocal;import com.sun.org.apache.xpath.internal.objects.XObject;import java.util.*;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;public class ThreadLocalTest {// public final static Map<String, Object> data = new Hashtable<>();public static ThreadLocal<Object> threadLocal=new ThreadLocal<Object>();private static Random random = new Random();public static class Task implements Runnable{@Overridepublic void run() {Integer i = random.nextInt(1000)+1;String name = Thread.currentThread().getName();System.out.println("线程["+name+"]生成的随机数是:" + i);// data.put(name,i);threadLocal.set(i);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}new OrderService().createOrder();Object o = threadLocal.get();System.out.println("在线程["+name+"]快结束时取出关联的数据是:" + o);}}public static void main(String[] args) {for (int i = 0; i < 3; i++) {new Thread(new Task()).start();}}}
ThreadLocal可以这样理解:每个ThreadLocal类对象可以参与多个线程,每个对象中有一个Map集合,每一个线程都只能使用Map中的一个键值对(键:当前线程;值:存入的数据)。如果想要每个线程使用多个键值对,则要多声明几个ThreadLocal类对象。
3、使用 Filter 和 ThreadLocal 组合管理事务
3.1、使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成
原理分析图:
ThreadLocal类对象在通过set()和get()方法储存和取值时,会自动识别当前线程作为键,对值进行操作。
conns.remove();一定要执行remove()操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
try{}catch(){}的catch中也可以抛异常throw new RuntimeException(e);
3.2、使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch。来进行实现的管理。
3.3、将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面。
在 web.xml 中我们可以通过错误页面配置来进行管理。
<!--error-page 标签配置,服务器出错之后,自动跳转的页面--><error-page><!--error-code 是错误类型--><error-code>500</error-code><!--location 标签表示。要跳转去的页面路径--><location>/pages/error/error500.jsp</location></error-page><!--error-page 标签配置,服务器出错之后,自动跳转的页面--><error-page><!--error-code 是错误类型--><error-code>404</error-code><!--location 标签表示。要跳转去的页面路径--><location>/pages/error/error404.jsp</location></error-page>
