JavaWeb学习|Filter与ThreadLocal

学习材料声明

所有知识点都来自互联网,进行总结和梳理,侵权必删。
引用来源:尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版

Filter

1、Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter过滤器
2、Filter 过滤器它是 JavaEE 的规范。也就是接口
3、Filter 过滤器它的作用是:拦截请求,过滤响应。拦截请求常见的应用场景有: 1、权限检查 2、日记操作 3、事务管理(这个在书城项目里有实践) ……等等

1.情景实践(要求未登录情况,浏览器不能访问admin目录下的所有文件)

设置filter类,继承Filter,编写doFilter
在web.xml里面配置filter的url。
在这里插入图片描述
Filter:

public class AdminFilter implements Filter {
	/**
	* doFilter 方法,专门用于拦截请求。可以做权限检查
	*/
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChainfilterChain) throws IOException, ServletException {
		HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
		HttpSession session = httpServletRequest.getSession();
		Object user = session.getAttribute("user");
		// 如果等于 null,说明还没有登录
		if (user == null) {
			servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
			return;
		} else {
			// 让程序继续往下访问用户的目标资源
			filterChain.doFilter(servletRequest,servletResponse);
		}
	}
}

配置:

<!--filter 标签用于配置一个 Filter 过滤器-->
<filter>
	<!--给 filter 起一个别名-->
	<filter-name>AdminFilter</filter-name>
	<!--配置 filter 的全类名-->
	<filter-class>com.atguigu.filter.AdminFilter</filter-class>
