ToB企服应用市场:ToB评测及商务社交产业平台

标题: JavaWeb三大组件-Filter [打印本页]

作者: 张春    时间: 2022-6-26 14:41
标题: JavaWeb三大组件-Filter
文章目录



Filter

1. 概念

Filter过滤器是JavaWeb的三大组件之一。三大组件:Servlet,Listener,Filter
Filter过滤器是JavaEE的规范,即接口
作用:拦截请求,过滤响应
拦截请求常见的应用场景:


2. 基本使用

例子:要求在你的web工程下,有一个admin目录,这个目录下的所有资源(html,jpg,jsp等)都必须是用户登录之后才允许访问。

使用:
  1. // 先写个类去实现javax.servlet.Filter
  2. public class AdminFilter implements Filter {
  3.     // 这个方法重要,主要用于拦截请求!!(权限检查)
  4.     @Override
  5.     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
  6.                          FilterChain filterChain) throws IOException, ServletException
  7.     {
  8.         HttpServletRequest req = (HttpServletRequest) servletRequest; // 要强转一下,才能获取Session
  9.         HttpServletResponse resp = (HttpServletResponse) servletResponse;
  10.         HttpSession session = req.getSession();  // 获取Session
  11.         Object user = session.getAttribute("user");
  12.         if (user == null) {
  13.             req.getRequestDispatcher("/login.jsp").forward(req, resp); //没登录转发到登陆页面
  14.             return;
  15.         } else {
  16.             // 如果已经登录,如果有下一个Filter则进入,没有则放行,去访问用户请求的资源!(没有这行是不行的)
  17.             filterChain.doFilter(req, resp);
  18.         }
  19.     }
  20.     // 下面两个可以空实现
  21.     @Override
  22.     public void init(FilterConfig filterConfig) throws ServletException { }
  23.     @Override
  24.     public void destroy() { }
  25. }
