Filter的常见作用:
现在在WebContent目录下有一个目录admin。这个目录是管理员操作的目录。这个目录里有jsp文件,有html文件,还有图片资源文件。现在我们要让这些资源都在用户登录才能被访问。那么我们要怎么实现这样的需求。
前面我们讲过Session。有同学可能会想,我们可以在用户登录之后。把用户的信息保存在Session域对象中。然后在jsp页面里通过Session域对象获取用户的信息,如果用户信息存在,说明用户已登录。否则就重定向到登录页面。这个方案可行。可是html页面呢? html页面是没有Session域对象的。
这就需要我们使用Filter过滤器来进行请求的拦截。然后判断Session域对象中是否包含用户的信息。
现在我们以admin目录下user.jsp为例进行讲解。
1)Filter1的类代码:
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Filter1 implements Filter {
/**
* Filter初始化方法
*/
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* Filter的过滤方法
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 强转
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取用户登录信息
String username = (String) httpRequest.getSession().getAttribute("username");
if (username != null) {
// 过滤器中,只要允许用户访问资源,一定要调用chain.doFilter方法,否则用户永远访问不到资源
chain.doFilter(request, response);
} else {
// 如果用户未登录。返回登录页面
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
}
}
/**
* Filter销毁的方法
*/
public void destroy() {
}
}
2)web.xml文件中的Filter配置
<filter>
<filter-name>Filter1filter-name>
<filter-class>com.atguigu.filter.Filter1filter-class>
filter>
<filter-mapping>
<filter-name>Filter1filter-name>
<url-pattern>/admin/user.jspurl-pattern>
filter-mapping>
Servlet的生命周期
Filter生命周期:
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Filter2 implements Filter {
public Filter2() {
System.out.println("Filter2 构造 方法 被调用");
}
/**
* Filter初始化方法
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter2 init 方法被调用。初始化……");
}
/**
* Filter的过滤方法
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Filter2 doFilter 方法被调用 ");
// 一定要调用此方法,否则用户访问的资源会访问不到。
chain.doFilter(request, response);
}
/**
* Filter销毁的方法
*/
public void destroy() {
System.out.println("Filter2 的destroy方法被调用……");
}
}
<filter>
<filter-name>Filter2filter-name>
<filter-class>com.atguigu.filter.Filter2filter-class>
filter>
<filter-mapping>
<filter-name>Filter2filter-name>
<url-pattern>/login.jspurl-pattern>
filter-mapping>
查看整个控制台的打印如下:
1)Filter在工程启动的时候初始化。
2)在访问过滤的时候调用doFilter方法
3)Tomcat关闭Filter被销毁的时候调用destory方法
作用:FilterConfig类和ServletConfig类是一样的。可以获取Filter在web.xml文件中的配置信息,做初始化之用。
我们可以在web.xml文件中给Filter添加初始化参数。然后在init初始化方法中使用FilterConfig类获取到初始化的参数。
FilterConfig类,一般有三个作用:
<filter>
<filter-name>Filter2filter-name>
<filter-class>com.atguigu.filter.Filter2filter-class>
<init-param>
<param-name>usernameparam-name>
<param-value>rootparam-value>
init-param>
filter>
/**
* Filter初始化方法
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter2 init 方法被调用。初始化……");
// 获取Filter的名称
String filterName = filterConfig.getFilterName();
System.out.println("Filter name ==>>> " + filterName);
// 获取初始化参数。username的值
String username = filterConfig.getInitParameter("username");
System.out.println("username ==>> " + username);
// 获取ServletContext的对象实例
ServletContext ctx = filterConfig.getServletContext();
System.out.println(ctx);
}
FilterChain是整个Filter过滤器的调用者。Filter与Filter之间的传递,或者Filter与请求资源之间的传递都靠FilterChain.doFilter方法。
一般Filter.doFilter中的代码分为三段。
第一段是FilterChain.doFilter之前的代码。一般用来做请求的拦截,检查用户访问的权限,访问日记的记录。参数编码的设置等等操作。
第二段是FilterChain.doFilter方法。此方法可以将代码的执行传递到下一个Filter中。或者是传递到用户最终访问的资源中。
第三段是FilterChain.doFilter之后的代码。主要用过做一些日记操作。我们很少会在第三段中做太多复杂的操作。
在每一个Filter类的doFilter方法中,一定要调用chain.doFilter方法,除非你想要阻止用户继续往下面访问。否则一定要调用FilterChain的doFilter方法。
第一个Filter类ChainFilter1 代码:
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ChainFilter1 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("资源访问前---ChainFilter1 -- 开始执行");
// 转发下一个Filter或者请求的资源
chain.doFilter(request, response);
System.out.println("资源访问后---ChainFilter1 -- 执行结束");
}
public void destroy() {
}
}
第二个Filter类ChainFilter2 代码:
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ChainFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("资源访问前---ChainFilter2 -- 开始执行");
// 转发下一个Filter或者请求的资源
chain.doFilter(request, response);
System.out.println("资源访问后---ChainFilter2 -- 执行结束");
}
public void destroy() {
}
}
<filter>
<filter-name>ChainFilter1filter-name>
<filter-class>com.atguigu.filter.ChainFilter1filter-class>
filter>
<filter-mapping>
<filter-name>ChainFilter1filter-name>
<url-pattern>/chainFilter.jspurl-pattern>
filter-mapping>
<filter>
<filter-name>ChainFilter2filter-name>
<filter-class>com.atguigu.filter.ChainFilter2filter-class>
filter>
<filter-mapping>
<filter-name>ChainFilter2filter-name>
<url-pattern>/chainFilter.jspurl-pattern>
filter-mapping>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>
<%
System.out.println("这是请求资源的代码");
%>
这是ChainFilter.jsp
body>
html>
千万要注意:在Filter类的doFilter方法中,除非你要拦截请求的资源,否则一定要调用FilterChain参数的doFilter方法让代码的执行传递到下一个Filter或访问的资源中
精确匹配 比如: /xxx/xxx/xxx.jsp 或 /xxx/xxx/xxx.html 等
目录匹配 比如:
/abc/* 表示可以拦截abc目录下的所有资源,甚至是abc目录下的其他目录,
/* 表示访问 当前工程下所有资源
后缀名匹配 比如:*.jsp 表示拦截所有后缀为jsp文件资源
精确匹配前面 ,我们已经演示过了。
下面我们以目录匹配为示例展示代码。大家可以在此基础上。修改web.xml文件中的<url-pattern>标签来测试自己想要的路径
1)Filter的代码如下:
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class FilterPath implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("filter path 执行了");
// 将代码执行传递到下一个Filter或者是请求资源
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
2)web.xml文件中的配置内容:
<filter>
<filter-name>FilterPathfilter-name>
<filter-class>com.atguigu.filter.FilterPathfilter-class>
filter>
<filter-mapping>
<filter-name>FilterPathfilter-name>
<url-pattern>/admin/*url-pattern>
filter-mapping>
1、使用Filter来拦截/pages/manager/目录下的所有页面。因为这些内容都属于管理员模块。
2、使用Filter和ThreadLocal组合来控制事务
根据咱们今天讲的Filter的知识点,我们只需要,在登录的时候,把用户的信息保存到Session对象中,
然后创建一个Filter类去检查Session对象中用户的登录信息。然后再去web.xml文件中去配置拦截的地址为/pages/manager/*即可。
1)修改UserServlet中登录的代码
/**
* 登录的操作
*
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
public void login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User t = new User();
Utils.copyMap2Bean(request.getParameterMap(), t);
// 根据用户名密码根据系统
User user = userService.loginByUsernameAndPassword(t);
// 如果user不为null,说明登录成功!
if (user != null) {
// 把用户添加到Session对象中
request.getSession().setAttribute("user", user);
System.out.println("[" + user.getUsername() + "]用户登录成功!跳转去登录成功页面login_success.jsp");
// 登录成功之后。转发到登录成功 页面
request.getRequestDispatcher("/pages/user/login_success.jsp")
.forward(request, response);
} else {
// 如果user == null ,说明登录失败,用户名错误,或者密码错误。
request.setAttribute("msg", "登录失败,用户名或密码错误!");
request.setAttribute("username", t.getUsername());
System.out.println("[" + t.getUsername() + "]用户登录失败!跳转去登录页面login.jsp");
request.getRequestDispatcher("/pages/user/login.jsp").forward(request, response);
}
}
2)
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.atguigu.bean.User;
public class ManagerFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//强转request为HttpServletRequest和response为HttpServletResponse
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取Session中的用户信息
User user = (User) httpRequest.getSession().getAttribute("user");
// 用户不为空,说明已登录
if (user != null) {
// 用户已登录,就继续访问资源
chain.doFilter(request, response);
} else {
// 没有登录就重定向到登录页面
httpResponse.sendRedirect(httpRequest.getContextPath() + "/pages/user/login.jsp");
}
}
public void destroy() { }
}
3)web.xml文件中的配置:
<filter>
<filter-name>managerFilterfilter-name>
<filter-class>com.atguigu.filter.ManagerFilterfilter-class>
filter>
<filter-mapping>
<filter-name>managerFilterfilter-name>
<url-pattern>/pages/manager/*url-pattern>
filter-mapping>
两个问题?
我们先来看第一个问题。我们以去结账生成订单为例。在结账生成订单的时候,我们要插入订单的信息,还要插入订单项的信息。还有修改图书的库存信息。这一系列的操作要么应该都成功 。要么应该都失败。比如说,当我们插入订单信息,成功之后,插入订单项之前抛了一个异常,而使得插入订单项,修改图书库存信息这一系列的操作都无法执行。那么数据库里就只有订单的信息,而找不到这个订单购买了什么商品。这种情况下,我们就需要使用数据库的事务来管理这一系列的数据库操作。当所有数据库的操作都成功之后 。我们再手动的提交事务。来确保这些操作的原子性。
现在我们来看看第二个问题。ThreadLocal类可以让我们在每个线程中存取当前线程使用的Connection对象,这样在下次获取的时候,就是同一个Connection连接
ThreadLocal使用,我们只需要记住三点:
一:ThreadLocal类可以让我们以当前线程为key保存一个线程内部变量。而不必担心线程安全问题。
二:ThreadLocal类一般是和static静态关键字组合使用。
三:ThreadLocal类存储的变量在线程销毁后。会被虚拟机自动gc,释放。
我们先来看一下。在线程里保存变量,然后在线程中取自己保存的变量的情况
1)map来实现线程保存变量:
package com.atguigu.threadlocal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class TestThreadLocal1 {
// 定义一个整型
private static Map
// 随机数对象
private static Random random = new Random(System.currentTimeMillis());
static class MyTask implements Runnable {
Map
public MyTask(Map
super();
this.map = map;
}
public void run() {
System.out.println(Thread.currentThread().getName() + " -- begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 生成随机数,用于相加
int num = random.nextInt(1000);
//
System.out.println(Thread.currentThread().getName() + "生成一个随机数:" + num);
// 把随机数保存到map中
map.put(Thread.currentThread().getName(), num);
// 用线程做key获取自己的变量
System.out.println("获取" + Thread.currentThread().getName() + " -- "
+ map.get(Thread.currentThread().getName()));
System.out.println(Thread.currentThread().getName() + " -- end");
}
}
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(new MyTask(map));
Thread t2 = new Thread(new MyTask(map));
t1.start();
t2.start();
}
}
2)ThreadLocal实现线程保存变量
package com.atguigu.threadlocal;
import java.util.Random;
public class TestThreadLocal2 {
// 定义一个整型
private static ThreadLocal
// 随机数对象
private static Random random = new Random(System.currentTimeMillis());
static class MyTask implements Runnable {
ThreadLocal
public MyTask(ThreadLocal
this.i = i;
}
public void run() {
System.out.println(Thread.currentThread().getName() + " -- begin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 生成随机数,用于相加
int num = random.nextInt(1000);
//
System.out.println(Thread.currentThread().getName() + "生成一个随机数:" + num);
// 把随机数保存到map中
i.set(num);
// 用线程做key获取自己的变量
System.out.println("获取" + Thread.currentThread().getName() + " -- " + i.get());
System.out.println(Thread.currentThread().getName() + " -- end");
}
}
public static void main(String[] args) throws Exception {
Thread t1 = new Thread(new MyTask(threadLocal));
Thread t2 = new Thread(new MyTask(threadLocal));
t1.start();
t2.start();
}
}
经过上面两个小示例的代码,我们可以知道,在多个线程里我们可以使用ThreadLocal保存线程自己需要的变量,而不需要担心线程安全的问题。所以我们只可以使用ThreadLocal来保存数据库的连接,这样,在一次请求中。是一个线程处理所有的操作。这样可以保正一个请求,使用相同的Connection对象。可以确保多个操作在一个连接的一个事务中完成。来达到。要么都成功 。要么都失败的效果。
以生成订单为例。来展示如何使用Filter和ThreadLocal管理事务
1)先修改JDBCUtils中代码。使用ThreadLocal管理Connection对象
package com.atguigu.util;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 获取数据库连接的工具类
*
* @author wzg
*
*/
public class JDBCUtils {
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("book_devoloper");
/**
* 使用ThreadLocal保存Connection对象
*/
private static ThreadLocal
private JDBCUtils() {
}
/**
* 获取数据库连接
*
* @return 如果获取连接成功,返回数据的连接对象。
* 如果获取数据库连接失败,则返回null
*/
public static Connection getConnection() {
// 先从ThreadLocal中获取
Connection connection = connectionThreadLocal.get();
try {
if (connection == null) {
// 从c3p0中获取数据库连接
connection = dataSource.getConnection();
// 设置事务为手动提交
connection.setAutoCommit(false);
connectionThreadLocal.set(connection);
}
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* 释放数据库连接
*/
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 释放数据库连接
*/
public static void closeConnection() {
// 从线程ThreadLocal中获取
Connection conn = connectionThreadLocal.get();
if (conn != null) {
try {
// 事务提交
conn.commit();
// 事务关闭
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 移除
connectionThreadLocal.remove();
}
public static void rollback() {
// 从线程ThreadLocal中获取
Connection conn = connectionThreadLocal.get();
if (conn != null) {
try {
// 事务回滚
conn.rollback();
// 关闭连接
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 移除
connectionThreadLocal.remove();
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(getConnection());
}
}
}
2)然后修改BaseDaoImpl的代码
记住,在BaseDaoImpl里,都不要再关闭Connection,因为要让所有的操作都在同一个Connection中使用,而且所有的异常都要往外抛。直到让Filter可以拦截到,做rollback回滚操作。
package com.atguigu.dao.impl;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import com.atguigu.util.JDBCUtils;
/**
* 我们使用的是DBUtil操作数据库
*
* @author wzg
*
* @param
*/
public abstract class BaseDaoImpl
/**
* DBUtils操作数据库需要使用的类
*/
protected QueryRunner queryRunner;
/**
* 保存BaseDaoImpl类的泛型对象class类型
*/
protected Class
@SuppressWarnings("unchecked")
public BaseDaoImpl() {
// 创建一个QueryRunner对象实例
queryRunner = new QueryRunner();
// 获取父类中带有泛型的父类的class类型
ParameterizedType supperClass = (ParameterizedType) getClass().getGenericSuperclass();
// 获取泛型中的具体的类型的class
type = (Class
}
/**
* 执行update,delete,insert语句
*
* @param sql
* 要执行的sql语句
* @param params
* 执行的sql语句的参数
* @return 如果语句执行成功返回true
* 如果执行失败返回false
* @throws SQLException
*/
public int update(String sql, Object... params) {
Connection connection = null;
int updateCount = 0;
try {
connection = JDBCUtils.getConnection();
updateCount = queryRunner.update(connection, sql, params);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return updateCount;
}
/**
* 执行查询语句,只返回第一个记录
*
* @param sql
* 要执行的sql语句
* @param params
* 执行的sql语句的参数
* @return 返回查询对象的具体实例
* 如果查询的数据不存在,则返回null
* 查询失败也返回null
* @throws SQLException
*/
public T queryOne(String sql, Object... params) {
Connection connection = null;
try {
// 获取数据库连接
connection = JDBCUtils.getConnection();
// 执行查询语句
return queryRunner.query(connection, sql, new BeanHandler
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 执行查询语句,返回查询后的对象实例集合
*
* @param sql
* 要执行的sql语句
* @param params
* sql语句的参数
* @return 返回的是查找到的对象集合
* 查询失败返回null
* @throws Exception
*/
public List
Connection connection = null;
try {
// 获取数据库连接
connection = JDBCUtils.getConnection();
// 执行查询语句
return queryRunner.query(connection, sql, new BeanListHandler
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 执行批量操作
*
* @param sql
* 要执行的sql语句
* @param params
* 参数
* @return 返回每个语句修改的数量
* @throws Exception
*/
public int[] batch(String sql, Object[][] params) {
Connection connection = null;
try {
// 获取数据库连接
connection = JDBCUtils.getConnection();
// 执行查询语句
return queryRunner.batch(connection, sql, params);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 查询只有一个返回值的语句
*
* @param sql
* @param params
* @return
* @throws Exception
*/
public Object querySingleValue(String sql, Object... params) {
Connection connection = null;
try {
// 获取数据库连接
connection = JDBCUtils.getConnection();
// 执行查询语句
return queryRunner.query(connection, sql, new ScalarHandler(), params);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
3)修改BaseServlet的方法调用,代码如下 :
在下面的代码中,一定要把所有的异常,都使用RuntimeException包装起来往外抛。这样Filter里才能收到异常,否则异常只会到BaseServlet就会终止,而不会继续往外抛
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 解决post乱码问题,设置请求的参数字符集为UTf-8
request.setCharacterEncoding("UTF-8");
// action参数就可以用来判断是当前用户模块的哪一个操作。
String action = request.getParameter("action");
// 定义一个Method方法对象
Method actionMethod;
try {
// 通过反射获取到与action字符串对应的操作方法
actionMethod = getClass().getDeclaredMethod(action, HttpServletRequest.class,
HttpServletResponse.class);
// System.out.println(actionMethod);
// 调用Method对象的invoke函数执行方法
actionMethod.invoke(this, request, response);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
4)添加TransactionFilter类管理事务
package com.atguigu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.atguigu.util.JDBCUtils;
/**
* TrasactionFilter类用于管理事务
*/
public class TransactionFilter implements Filter {
public TransactionFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
// 放行操作
chain.doFilter(request, response);
// 关闭连接,并提交事务
JDBCUtils.closeConnection();
} catch (Exception e) {
// 回滚 事务
JDBCUtils.rollback();
throw e;
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
5)在web.xml文件中的配置
<filter>
<filter-name>TransactionFilterfilter-name>
<filter-class>com.atguigu.filter.TransactionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>TransactionFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<error-page>
<error-code>500error-code>
<location>/error500.jsplocation>
error-page>
6)error500.jsp页面中的错误提示
一般每个项目都有自己错误提示页面。等在实际项目中,只需要把这个内容改成你公司提示的页面即可。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<body>
系统出现故障,我们马上为您解决。请耐心等待!<a href="${pageContext.request.contextPath }">返回首页a>
body>
html>