D18 Sping Boot 入门 Sping框架--Java Web之书城项目(八) 过滤器

一、使用Filter过滤器拦截/pages/manager/所有内容,实现权限检查

新建ManagerFilter

 1 package com.gychen.filter;
 2 
 3 import javax.servlet.*;
 4 import javax.servlet.http.HttpServletRequest;
 5 import java.io.IOException;
 6 
 7 public class ManagerFilter implements Filter {
 8 
 9     @Override
10     public void init(FilterConfig filterConfig) throws ServletException {
11 
12     }
13 
14     @Override
15     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
16 
17         HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
18 
19         Object user =httpServletRequest.getSession().getAttribute("user");
20 
21         if (user ==null) {
22             httpServletRequest.getRequestDispatcher("/pages/user/login.jsp").forward(servletRequest,servletResponse);
23         } else {
24             filterChain.doFilter(servletRequest,servletResponse);
25         }
26     }
27 
28     @Override
29     public void destroy() {
30 
31     }
32 }
ManagerFilter

二、ThreadLocal的使用

ThreadLocal 的作用,它可以解决多线程的数据安全问题。
ThreadLocal 它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
ThreadLocal 的特点:
  1、ThreadLocal 可以为当前线程关联一个数据。(它可以像 Map 一样存取数据,key 为当前线程)
  2、每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个
    ThreadLocal 对象实例。
  3、每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型
  4、ThreadLocal 中保存数据,在线程销毁后。会由 JVM 虚拟自动释放。

三、实现Filter和ThreadLocal组合管理事务

3.1 在JdbcUtils里用ThreadLocal重构

  1 package com.gychen.utils;
  2 
  3 import com.alibaba.druid.pool.DruidDataSource;
  4 import com.alibaba.druid.pool.DruidDataSourceFactory;
  5 
  6 import java.io.InputStream;
  7 import java.sql.Connection;
  8 import java.sql.SQLException;
  9 import java.util.Properties;
 10 
 11 public class JdbcUtils {
 12 
 13     private static DruidDataSource dataSource;
 14     // 用作单线程事务管理
 15     private static ThreadLocal<Connection> conns = new ThreadLocal<Connection>();
 16 
 17     static {
 18 
 19         try {
 20             Properties properties = new Properties();
 21             //读取jdbc.properties配置文件属性
 22             InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
 23             //从流中加载数据
 24             properties.load(inputStream);
 25             //创建 数据库 连接池
 26             dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
 27 //            System.out.println(dataSource.getConnection());
 28         } catch (Exception e) {
 29             e.printStackTrace();
 30         }
 31 
 32     }
 33 
 34 
 35     /**
 36      * 获取数据库连接池中的连接
 37      * @return 如果返回null 说明获取连接失败<br/> 有值就是获取连接成功
 38      */
 39 //    public static Connection getConnection(){
 40 //        Connection conn = null;
 41 //        try {
 42 //            conn = dataSource.getConnection();
 43 //        } catch (SQLException e) {
 44 //            e.printStackTrace();
 45 //        }
 46 //        return  conn;
 47 //    }
 48 
 49     public static Connection getConnection(){
 50         Connection conn = conns.get();
 51         if (conn == null) {
 52             try {
 53                 conn = dataSource.getConnection(); // 从数据库连接池中获取连接
 54 
 55                 conns.set(conn);  // 保存到ThreadLocal对象中,供后面的JBDC操作使用
 56 
 57                 conn.setAutoCommit(false);  // 设置为手动管理事务
 58             } catch (SQLException e) {
 59                 e.printStackTrace();
 60             }
 61         }
 62         return conn;
 63     }
 64 
 65 //    /**
 66 //     * 关闭连接,放回数据库连接池
 67 //     * @param conn
 68 //     */
 69 //    public static void close(Connection conn){
 70 //        if(conn != null){
 71 //            try {
 72 //                conn.close();
 73 //            } catch (SQLException e) {
 74 //                e.printStackTrace();
 75 //            }
 76 //        }
 77 //    }
 78 
 79     /**
 80      * 提交事务并关闭释放连接
 81      */
 82     public static void commitAndClose(){
 83         Connection connection = conns.get();
 84         if (connection != null) {  // 如果不等于null,说明之前使用过连接,操作过数据库
 85             try {
 86                 connection.commit();  // 提交事务
 87             } catch (SQLException e) {
 88                 e.printStackTrace();
 89             } finally {
 90                 try {
 91                     connection.close();   // 关闭连接,释放资源
 92                 } catch (SQLException e) {
 93                     e.printStackTrace();
 94                 }
 95             }
 96 
 97         }
 98         // 一定要执行remove操作,否则会出错(因为Tomcat服务器底层使用了线程池技术)
 99         conns.remove();
100     }
101 
102 
103     /**
104      * 回滚事务并关闭释放连接
105      */
106     public static void rollbackAndClose(){
107         Connection connection = conns.get();
108         if (connection != null) {  // 如果不等于null,说明之前使用过连接,操作过数据库
109             try {
110                 connection.rollback();  // 回滚事务
111             } catch (SQLException e) {
112                 e.printStackTrace();
113             } finally {
114                 try {
115                     connection.close();   // 关闭连接,释放资源
116                 } catch (SQLException e) {
117                     e.printStackTrace();
118                 }
119             }
120 
121         }
122         // 一定要执行remove操作,否则会出错(因为Tomcat服务器底层使用了线程池技术)
123         conns.remove();
124     }
125 
126 
127     public static void main(String[] args) {
128 
129     }
130 
131 }
JdbcUtils

在Dao里删除close操作并抛出异常

3.2 使用Filter过滤器统一给所有的Service方法都加上try-catch。来进行实现的管理。

  在com.gychen.filter里新建TransactionFilter并配置web.xml

 1 package com.gychen.filter;
 2 
 3 import com.gychen.utils.JdbcUtils;
 4 
 5 import javax.servlet.*;
 6 import java.io.IOException;
 7 
 8 public class TransactionFilter implements Filter {
 9 
10     @Override
11     public void init(FilterConfig filterConfig) throws ServletException {
12 
13     }
14 
15     @Override
16     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
17 
18         try {
19             filterChain.doFilter(servletRequest,servletResponse);
20             JdbcUtils.commitAndClose();  // 提交事务
21         } catch (Exception e) {
22             JdbcUtils.rollbackAndClose();  // 回滚事务
23             e.printStackTrace();
24 
25         }
26     }
27 
28     @Override
29     public void destroy() {
30 
31     }
32 }
TransactionFilter

在BaseServlet中抛出异常 throw new RuntimeException(e); 

3.3 将所有异常都统一交给Tomcat展示友好的错误信息页面

在web.xml中可以通过错误页面配置来进行管理

1  <!--错误页面管理配置-->
2     <!-- error-page标签配置 服务器出错之后自动跳转的页面 -->
3     <error-page>
4         <!-- error-code是错误类型 -->
5         <error-code>500</error-code>
6         <!-- location表示要跳转的页面路径 -->
7         <location>/pages/error/error500.jsp</location>
8     </error-page>

在pages里新建error文件夹,新建erro500.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>error500</title>
</head>
<body>
    很抱歉,您访问的页面服务器出现错误
</body>
</html>

原文地址:https://www.cnblogs.com/nuister/p/13071826.html