复制代码
  1. <filter>
  2.     <filter-name>AdminFilter</filter-name>  
  3.     <filter-class>com.sutong.filter.AdminFilter</filter-class>  
  4. </filter>
  5. <filter-mapping>
  6.     <filter-name>AdminFilter</filter-name>
  7.    
  8.     <url-pattern>/admin/*</url-pattern>
  9. </filter-mapping>
复制代码

3. 生命周期

Filter 的方法执行顺序:

4. FilterConfig类

FIlterConfig,Filter过滤器的配置文件类,Tomcat每次创建的Filter的时候,会同时创建一个FilterConfig类。
作用:获取Filter过滤器的配置内容
  1. @Override
  2. public void init(FilterConfig filterConfig) throws ServletException {
  3.     String filterName = filterConfig.getFilterName(); // 1
  4.     String value = filterConfig.getInitParameter("key1"); // 2
  5.     ServletContext servletContext = filterConfig.getServletContext(); // 3
  6. }
复制代码

5. FilterChain类

FilterChain 是过滤器链(多个过滤器一起工作)
filterChain.doFilter(req, resp) 该方法是作用:

如果验证通过,执行完目标资源后会返回 doFilter 方法调用的地方,继续执行下面的代码。
当多个过滤器时,拦截同一个文件/目录时,Filter 配置文件的顺序(即web.xml中的配置顺序)决定了每 Filter 的执行顺序,配置在前先执行。
当多个过滤器的特点:⭐

6. 拦截路径


   Filter只关系请求的地址是否匹配,不关心资源是否存在。
  
7. ThreadLocal+Filter管理事务

7.1 ThreadLocal

ThreadLocal是jdk1.2开始的,作用:可以解决多线程的数据安全问题
ThreadLocal可以给当前线程关联一个数据(可以是普通变量,对象,集合等)
(可以简单理解为,像Map一样,当前线程名为key,关联的数据为value)
如果想要给当前线程关联多个数据则需要多个ThreadLocal实例,ThreadLocal实例一般都是 static 类型,其中保存的数据在线程销毁后由JVM虚拟机自动释放。
  1. // Hashtable线程安全
  2. public static Map<String, Object> map = new Hashtable<>();
  3. // ThreadLocal泛型就是关联数据的类型,类似:Map中V的类型,K是当前线程
  4. // 只能关联一个数据,多个则需new多个
  5. public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();
  6. // 使用
  7. public void test() {
  8.     map.put(Thread.currentThread().getName(), "Map存数据");
  9.     threadLocal.set("ThreadLocal存数据");
  10.     // 取数据
  11.     Object obj1 = map.get(Thread.currentThread().getName());
  12.     Object obj2 = threadLocal.get();
  13. }
复制代码

7.2 MySQL事务前提

   我们在book项目的时候,如果生成订单后发生错误,则生成订单成功而订单详情生成失败,这是严重错误的,所以我们要使用事务确保这些操作在一个事务内。
  而确保在一个事务的前期是 使用同一个 Connection 连接对象! 这里就可以用 ThreadLocal 了,把Connection 存到ThreadLocal 中,确保多个Service使用的是同一个连接对象。
而使用 ThreadLocal 关联数据要确保上面这些操作在一个线程中执行! (经过验证我们book中生成订单操作都是在一个线程下的)
  1. String orderId = null;
  2. try {
  3.     orderId = orderService.createOrder(cart, loginUser.getId());
  4.     JdbcUtils.commitAndClose();    // 生成订单,没异常提交事务关闭连接
  5. } catch (Exception e) {
  6.         JdbcUtils.rollbackAndClose();  // 有异常回滚,关闭连接 !!
  7. }
  8. // 但这样做每个xxxService.xxx() 都要进行try catch,太麻烦了,可以使用Filter,看下面
复制代码

7.3 Filter统一管理

使用Filter统一给所有的 Service 方法都加上 try-catch,来实现管理!!
所有的异常都要抛给 Filter,不要私自处理异常
TransactionFilter.java :
  1. public class TransactionFilter implements Filter {
  2.     @Override
  3.     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
  4.                          FilterChain filterChain) {
  5.         try {
  6.             // 下面这行相当于调用xxxService.xxx()方法,
  7.             // 所以我们对这行进行try-catch就行了(即给所有的Servlet中的所以方法进行了try-catch)
  8.             filterChain.doFilter(servletRequest, servletResponse);
  9.             JdbcUtils.commitAndClose();   // 没异常提交事务,关闭连接
  10.         } catch (Exception e) {
  11.             JdbcUtils.rollbackAndClose();  // 有异常回滚,关闭连接
  12.             e.printStackTrace();           // 可以不打印,打印可以让我们开到什么错误
  13.             throw new RuntimeException(e); // 再把错误抛给Tomcat去显示我们准备的错误页面!!!!!!
  14.             // (如果有异常了,用户页面则会一页空白,我们要给用户一点友好的提示!可以交给Tomcat展示友好的错误页面信息)
  15.         }
  16.     }
  17.     @Override
  18.     public void init(FilterConfig filterConfig) throws ServletException { }
  19.     @Override
  20.     public void destroy() { }
  21. }
复制代码
web.xml
  1. <filter>
  2.     <filter-name>TransactionFilter</filter-name>
  3.     <filter-class>com.sutong.filter.TransactionFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6.     <filter-name>TransactionFilter</filter-name>
  7.     <url-pattern>/*</url-pattern>  
  8. </filter-mapping>
复制代码

7.4 错误信息展示

TransactionFilter.java
  1. try {
  2.     filterChain.doFilter(servletRequest, servletResponse);
  3.     JdbcUtils.commitAndClose();
  4. } catch (Exception e) {
  5.     JdbcUtils.rollbackAndClose();      
  6.     throw new RuntimeException(e); // 再把错误抛给Tomcat去显示我们准备的错误页面!!!!!!
  7.     // (如果有异常了,用户页面则会一页空白,我们要给用户一点友好的提示!可以交给Tomcat展示友好的错误页面信息)
  8. }
复制代码
web.xml配置
  1. <error-page>
  2.     <error-code>500</error-code>
  3.     <location>/pages/error/error500.jsp</location>
  4. </error-page>
  5. <error-page>
  6.     <error-code>404</error-code>
  7.     <location>/pages/error/error404.jsp</location>
  8. </error-page>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4