过滤器
图示
相关代码
Demo01Servlet
package com.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;
/**
* @ClassName: Demo01Servlet
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebServlet("/demo01.do")
public class Demo01Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo01Servlet");
response.sendRedirect("succ.html");
}
}
Demo01Filters
package com.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @ClassName: Demo01Filters
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
// @WebFilter("/demo01.do")
// @WebFilter("*.do")
public class Demo01Filters implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("hello A");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
// 响应后用这个
System.out.println("hello A2");
}
@Override
public void destroy() {
}
}
Demo02Servlet
package com.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;
/**
* @ClassName: Demo01Servlet
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebServlet("/demo02.do")
public class Demo02Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo02Servlet");
response.sendRedirect("succ.html");
}
}
输出结果
hello A
Demo01Servlet
hello A2
Demo02Servlet
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">
<filter>
<filter-name>Demo01Filters</filter-name>
<filter-class>com.filters.Demo01Filters</filter-class>
</filter>
<filter-mapping>
<filter-name>Demo01Filters</filter-name>
<url-pattern>/demo01.do</url-pattern>
</filter-mapping>
</web-app>
注解写过滤器
package com.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @ClassName: Demo01Filters
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter("/demo01.do")
// @WebFilter("*.do")
public class Demo01Filters implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("hello A");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
// 响应后用这个
System.out.println("hello A2");
}
@Override
public void destroy() {
}
}
过滤器链
相关代码
Filter01
package com.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName: Filter01
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter("/demo03.do")
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("A");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("A2");
}
@Override
public void destroy() {
}
}
Filter02
package com.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
/**
* @ClassName: Filter02
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter("/demo03.do")
public class Filter02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("B");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("B2");
}
@Override
public void destroy() {
}
}
Filter03
package com.filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
/**
* @ClassName: Filter03
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter("/demo03.do")
public class Filter03 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("C");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("C2");
}
@Override
public void destroy() {
}
}
Demo03Servlet
package com.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;
/**
* @ClassName: Demo03Servlet
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebServlet("/demo03.do")
public class Demo03Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Demo03Servlet");
}
}
输出结果
A
B
C
Demo03Servlet
C2
B2
A2
特别注意.先后顺序
- 如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
- 如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
优化2.3增加过滤器
类图
相关代码
CharacterEncodingFilter
package com.atguigu.myssm.filters;
import com.atguigu.uils.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @ClassName: CharacterEncodingFilter
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter(urlPatterns = {"*.do"}, initParams = {@WebInitParam(name = "characterEncoding", value = "UTF-8")})
public class CharacterEncodingFilter implements Filter {
private String characterEncoding = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String characterEncodingStr = filterConfig.getInitParameter("characterEncoding");
if (StringUtils.isNotEmpty(characterEncodingStr)) {
characterEncoding = characterEncodingStr;
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 强转
((HttpServletRequest) servletRequest).setCharacterEncoding(characterEncoding);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
DispatcherServlet
package com.atguigu.myssm.myspringmvc;
import com.atguigu.myssm.io.BeanFactory;
import com.atguigu.myssm.io.ClassPathXmlApplicationContext;
import com.atguigu.uils.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @ClassName: DispatcherServlet
* @Description:
* @Author: wty
* @Date: 2022/12/7
*/
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
private BeanFactory beanFactory = null;
public DispatcherServlet() {
}
/**
* @param
* @return void
* @description Servlet初始化阶段,并且初始化BeanFactory对象
* @date 2022/12/8 10:54
* @author wty
**/
@Override
public void init() throws ServletException {
super.init();
beanFactory = new ClassPathXmlApplicationContext();
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置编码
// request.setCharacterEncoding("UTF-8");
// 假设URL是:http://localhost:8080/pro15/hello.do
// 那么servletPath 是hello.do
String servletPath = request.getServletPath();
/// hello.do
System.out.println(servletPath);
// 1.字符串截取 hello.do 得到 hello
servletPath = servletPath.substring(1, servletPath.length() - 3);
System.out.println(servletPath);
// 2. hello 和 helloController对应上
Object contorllerBeanObject = beanFactory.getBean(servletPath);
// 下面的逻辑来自于FruitController
String operate = request.getParameter("operate");
if (StringUtils.isEmpty(operate)) {
operate = "index";
}
try {
Method declaredMethods[] = contorllerBeanObject.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (operate.equals(declaredMethod.getName())) {
// 1.统一获取请求参数
// 获取当前方法的所有参数,返回参数数组
Parameter[] parameters = declaredMethod.getParameters();
// parametersobjectsValue用来存放参数的值
Object[] parametersobjectsValue = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String parameterName = parameter.getName();
// 如果参数名是request、response、session那么单独处理
if ("request".equals(parameterName)) {
parametersobjectsValue[i] = request;
} else if ("response".equals(parameterName)) {
parametersobjectsValue[i] = response;
} else if ("session".equals(parameterName)) {
parametersobjectsValue[i] = request.getSession();
} else {
// 从请求中获取参数值
String parameterValue = request.getParameter(parameterName);
//当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
// 最后的2在parameterValue中是"2"会报错argument type mismatch
String typeName = parameter.getType().getName();
if ("java.lang.String".equals(typeName)) {
parametersobjectsValue[i] = parameterValue;
} else if (null != parameterValue && "java.lang.Integer".equals(typeName)) {
parametersobjectsValue[i] = Integer.parseInt(parameterValue);
} else {
parametersobjectsValue[i] = parameterValue;
}
}
}
// 2.controller组件中的方法调用
declaredMethod.setAccessible(true);
Object o = declaredMethod.invoke(contorllerBeanObject, parametersobjectsValue);
// 3.视图处理:
String methodReturnStr = (String) o;
if (methodReturnStr.startsWith("redirect")) {
// 比如 redirect:fruit.do
// 截取后只想要 fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
response.sendRedirect(redirectStr);
} else {
// 比如 edit
super.processTemplate(methodReturnStr, request, response);
}
} else {
//throw new RuntimeException("operate值非法!");
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
// 常间错误 argument type mismatch
// 当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
增加事务控制
目前的事务管理形式存在的问题
更改后的事务形式
类图
通过OpenSessionInViewFilter过滤器实现上层抛错
相关代码
BasicDAO
package com.atguigu.fruit.basic;
import com.atguigu.fruit.exceptions.DAOException;
import com.atguigu.uils.DruidUtils;
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 java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* @ClassName: BasicDAO
* @Description:
* @Author: wty
* @Date: 2022/12/5
*/
public class BasicDAO<T> {
private QueryRunner queryRunner = new QueryRunner();
/**
* @param
* @return int
* @description //TODO
* @param: sqlStr
* @param: params
* @date 2022/12/4 17:53
* @author wty
**/
public int dml(String sqlStr, Object... params) {
Connection connection = null;
int affectedrows = 0;
try {
connection = DruidUtils.getConnection();
affectedrows = queryRunner.update(connection, sqlStr, params);
} catch (SQLException e) {
e.printStackTrace();
throw new DAOException("BasicDAO dml出错!");
} finally {
DruidUtils.close(null, null, connection);
}
return affectedrows;
}
/**
* @return java.util.List<T>
* @description 返回多行结果
* @param: sqlStr
* @param: clazz
* @param: params
* @date 2022/12/4 17:59
* @author wty
**/
public List<T> queryMulti(String sqlStr, Class<T> clazz, Object... params) {
Connection connection = null;
List<T> list = null;
try {
connection = DruidUtils.getConnection();
list = queryRunner.query(connection, sqlStr, new BeanListHandler<T>(clazz), params);
} catch (Exception e) {
e.printStackTrace();
throw new DAOException("BasicDAO queryMulti出错!");
} finally {
DruidUtils.close(null, null, connection);
}
return list;
}
/**
* @param
* @return T
* @description 返回单行多列数据
* @param: sqlStr
* @param: clazz
* @param: params
* @date 2022/12/4 18:01
* @author wty
**/
public T querySingle(String sqlStr, Class<T> clazz, Object... params) {
Connection connection = null;
T t = null;
try {
connection = DruidUtils.getConnection();
t = queryRunner.query(connection, sqlStr, new BeanHandler<T>(clazz), params);
} catch (Exception e) {
e.printStackTrace();
throw new DAOException("BasicDAO querySingle出错!");
} finally {
DruidUtils.close(null, null, connection);
}
return t;
}
public Object queryScalar(String sqlStr, Object... params) {
Connection connection = null;
Object o = null;
try {
connection = DruidUtils.getConnection();
o = queryRunner.query(connection, sqlStr, new ScalarHandler(), params);
} catch (Exception e) {
e.printStackTrace();
throw new DAOException("BasicDAO queryScalar出错!");
} finally {
DruidUtils.close(null, null, connection);
}
return o;
}
}
DAOException
package com.atguigu.fruit.exceptions;
/**
* @ClassName: 抛出异常整合
* @Description:
* @Author: wty
* @Date: 2022/12/9
*/
public class DAOException extends RuntimeException {
public DAOException(String msg) {
super(msg);
}
}
DispatcherServletException
package com.atguigu.fruit.exceptions;
/**
* @ClassName: DispatcherServletException
* @Description:
* @Author: wty
* @Date: 2022/12/9
*/
public class DispatcherServletException extends RuntimeException {
public DispatcherServletException(String msg) {
super(msg);
}
}
CharacterEncodingFilter
package com.atguigu.myssm.filters;
import com.atguigu.uils.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @ClassName: CharacterEncodingFilter
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter(urlPatterns = {"*.do"}, initParams = {@WebInitParam(name = "characterEncoding", value = "UTF-8")})
public class CharacterEncodingFilter implements Filter {
private String characterEncoding = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String characterEncodingStr = filterConfig.getInitParameter("characterEncoding");
if (StringUtils.isNotEmpty(characterEncodingStr)) {
characterEncoding = characterEncodingStr;
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 强转
((HttpServletRequest) servletRequest).setCharacterEncoding(characterEncoding);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
OpenSessionInViewFilter
package com.atguigu.myssm.filters;
import com.atguigu.myssm.trans.TransactionManager;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.sql.SQLException;
/**
* @ClassName: OpenSessionInViewFilter
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
@WebFilter("*.do")
public class OpenSessionInViewFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
// 开启事务
TransactionManager.beginTrans();
System.out.println("开启事务");
filterChain.doFilter(servletRequest, servletResponse);
// 提交事务
TransactionManager.commit();
System.out.println("提交事务");
} catch (Exception e) {
try {
TransactionManager.rollback();
System.out.println("回滚事务");
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
@Override
public void destroy() {
}
}
DispatcherServlet
package com.atguigu.myssm.myspringmvc;
import com.atguigu.fruit.exceptions.DispatcherServletException;
import com.atguigu.myssm.io.BeanFactory;
import com.atguigu.myssm.io.ClassPathXmlApplicationContext;
import com.atguigu.uils.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @ClassName: DispatcherServlet
* @Description:
* @Author: wty
* @Date: 2022/12/7
*/
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
private BeanFactory beanFactory = null;
public DispatcherServlet() {
}
/**
* @param
* @return void
* @description Servlet初始化阶段,并且初始化BeanFactory对象
* @date 2022/12/8 10:54
* @author wty
**/
@Override
public void init() throws ServletException {
super.init();
beanFactory = new ClassPathXmlApplicationContext();
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置编码
// request.setCharacterEncoding("UTF-8");
// 假设URL是:http://localhost:8080/pro15/hello.do
// 那么servletPath 是hello.do
String servletPath = request.getServletPath();
/// hello.do
System.out.println(servletPath);
// 1.字符串截取 hello.do 得到 hello
servletPath = servletPath.substring(1, servletPath.length() - 3);
System.out.println(servletPath);
// 2. hello 和 helloController对应上
Object contorllerBeanObject = beanFactory.getBean(servletPath);
// 下面的逻辑来自于FruitController
String operate = request.getParameter("operate");
if (StringUtils.isEmpty(operate)) {
operate = "index";
}
try {
Method declaredMethods[] = contorllerBeanObject.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (operate.equals(declaredMethod.getName())) {
// 1.统一获取请求参数
// 获取当前方法的所有参数,返回参数数组
Parameter[] parameters = declaredMethod.getParameters();
// parametersobjectsValue用来存放参数的值
Object[] parametersobjectsValue = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String parameterName = parameter.getName();
// 如果参数名是request、response、session那么单独处理
if ("request".equals(parameterName)) {
parametersobjectsValue[i] = request;
} else if ("response".equals(parameterName)) {
parametersobjectsValue[i] = response;
} else if ("session".equals(parameterName)) {
parametersobjectsValue[i] = request.getSession();
} else {
// 从请求中获取参数值
String parameterValue = request.getParameter(parameterName);
//当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
// 最后的2在parameterValue中是"2"会报错argument type mismatch
String typeName = parameter.getType().getName();
if ("java.lang.String".equals(typeName)) {
parametersobjectsValue[i] = parameterValue;
} else if (null != parameterValue && "java.lang.Integer".equals(typeName)) {
parametersobjectsValue[i] = Integer.parseInt(parameterValue);
} else {
parametersobjectsValue[i] = parameterValue;
}
}
}
// 2.controller组件中的方法调用
declaredMethod.setAccessible(true);
Object o = declaredMethod.invoke(contorllerBeanObject, parametersobjectsValue);
// 3.视图处理:
String methodReturnStr = (String) o;
if (methodReturnStr.startsWith("redirect")) {
// 比如 redirect:fruit.do
// 截取后只想要 fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
response.sendRedirect(redirectStr);
} else {
// 比如 edit
super.processTemplate(methodReturnStr, request, response);
}
} else {
//throw new RuntimeException("operate值非法!");
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new DispatcherServletException("DispatcherServlet 出错了!");
}
}
}
// 常间错误 argument type mismatch
// 当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
TransactionManager
package com.atguigu.myssm.trans;
import com.atguigu.uils.DruidUtils;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @ClassName: TransactionManager
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
public class TransactionManager {
// 开启事务
public static void beginTrans() throws SQLException {
Connection connection = DruidUtils.getConnection();
connection.setAutoCommit(false);
}
// 提交事务
public static void commit() throws SQLException {
Connection connection = DruidUtils.getConnection();
connection.commit();
// 关闭连接
DruidUtils.closeConnection();
}
// 回滚事务
public static void rollback() throws SQLException {
Connection connection = DruidUtils.getConnection();
connection.rollback();
// 关闭连接
DruidUtils.closeConnection();
}
}
DruidUtils
package com.atguigu.uils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @ClassName: DruidUtils
* @Description:
* @Author: wty
* @Date: 2022/12/5
*/
public class DruidUtils {
private static DataSource dataSource;
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("F:\\javawebwork\\pro20-javaweb-fruit2.3-transaction\\src\\druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 获取链接
* @Author: wty
* @Date: 2022/12/4
*/
public static Connection getConnection() {
Connection connection = null;
try {
connection = threadLocal.get();
if (null == connection) {
connection = dataSource.getConnection();
threadLocal.set(connection);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return threadLocal.get();
}
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
//try {
//
// if (null != resultSet) {
// resultSet.close();
// }
// if (null != statement) {
// statement.close();
// }
// if (null != connection) {
// connection.close();
// }
//} catch (SQLException e) {
// throw new RuntimeException(e);
//}
}
public static void closeConnection() throws SQLException {
Connection connection = threadLocal.get();
if (null == connection) {
return;
}
if (!connection.isClosed()) {
connection.close();
threadLocal.set(null);
}
}
}
输出
开启事务
/fruit.do
fruit
getFruitList中的connection:com.mysql.jdbc.JDBC4Connection@d37fec3
getFruitCount的connection是com.mysql.jdbc.JDBC4Connection@d37fec3
提交事务
监听器
图示
xml配置
<listener>
<listener-class>com.atguigu.listener.MyServletContextListener</listener-class>
</listener>
注解配置
package com.atguigu.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* @ClassName: MyServletContextListener
* @Description:
* @Author: wty
* @Date: 2022/12/9
*/
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("Servlet上下文对象初始化被我监听到了!");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("Servlet上下文对象销毁被我监听到了!");
}
}
输出结果
Tomcat启动
Tomcat关闭
优化水果库存增加监听器
类图
相关代码
ClassPathXmlApplicationContext
package com.atguigu.myssm.ioc;
import com.atguigu.uils.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName: ClassPathXmlApplicationContext
* @Description:
* @Author: wty
* @Date: 2022/12/8
*/
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beanMap = new HashMap<>();
private String path = "applicationContext.xml";
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
public ClassPathXmlApplicationContext() {
this("applicationContext.xml");
}
/**
* @param
* @return
* @description //构造方法
* @date 2022/12/8 10:49
* @author wty
**/
public ClassPathXmlApplicationContext(String path) {
if (StringUtils.isEmpty(path)) {
throw new RuntimeException("IOC 配置文件未指定(ClassPathXmlApplicationContext)");
}
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
// 1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
// 2.创建DocumentBuilder
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// 3.创建Document
Document document = documentBuilder.parse(inputStream);
// 4.获取所有的bean结点
NodeList beanNodeList = document.getElementsByTagName("bean");
for (int i = 0; i < beanNodeList.getLength(); i++) {
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
// 创建bean对象和bean实例
Class<?> beanClass = Class.forName(className);
// 类对象
Object beanObject = beanClass.newInstance();
// 加入servletContext
//Field servletContextField = beanObj.getDeclaredField("servletContext");
//servletContextField.setAccessible(true);
//servletContextField.set(o, this.getServletContext());
//Method setServletContext = beanObj.getDeclaredMethod("setServletContext", ServletContext.class);
//setServletContext.invoke(o, this.getServletContext());
// 将bean对象保存到beanMap中
beanMap.put(beanId, beanObject);
// 到目前位置需要注意bean之间的依赖关系
}
}
// 5. 组装bean之间的依赖关系
for (int i = 0; i < beanNodeList.getLength(); i++) {
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
NodeList beanchildNodeList = beanElement.getChildNodes();
System.out.println(beanchildNodeList.getLength());
for (int j = 0; j < beanchildNodeList.getLength(); j++) {
Node beanChildNode = beanchildNodeList.item(j);
/**
*
* Node 结点
* Element 元素节点 sname
* Text 文本节点 jim
* <sname>jim</sname>
*
*/
if (beanChildNode.getNodeType() == Node.ELEMENT_NODE
&& "property".equals(beanChildNode.getNodeName())) {
Element propertyElement = (Element) beanChildNode;
String propertyName = propertyElement.getAttribute("name");
String propertyref = propertyElement.getAttribute("ref");
// 1.找到propertyref对应的实例propertyName
Object refObject = beanMap.get(propertyref);
// 2.将refObject设置到当前bean对应的实例的property属性上
Object beanObject = beanMap.get(beanId);
Class<?> beanClass = beanObject.getClass();
Field propertyField = beanClass.getDeclaredField(propertyName);
propertyField.setAccessible(true);
propertyField.set(beanObject, refObject);
}
}
}
}
} catch (ParserConfigurationException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException | ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
ContextLoaderListener
package com.atguigu.myssm.listeners;
import com.atguigu.myssm.ioc.BeanFactory;
import com.atguigu.myssm.ioc.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* @ClassName: ContextLoaderListener
* @Description: 监听器上下文启动,在上下文启动的时候创建IOC容器,然后将其保存到application作用域,之后中央控制器从application作用域获取IOC容器
* @Author: wty
* @Date: 2022/12/9
*/
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext application = servletContextEvent.getServletContext();
String path = application.getInitParameter("contextConfigLocation");
BeanFactory beanFactory = new ClassPathXmlApplicationContext(path);
application.setAttribute("beanFactory", beanFactory);
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
DispatcherServlet
package com.atguigu.myssm.myspringmvc;
import com.atguigu.fruit.exceptions.DispatcherServletException;
import com.atguigu.myssm.ioc.BeanFactory;
import com.atguigu.uils.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @ClassName: DispatcherServlet
* @Description:
* @Author: wty
* @Date: 2022/12/7
*/
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
private BeanFactory beanFactory = null;
public DispatcherServlet() {
}
/**
* @param
* @return void
* @description Servlet初始化阶段,并且初始化BeanFactory对象
* @date 2022/12/8 10:54
* @author wty
**/
@Override
public void init() throws ServletException {
super.init();
// 之前是在此处主动创建IOC容器
// beanFactory = new ClassPathXmlApplicationContext();
// 现在优化为从application作用域去获取
Object objectBeanFactory = getServletContext().getAttribute("beanFactory");
if (null != objectBeanFactory) {
beanFactory = (BeanFactory) objectBeanFactory;
} else {
throw new DispatcherServletException("DispatcherServlet 出错了!");
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置编码
// request.setCharacterEncoding("UTF-8");
// 假设URL是:http://localhost:8080/pro15/hello.do
// 那么servletPath 是hello.do
String servletPath = request.getServletPath();
/// hello.do
System.out.println(servletPath);
// 1.字符串截取 hello.do 得到 hello
servletPath = servletPath.substring(1, servletPath.length() - 3);
System.out.println(servletPath);
// 2. hello 和 helloController对应上
Object contorllerBeanObject = beanFactory.getBean(servletPath);
// 下面的逻辑来自于FruitController
String operate = request.getParameter("operate");
if (StringUtils.isEmpty(operate)) {
operate = "index";
}
try {
Method declaredMethods[] = contorllerBeanObject.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (operate.equals(declaredMethod.getName())) {
// 1.统一获取请求参数
// 获取当前方法的所有参数,返回参数数组
Parameter[] parameters = declaredMethod.getParameters();
// parametersobjectsValue用来存放参数的值
Object[] parametersobjectsValue = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String parameterName = parameter.getName();
// 如果参数名是request、response、session那么单独处理
if ("request".equals(parameterName)) {
parametersobjectsValue[i] = request;
} else if ("response".equals(parameterName)) {
parametersobjectsValue[i] = response;
} else if ("session".equals(parameterName)) {
parametersobjectsValue[i] = request.getSession();
} else {
// 从请求中获取参数值
String parameterValue = request.getParameter(parameterName);
//当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
// 最后的2在parameterValue中是"2"会报错argument type mismatch
String typeName = parameter.getType().getName();
if ("java.lang.String".equals(typeName)) {
parametersobjectsValue[i] = parameterValue;
} else if (null != parameterValue && "java.lang.Integer".equals(typeName)) {
parametersobjectsValue[i] = Integer.parseInt(parameterValue);
} else {
parametersobjectsValue[i] = parameterValue;
}
}
}
// 2.controller组件中的方法调用
declaredMethod.setAccessible(true);
Object o = declaredMethod.invoke(contorllerBeanObject, parametersobjectsValue);
// 3.视图处理:
String methodReturnStr = (String) o;
if (methodReturnStr.startsWith("redirect")) {
// 比如 redirect:fruit.do
// 截取后只想要 fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
response.sendRedirect(redirectStr);
} else {
// 比如 edit
super.processTemplate(methodReturnStr, request, response);
}
} else {
//throw new RuntimeException("operate值非法!");
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new DispatcherServletException("DispatcherServlet 出错了!");
}
}
}
// 常间错误 argument type mismatch
// 当前页面http://localhost:8080/pro16/fruit.do?pageNumber=2
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">
<!-- 配置上下文参数 -->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
</web-app>
最终系统框架图
总结
今日内容:
1. 过滤器Filter
2. 事务管理(TransactionManager、ThreadLocal、OpenSessionInViewFilter)
3. 监听器(Listener , ContextLoaderListener)
1.过滤器Filter
- Filter也属于Servlet规范
- Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
配置Filter,可以用注解@WebFilter,也可以使用xml文件 - Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter(“*.do”)表示拦截所有以.do结尾的请求
- 过滤器链
1)执行的顺序依次是: A B C demo03 C2 B2 A2
2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
2.事务管理
-
涉及到的组件:
- OpenSessionInViewFilter
- TransactionManager
- ThreadLocal
- ConnUtil
- BaseDAO -
ThreadLocal
- get() , set(obj)
- ThreadLocal称之为本地线程 。 我们可以通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据
- set方法源码分析:
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前的线程
ThreadLocalMap map = getMap(t); //每一个线程都维护各自的一个容器(ThreadLocalMap)
if (map != null)
map.set(this, value); //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection)
else
createMap(t, value); //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化
}
-get方法源码分析:
public T get() {
Thread t = Thread.currentThread(); //获取当前的线程
ThreadLocalMap map = getMap(t); //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合)
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带
if (e != null) {
@SuppressWarnings(“unchecked”)
T result = (T)e.value; //entry.value就可以获取到工具箱了
return result;
}
}
return setInitialValue();
}
3.监听器
1) ServletContextListener - 监听ServletContext对象的创建和销毁的过程
2) HttpSessionListener - 监听HttpSession对象的创建和销毁的过程
3) ServletRequestListener - 监听ServletRequest对象的创建和销毁的过程
4) ServletContextAttributeListener - 监听ServletContext的保存作用域的改动(add,remove,replace)
5) HttpSessionAttributeListener - 监听HttpSession的保存作用域的改动(add,remove,replace)
6) ServletRequestAttributeListener - 监听ServletRequest的保存作用域的改动(add,remove,replace)
7) HttpSessionBindingListener - 监听某个对象在Session域中的创建与移除
8) HttpSessionActivationListener - 监听某个对象在Session域中的序列化和反序列化
4.ServletContextListener的应用 - ContextLoaderListener