Java web 2022跟学尚硅谷(六) 后端基础

过滤器

图示

过滤器

相关代码

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
特别注意.先后顺序
  1. 如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
  2. 如果采取的是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

增加事务控制

目前的事务管理形式存在的问题

增加事务控制

更改后的事务形式

在这里插入图片描述

类图

类图1
类图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启动

输出结果1

Tomcat关闭

输出结果2

优化水果库存增加监听器

类图

类图

相关代码

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

  1. Filter也属于Servlet规范
  2. Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
    配置Filter,可以用注解@WebFilter,也可以使用xml文件
  3. Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter(“*.do”)表示拦截所有以.do结尾的请求
  4. 过滤器链
    1)执行的顺序依次是: A B C demo03 C2 B2 A2
    2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
    3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序

2.事务管理

  1. 涉及到的组件:
    - OpenSessionInViewFilter
    - TransactionManager
    - ThreadLocal
    - ConnUtil
    - BaseDAO

  2. 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心向阳光的天域

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值