</filter>
<!--filter-mapping 配置 Filter 过滤器的拦截路径-->
<filter-mapping>
	<!--filter-name 表示当前的拦截路径给哪个 filter 使用-->
	<filter-name>AdminFilter</filter-name>
	<!--url-pattern 配置拦截路径
	/ 表示请求地址为:http://ip:port/工程路径/ 映射到 IDEA 的 web 目录
	/admin/* 表示请求地址为:http://ip:port/工程路径/admin/*-->
	<url-pattern>/admin/*</url-pattern>
</filter-mapping>

2.Filter过滤的整个生命周期

Filter 的生命周期包含几个方法
1、构造器方法
2、init 初始化方法
第 1,2 步,在 web 工程启动的时候执行(Filter 已经创建)
3、doFilter 过滤方法
第 3 步,每次拦截到请求,就会执行
4、destroy 销毁
第 4 步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)

3.Filter的一些配置

和servlet一样,filter也可以配置一些东西。

FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
FilterConfig 类的作用是获取 filter 过滤器的配置内容
1、获取 Filter 的名称 filter-name 的内容
2、获取在 Filter 中配置的 init-param 初始化参数
3、获取 ServletContext 对象

web.xml里面配置初始化参数

<!--filter 标签用于配置一个 Filter 过滤器-->
<filter>
	<!--给 filter 起一个别名-->
	<filter-name>AdminFilter</filter-name>
	<!--配置 filter 的全类名-->
	<filter-class>com.atguigu.filter.AdminFilter</filter-class>
	<init-param>
		<param-name>username</param-name>
		<param-value>root</param-value>
	</init-param>
	<init-param>
		<param-name>url</param-name>
		<param-value>jdbc:mysql://localhost3306/test</param-value>
	</init-param>
</filter>

如何在filter类里面获取:

@Override
public void init(FilterConfig filterConfig) throws ServletException {
	System.out.println("2.Filter 的 init(FilterConfig filterConfig)初始化");
	// 1、获取 Filter 的名称 filter-name 的内容
	System.out.println("filter-name 的值是:" + filterConfig.getFilterName());
	// 2、获取在 web.xml 中配置的 init-param 初始化参数
	System.out.println("初始化参数 username 的值是:" + filterConfig.getInitParameter("username"));
	System.out.println("初始化参数 url 的值是:" + filterConfig.getInitParameter("url"));
	// 3、获取 ServletContext 对象
	System.out.println(filterConfig.getServletContext());
}

4.FilterChain 过滤器链

整个过滤器流程,同时,在web.xml里面的配置顺序代表了整个过滤流程的顺序。
在这里插入图片描述

5.拦截路径

精确匹配
/target.jsp
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp

目录匹配
/admin/
以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/

后缀名匹配
.html
以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
.do
以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
*.action
以上配置的路径,表示请求地址必须以.action 结尾才会拦截到
Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在!!!
请记住,可以同时配置多个。

ThreadLocal

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

1.一个小实践

//创建
public static ThreadLocal threadLocal = new ThreadLocal();
//绑定
threadLocal.set(i);
//获取
Object o = threadLocal.get();

public class ThreadLocalTest {
	// public static Map<String,Object> data = new Hashtable<String,Object>();
	//创建
	public static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();
	private static Random random = new Random();
	public static class Task implements Runnable {
		@Override
		public void run() {
			// 在 Run 方法中,随机生成一个变量(线程要关联的数据),然后以当前线程名为 key 保存到 map 中
			Integer i = random.nextInt(1000);
			// 获取当前线程名
			String name = Thread.currentThread().getName();
			System.out.println("线程["+name+"]生成的随机数是:" + i);
			// data.put(name,i);
			//绑定
			threadLocal.set(i);
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			new OrderService().createOrder();
			// 在 Run 方法结束之前,以当前线程名获取出数据并打印。查看是否可以取出操作
			// Object o = data.get(name);
			//获取
			Object o = threadLocal.get();
			System.out.println("在线程["+name+"]快结束时取出关联的数据是:" + o);
		}
	}
	public static void main(String[] args) {
		for (int i = 0; i < 3; i++){
		new Thread(new Task()).start();
	}
	}
}

2.书城项目是要求利用Filter和ThreadLocal是组合管理事务。

这里涉及线程的知识,啊啊啊,忘得差不多了。
使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完成。
主要的改动在JDBC,然后设置Filter来统一处理提交和回滚。同时要记得千万要抛出异常,才能实现回滚。
在这里插入图片描述
JDBC里改动,要创建ThreadLocal绑定conn。然后设置提交和回滚。

public class JdbcUtils {
	private static DruidDataSource dataSource;
	private static ThreadLocal<Connection> conns = new ThreadLocal<Connection>();
	static {
		try {
			Properties properties = new Properties();
			// 读取 jdbc.properties 属性配置文件
			InputStream inputStream =
			JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
			// 从流中加载数据
			properties.load(inputStream);
			// 创建 数据库连接 池
			dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	* 获取数据库连接池中的连接
	* @return 如果返回 null,说明获取连接失败<br/>有值就是获取连接成功
	*/
	public static Connection getConnection(){
		Connection conn = conns.get();
		if (conn == null) {
			try {
				conn = dataSource.getConnection();//从数据库连接池中获取连接
				conns.set(conn); // 保存到 ThreadLocal 对象中,供后面的 jdbc 操作使用
				conn.setAutoCommit(false); // 设置为手动管理事务
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return conn;
	}
	/**
	* 提交事务,并关闭释放连接
	*/
	public static void commitAndClose(){
		Connection connection = conns.get();
		if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库
			try {
				connection.commit(); // 提交 事务
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					connection.close(); // 关闭连接,资源资源
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		// 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
		conns.remove();
	}
	/**
	* 回滚事务,并关闭释放连接
	*/
	public static void rollbackAndClose(){
		Connection connection = conns.get();
		if (connection != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库
			try {
				connection.rollback();//回滚事务
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				try {
					connection.close(); // 关闭连接,资源资源
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		// 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
		conns.remove();
	}
}

其他部分Dao

catch (SQLException e) {
	e.printStackTrace();
	throw new RuntimeException(e);
}

利用FIlter:给所有的 Service 方法都加上 try-catch。来进行实现的管理。
在这里插入图片描述

public class TransactionFilter implements Filter {
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		try {
			filterChain.doFilter(servletRequest,servletResponse);
			JdbcUtils.commitAndClose();// 提交事务
		} catch (Exception e) {
		JdbcUtils.rollbackAndClose();//回滚事务
			e.printStackTrace();
		}
	}
}
在 web.xml 中的配置:
<filter>
	<filter-name>TransactionFilter</filter-name>
	<filter-class>com.atguigu.filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>TransactionFilter</filter-name>
	<!-- /* 表示当前工程下所有请求 -->
	<url-pattern>/*</url-pattern>
</filter-mapping> 

BaseServlet 中的异常往外抛给 Filter 过滤器

public abstract class BaseServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
	IOException {
		doPost(req, resp);
	}
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
		// 解决 post 请求中文乱码问题
		// 一定要在获取请求参数之前调用才有效
		req.setCharacterEncoding("UTF-8");
		String action = req.getParameter("action");
		try {
			// 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象
			Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class,
			HttpServletResponse.class);
			// System.out.println(method);
			// 调用目标业务 方法
			method.invoke(this, req, resp);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);// 把异常抛给 Filter 过滤器
		}
	}
}

友好的错误代码展示

也是在xml文件中配置。

<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
	<!--error-code 是错误类型-->
	<error-code>500</error-code>
	<!--location 标签表示。要跳转去的页面路径-->
	<location>/pages/error/error500.jsp</location>
</error-page>
<!--error-page 标签配置,服务器出错之后,自动跳转的页面-->
<error-page>
	<!--error-code 是错误类型-->
	<error-code>404</error-code>
	<!--location 标签表示。要跳转去的页面路径-->
	<location>/pages/error/error404.jsp</location>
</error-page>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/387905.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RH850从0搭建Autosar开发环境【2X】- Davinci Configurator之XCP模块配置详解(上)

XCP模块配置详解 - 上 一、XCP模块配置项处理1.1 Tx Pdu配置项二、XCP模块其他配置项2.1 参数XcpMainFunctionPeriod2.2 参数XcpOnCanEnabled2.3 容器XcpOnCan总结从本节开始先专注与配置项错误处理以及构建Autosar Rh850的最小系统搭建。 XCP模块在汽车电子各控制器中处于十分…

使用ShardingJDBC实现分库分表

一、测试环境 JDK&#xff1a;1.8SpringBoot&#xff1a;2.7.17MySQL驱动&#xff1a;5.1.49MyBatis&#xff1a;2.3.1shardingJDBC&#xff1a;5.1.0 二、核心依赖 <!-- mysql 驱动 --> <dependency><groupId>mysql</groupId><artifactId>mysq…

Django学习笔记教程全解析:初步学习Django模型,初识API,以及Django的后台管理系统(Django全解析,保姆级教程)

把时间用在思考上是最能节省时间的事情。——[美]卡曾斯 导言 写在前面 本文部分内容引用的是Django官方文档&#xff0c;对官方文档进行了解读和理解&#xff0c;对官方文档的部分注释内容进行了翻译&#xff0c;以方便大家的阅读和理解。 概述 在上一篇文章里&#xff0…

【Python】高级数据类型

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

8.JS中的== 操作符的强制类型转换规则

对于 来说&#xff0c;如果对比双方的类型不一样&#xff0c;就会进行类型转换。假如对比 x 和 y 是否相同&#xff0c;就会进行如下判断流程&#xff1a; 首先会判断两者类型是否相同&#xff0c;类型相同的话就比较两者的大小&#xff1b;类型不相同的话&#xff0c;就会进…

Compose低级别API动画指南

Google官方为Compose提供的动画API与原生View体系的动画API相差甚远&#xff0c;目前总共分为四类&#xff1a;高级别动画API、低级别动画API、自定义动画、手势和动画&#xff08;其他&#xff09;&#xff0c;下图是官方提供的流程指示图&#xff0c;以供根据不同使用场景来选…

PMDG 737

在Simbrief中生成计划后下载两个文件 放到A:\Xbox\Community\pmdg-aircraft-738\Config\Flightplans中

深度学习疆界:探索基本原理与算法,揭秘应用力量,展望未来发展与智能交互的新纪元

目录 什么是深度学习 深度学习的基本原理和算法 深度学习的应用实例 深度学习的挑战和未来发展方向 挑战 未来发展方向 深度学习与机器学习的关系 深度学习与人类的智能交互 什么是深度学习 深度学习是一种基于神经网络的机器学习方法&#xff0c;旨在模仿人类大脑分析…

LabVIEW虚拟测试与分析仪

LabVIEW虚拟测试与分析仪 在现代工程技术领域&#xff0c;虚拟仪器的开发和应用已成为一种趋势。利用LabVIEW软件平台开发的虚拟测试与分析仪器进行展开&#xff0c;实现工程测试和分析中的实际需求。通过结合LabVIEW的强大功能和灵活性&#xff0c;成功实现了一套高效、精确的…

各指针含义区分

一、char *a P109: (1)(变量)指针变量&#xff1a;指针变量&#xff0c;即指针的定义&#xff1a;用来存放指针的变量。指向的是变量&#xff0c;且可以改变其指向的地址。P104 char *a (2)(变量)指针常量&#xff1a;指针常量&#xff0c;指向的是变量首字节的地址&#xff…

算法基础——单调栈,单调队列

目录 1.单调栈 例题&#xff1a;【模板】单调栈 例题:求和 2.单调队列 例题&#xff1a;滑动窗口 1.单调栈 例题&#xff1a;【模板】单调栈 可以想象出一个柱状图&#xff0c;值越大&#xff0c;这个柱子越高 以此题的样例为例&#xff1a; 第一个数为7&#xff0c;想…

【Java程序员面试专栏 分布式中间件】ElasticSearch 核心面试指引

关于ElasticSearch 部分的核心知识进行一网打尽,包括ElasticSearch 的基本概念,基本架构,工作流程,存储机制等,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 基础概念 从数据分类入手,考察全文索引的基本概念 现实世界中数据有哪…

yolov5配置教程

yolov5 yolov5 notepad notepad 直接下一步就可以 Git Git 取消勾选 修改默认编辑器为npp 其他都直接下一步 python3.8.1 python3.8.1 主要勾选添加环境变量 其他下一步即可 Miniconda Miniconda 其他下一步 然后添加系统环境变量 Pycharm Pycharm 把这个界面所…

MPLAB V8.92 printf

Compile error “A heap is required, but has not been specified” Set printf function #if 0 //for UART1 int fputc(int ch, FILE *f) { IFS1bits.U2TXIF 0; // if (runConfig.printOn 1) { // usart_data_transmit(USART0, (uint8_t)ch); U2TXREG ch; // while (RESE…

linux(阿里云)安装pytorch

目录 环境 安装步骤 1 检查python3和pip3是否已经安装 2 安装pytorch 3 安装完毕&#xff0c;检查pytorch版本 环境 阿里云 ubuntu 22.04 UEFI版 64位 安装步骤 1 检查python3和pip3是否已经安装 输入下面两条指令&#xff1a; python3 --version pip --version 检…

Nvm安装(windows版)

1、nvm 是什么 &#xff08;1&#xff09;nvm(Node.js version manager) 是一个命令行应用&#xff0c;可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 &#xff08;2&#xff09;有时候&#xff0c;我们可能同时在进行多个项目开发&#xff0c;而多个项…

书生·浦语大模型第六课作业

面向GPU的环境安装 conda create --name opencompass --clone/root/share/conda_envs/internlm-base source activate opencompass git clone https://github.com/open-compass/opencompass cd opencompass pip install -e . 数据准备 # 解压评测数据集到 data/ 处 cp /shar…

神经网络 | CNN 与 RNN——深度学习主力军

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要将卷积神经网络&#xff08;CNN&#xff09;和循环神经网络&#xff08;RNN&#xff09;这两个深度学习主力军进行对比。我们知道&#xff0c;从应用方面上来看&#xff0c;CNN 用于图像识别较多&#xff0c;而 RNN 用于…

c++阶梯之类与对象(下)

前文&#xff1a; c阶梯之类与对象&#xff08;上&#xff09;-CSDN博客 c阶梯之类与对象&#xff08;中&#xff09;-CSDN博客 c阶梯之类与对象&#xff08;中&#xff09;&#xff1c; 续集 &#xff1e;-CSDN博客 1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时&a…

Go教程-什么是编程?

什么是编程&#xff0c;这是个有趣的话题。 编程是什么 编程&#xff0c;字面意思即编写程序&#xff0c;即通过既定的关键字&#xff0c;来描述你的想法&#xff0c;并让计算机的各个部件按照你的想法来做事。 这里计算机的各个部件通常来说&#xff0c;指的是CPU和IO设备。…