java框架 2 springboot 过滤器 拦截器 异常处理 事务管理 AOP

Filter 过滤器

在这里插入图片描述
对所有请求都可以过滤。
在这里插入图片描述
实现Filter接口,重写几个方法,加上@WebFilter注解,表示拦截哪些路由,如上是所有请求都会拦截。
然后还需要在入口处加上@SvlterComponentScan注解,因为Filter是javaweb三大组件之一,并不是springboot的内容。
在这里插入图片描述
chain.doFilter是放行该请求的意思,如果没有将会卡在当前过滤器上。

过滤器链

一个服务可以配置多个过滤器,多个过滤器形成过滤器链。有点像koa的洋葱模型。

过滤器1执行 -> 过滤器2执行 -> 执行主要逻辑 -> 过滤器2放行后的逻辑执行 -> 过滤器1放行后的逻辑执行

那么怎么区分那个过滤器先执行呢?通过过滤器首字母排序来决定。

Interceptor拦截器

在这里插入图片描述

拦截器是Spring框架提供的,跟filter不一样。
使用:
在这里插入图片描述
实现HandlerInterceptor接口,重写方法,其中preHanldel是在controller执行前执行,返回值作为放行的条件。
postHandle是在controller执行后执行。
实现拦截器之后,还需要配置才能生效。
在这里插入图片描述
实现WebMvcConfigurer接口,然后使用@Configuration,这样springboot启动的时候会自动扫描该注解,生效该配置。
如上就是将拦截器注册,并指定其拦截的接口。

拦截器-拦截路径

在这里插入图片描述
可以通过addPathPatterns指定哪些路径需要拦截,通过excludePathPatterns指定哪些路径不需要拦截。

执行时机

上面说过,拦截器是spring框架提供的,而过滤器是tomcat框架提供的,如图。
在这里插入图片描述
如果都存在的话,会先执行过滤器,再执行拦截器的逻辑。
过滤器会拦截所有的请求资源,而拦截器只会拦截Spring环境中的资源。

案例 实现jwt登陆验证

安装对应依赖

	<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>

实现jwtUtils类

package com.example.demo.util;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;
import java.util.Map;public class JwtUtils {private static String singKey = "test1234"; // 密钥private static long expire = 432000L; //过期时间public static String generatorToken(Map<String, Object> data) {String jwt = Jwts.builder().addClaims(data).signWith(SignatureAlgorithm.HS256, JwtUtils.singKey).setExpiration(new Date(System.currentTimeMillis() + JwtUtils.expire)).compact();return jwt;}public static Claims parseToken(String token) {Claims calims = Jwts.parser().setSigningKey(singKey).parseClaimsJws(token).getBody();return calims;}}

使用jwt生成token

@Slf4j
@RestController
public class LoginController {@PostMapping("/login")public Result login(@RequestBody LoginUser body){Map<String, Object> data = new HashMap<>();log.info("{},{}", body.getName(),body.getPassword());data.put("name", body.getName());data.put("password", body.getPassword());String token = JwtUtils.generatorToken(data);return Result.success(token);};
}

使用对应的拦截器进行校验

@Component("loginInterceptor")
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {System.out.println("preHandle....." + req.getRequestURL());String url = req.getRequestURL().toString();if(url.contains("login")){// 登陆接口不需要校验return true;}String token = req.getHeader("token");try {if (token != null) {Claims data = JwtUtils.parseToken(token);req.setAttribute("user", data);return true;} else {throw new Exception("token不存在或者过期");}} catch (Exception e) {Result error = Result.error("token is not exists or expire");res.addHeader("Content-Type", "application/json");res.getWriter().write(JSONObject.toJSONString(error));return false;}}
}
@Configuration
public class SpringMvcConfigure implements WebMvcConfigurer {@Resource(name="loginInterceptor")LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(loginInterceptor).addPathPatterns("/**"); //该拦截器拦截所有请求}
}

登陆接口不需要验证,让该拦截器拦截对应请求,拿到token,进行解析,解析到用户数据就塞入req中,后续controller就可以拿到该用户信息。

异常处理

  • 程序开发过程中不可避免会碰到异常,有时候返回的信息并不是后端统一的信息。

在这里插入图片描述
像nest可以配置全局异常过滤器,会俘获所有的异常然后统一信息返回。

方案

java也可以定义全局异常处理器。
在这里插入图片描述

通过注解@RestControllerAdvice指定这是一个controller异常处理器,@RestControllerAdvicd中也包含@ResponseBody,表示所有的方法返回的值会被转为json传给前端(实际上所有的请求传输都是字符串,只不过设置了contentType为json,浏览器会自动识别contentType处理。)。通过@ExceptionHandler(Exception.class)指定拦截什么类型的异常,Exception.class就是指拦截所有的异常。

import com.example.demo.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public Result ex(Exception ex){ex.printStackTrace();return Result.error("服务器报错: " + ex.getMessage());}
}

事务管理

在这里插入图片描述

在这里插入图片描述
springboot提供了@Transactional注解来开启事务。

回滚异常


@Transactional注解,可以传入值,可以控制出现什么异常的情况下,回滚事务。默认只有运行时异常才会处理。

事务传播行为

事务a方法调用事务b方法的时候
在这里插入图片描述
比如在a中调用b的方法,当a失败后,事务回滚,会导致b方法执行的逻辑也会回滚,事务传播行为默认是有则加入,也就是b方法会加入当前a方法的事务中。

将其改为REQUIRES_NEW,在a中调用b的时候,会先挂起a的事务,然后起一个b的事务,当a失败后,a执行的逻辑会回滚,但是b方法执行的逻辑如果没报错,会保留。

在这里插入图片描述

案例 删除一个部门,并将该部门下所有员工删除,不管删除失败成功都需要记录日志

如下,启用Propagation.REQUIRES_NEW,在调用创建日志方法的时候并不会受原本事务的影响

  @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)public Result deleteDepts(Integer id) {try {this.dept.deleteDept(id);this.emp.deleteEmpByJobId(id); //删除员工表下该部门的员工return Result.success(0);} catch (Exception e) {return Result.error(e.getMessage());} finally {// 记录日志 也是一个事务方法,用REQUIRES_NEW则不会被上述逻辑影响,会正常记录日志logger.create(new Date(), "删除")}}

AOP

在这里插入图片描述
实现
在这里插入图片描述
编写AOP类,交给IOC容器管理。
通过joinPoint可以拿到原始方法。

AOP核心概念

在这里插入图片描述

  • 连接点,joinPoint,可以被AOP控制的方法,比如上图的list,delete,save等方法都属于连接点。
  • 通知,Advice,重复逻辑,比如上图的recordTime方法,共性逻辑(所有连接点都会执行)
  • 切入点:pointCut,顾名思义就是在哪里切入这个类,匹配连接点的条件。
  • 切面:描述通知与切入点的对应关系,如上图的@Around(切入点表达式)+recordTIme(通知)方法就是切面。
  • 目标对象:Target,AO类所应用的对象。
AOP的执行流程

AOP类是如何作用于目标对象的,
在这里插入图片描述
上述说过,AOP是通过动态代理实现的,如上,DeptServiceImpl类,是AOP的目标对象,他会根据通知,生成一个代理类,DeptServiceProxy,然后重新list方法,执行AOP类的逻辑,最后如上,通过@Autowired注入的deptService就不是DeptServiceImpl,而是DeptSerivceProxy这个代理对象,所以执行list方法的时候,就会执行代理对象list,从而执行通知的逻辑

通俗的说,AOP类会在不影响目标对象代码的基础上,基于目标对象,新增一些其他的逻辑,通过代理的形式生成一个新的类,交给IOC容器.

案例 记录每个controller的耗费时间

可以用拦截器做到,也可以用过滤器做到,也可以用AOP做到。

@Component
@Aspect
@Slf4j
public class TimeAspect {@Around("execution(* com.example.demo.controller.*.*(..))")public Object recordTime(ProceedingJoinPoint joinPoint) throws  Throwable{long begin = System.currentTimeMillis();Object object = joinPoint.proceed(); //调用原方法long end = System.currentTimeMillis();log.info(joinPoint.getSignature() + "执行耗时: {}ms", end- begin);return object; //返回}
}

在这里插入图片描述

AOP高阶
通知类型

上述我们使用的@Around就是通知类型。他的功能最强大,可以编写目标方法执行前的逻辑,也可以编写目标方法执行后的逻辑(可以拿到目标方法)

在这里插入图片描述
@Pointcut注解可以抽离公共的切入点表达式,服用切入点表达式
在这里插入图片描述

通知的执行顺序

当有多个通知都匹配到同一个切入点时,目标方法执行,多个通知方法都会执行。
跟过滤器一样,其实是根据AOP的类名字母排序有关,且@before和@after的执行顺序就跟洋葱模型一样,也是234 -> 432这样执行。
在这里插入图片描述

除此之外,还可以通过@Order注解来标记执行顺序。

切入点表达式

在这里插入图片描述
在这里插入图片描述

通配符号 * 和 …

在这里插入图片描述

 @Around("execution(* com.*.demo.controller.*.update*(*))")

* com表示 匹配任何返回值
com.*.demo表示二级包是任意的
controller.*表示controller下的类或者接口是任意的
update*表示以update开头的类或者接口
(*)表示匹配一个参数

上述表示 任何的返回值,com下任意的二级包里含有的demo三级包下的controller目录下的任意的以类或者接口下以update开头,且只能有一个参数的方法

如果换成…

 @Around("execution(* com..controller.*.update*(..))")

com…可以匹配任意层级的包
update*(…)表示匹配update开头的方法,且可以有任意参数。

上述表示 任何的返回值,com下任意的二级包里含有controller的目录,下的任意的以类或者接口下以update开头,且只能有一个参数的方法

多个切入点表达式可以用 || & 等组合。

@annotation

在这里插入图片描述
匹配标识有特定注解的方法
定义一个注解用来标识

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Mylog {}

将execution切换成@annotation

public class TimeAspect {//@Around("execution(* com.example.demo.controller.*.*(..))")@Around("@annotation(com.example.demo.aop.Mylog)")public Object recordTime(ProceedingJoinPoint joinPoint) throws  Throwable{long begin = System.currentTimeMillis();Object object = joinPoint.proceed(); //调用原方法long end = System.currentTimeMillis();log.info(joinPoint.getSignature() + "执行耗时: {}ms", end- begin);return object; //返回}
}
连接点

对于@Around,只能通过ProceddingJoinPoint获取连接点信息,如下

在这里插入图片描述
对于其他四种通知
在这里插入图片描述
只能通过JoinPoint获取连接点信息。

@Aspect
@Component
@Slf4j
public class TimeAspect {@Around("execution(* com.example.demo.controller.*.*(..))")public Object recordTime(ProceedingJoinPoint joinPoint) throws  Throwable{long begin = System.currentTimeMillis();String className = joinPoint.getTarget().getClass().getName();Signature signature = joinPoint.getSignature();String methodName = signature.getName();Object[] args = joinPoint.getArgs();log.info("打印结果==={},{},{},{}", className, signature, methodName, Arrays.toString(args));Object object = joinPoint.proceed(); //调用原方法long end = System.currentTimeMillis();log.info(joinPoint.getSignature() + "执行耗时: {}ms", end- begin);return object; //返回}
}
案例 对增删改操作进行日志写入操作

使用AOP完成该功能。
定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperatorLog {
}

在增删改方法上加上该注解
编写AOP代码

@Component
@Aspect
@Slf4j
public class OperatorLog {// 通过注解获取request对象@Autowiredprivate HttpServletRequest request;@Around("@annotation(com.example.demo.aop.OperatorLog)")public Object createLog(ProceedingJoinPoint joinPoint) throws Throwable {long begin = System.currentTimeMillis();Claims user = (Claims) request.getAttribute("user");String className = joinPoint.getTarget().getClass().getName();Signature signature = joinPoint.getSignature();String methodName = signature.getName();Object[] args = joinPoint.getArgs();Object object = joinPoint.proceed(); //调用原方法long time = begin -  System.currentTimeMillis();Log newLog = new Log((String) user.get("name"),time, methodName, Arrays.toString(args),className);log.info("插入一条日志: {}",newLog);Log.insertLogs(newLog);return object; //返回}
}

通过注解获取request对象,在拦截器的时候将user注入到req里面去,所以这里可以获取得到。然后插入一条日志。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于深度学习的心律异常分类系统设计——算法设计

基于深度学习的心律异常分类系统——算法设计 第一章 研究背景算法流程本文研究内容 第二章 心电信号分类理论基础心电信号产生机理MIT-BIH 心律失常数据库 第三章 心电信号预处理心电信号噪声来源与特点基线漂移工频干扰肌电干扰 心电信号读取与加噪基于小波阈值去噪技术的应用…

PP-Matting——支持多场景精细化高精度人像抠图(C++模型推理)

简介 Matting和分割是图像处理中两个重要的任务&#xff0c;它们在抠图和图像分析中起着不同的作用。 分割方法将图像分成不同的区域&#xff0c;并为每个像素分配一个分类标签&#xff0c;因此其输出是一个像素级别的分类标签图&#xff0c;通常是整型数据。这种方法适用于将…

有ai写文案的工具吗?分享5款好用的工具!

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已渗透到我们生活的方方面面&#xff0c;包括内容创作领域。AI写文案的软件以其高效、便捷的特点&#xff0c;正逐渐受到广大内容创作者、营销人员、甚至普通用户的青睐。本文将为您盘点几款热门的AI写文案软件&…

matlab 最小二乘拟合圆柱

目录 一、算法原理1、算法简介2、参考文献二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、算法简介 圆柱拟合步骤主要包括两步: 一是确定柱面模型参数初始值; 二是…

记一次由于buff/cache导致服务器内存爆满的问题

目录 前言 复现 登录服务器查看占用内存进程排行 先了解一下什么是buff/cache&#xff1f; 尝试释放buffer/cache /proc/sys/vm/drop_caches dirty_ratio dirty_background_ratio dirty_writeback_centisecs dirty_expire_centisecs drop_caches page-cluster swap…

关于在CentOS中卸载MySQL

想要卸载MySQL当然要知道自己的MySQL是用那种方法来安装的了&#xff0c;一般来说MySQL的安装方法在市面上有三种 编译安装、YUM安装、RPM安装&#xff0c;下面会介绍到后两种安装的卸载方法 首先查看是否安装MySQL&#xff0c;一般可以看到版本信息就证明安装了 mysql -V 卸载…

Linux虚拟主机如何快速卸载一键安装的网站程序

接到一位用户发送的请求帮助&#xff0c;想要卸载通过Softaculous一键安装的网站程序&#xff0c;但是没有找到地方&#xff0c;根据与该用户的沟通得知是一个小白用户&#xff0c;想要自己搭建一个博客类的网站&#xff0c;了解到Hostease 有适合新用户并且带管理面板的产品Li…

nacos 更新报错“发布失败。请检查参数是否正确”

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容起因解决方案结果 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华…

从底层结构开始学习FPGA(0)----FPGA的硬件架构层次(BEL Site Tile FSR SLR Device)

系列目录与传送门 《从底层结构开始学习FPGA》目录与传送门 Xilinx的FPGA&#xff0c;从硬件架构的角度可以划分为6个层次&#xff0c;从底层到顶层依次是&#xff1a; BEL&#xff08;最底层单元&#xff09;SiteTileFSRSLRDevice&#xff08;FPGA芯片&#xff09; 接下来我…

【研究僧总结】回顾第1095个创作日

目录 前言一. 机缘二. 日常三. 展望 前言 感觉刚过1024不久&#xff0c;现在又来个1095创作日 一. 机缘 研究僧一直在找平台做笔记&#xff0c;方便之后的回顾总结&#xff0c;也让各位网友见证你我的成长&#xff0c;相互学习 止不住的写文止不住的成长&#xff0c;大家共同…

Halcon 路标牌识别

文章目录 gray_closing_shape 使用选定的掩码执行灰度值关闭create_planar_uncalib_deformable_model 为未校准的透视匹配创建一个可变形的模型get_deformable_model_params 返回可变形模型的参数find_planar_uncalib_deformable_model 在图像中寻找平面投影不变变形模型的最佳…

面试常问:为什么 Vite 速度比 Webpack 快?

前言 最近作者在学习 webpack 相关的知识&#xff0c;之前一直对这个问题不是特别了解&#xff0c;甚至讲不出个123....&#xff0c;这个问题在面试中也是常见的&#xff0c;作者在学习的过程当中总结了以下几点&#xff0c;在这里分享给大家看一下&#xff0c;当然最重要的是…

asp.net在线租车平台

说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net架构和sql server数据库 功能模块&#xff1a; asp.net在线租车平台 用户功能有首页 行业新闻用户注册车辆查询租车介绍访问后台 后台管理员可以进行用户管理 管…

Python 解析CSV文件 使用Matplotlib绘图

数据存储在CSV文件中&#xff0c;使用Matplotlib实现数据可视化。 CSV文件&#xff1a;comma-separated values&#xff0c;是在文件中存储一系列以‘&#xff0c;’分隔的值。 例如&#xff1a;"0.0","2016-01-03","1","3","20…

Linux:网络的初步认知

文章目录 网络的认知如何理解协议网络分层OSI模型TCP/IP五层(或四层)模型网络传输的基本流程协议的参与局域网通信原理 本篇将会引入到网络的话题 网络的认知 第一个问题是&#xff0c;网卡是文件吗&#xff1f;答案是显然的&#xff0c;在Linux下一切皆文件&#xff0c;基于…

【Linux】进程控制 -- 详解

一、进程创建 目前学习到的进程创建的两种方式&#xff1a; 命令行启动命令&#xff08;程序、指令等&#xff09; 。通过程序自身&#xff0c;调用 fork 函数创建出子进程。 1、fork 函数初识 在 Linux 中的系统接口 fork 函数是非常重要的函数&#xff0c;它从已存在进程中…

【Linux】深入了解Linux磁盘配额:限制用户磁盘空间的利器

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 前言 在多用户环境下管理磁盘空间是服务器管理中的一项重要任务。Linux提供了强大的磁盘配额功能&#xff0c;可以帮助管理员限制用户或组对文件系统…

一分钟了解自动化测试【建议收藏】

引子 写在最前面&#xff1a;目前自动化测试并不属于新鲜的事物&#xff0c;或者说自动化测试的各种方法论已经层出不穷&#xff0c;但是&#xff0c;能够明白自动化测试并很好落地实施的团队还不是非常多&#xff0c;我们接来下用通俗的方式来介绍自动化测试…… 本文共有2410…

Zookeeper的ZAB协议原理详解

Zookeeper的ZAB协议原理详解 如何保证数据一致性。 Paxos&#xff0c; 吸收了主从。 zk 数据模型Watch机制 zab zookeeper原子广播协议。 ZAB概念 ZooKeeper是通过Zab协议来保证分布式事务的最终一致性。 Zab(ZooKeeper Atomic Broadcast,.ZooKeeper原子广播协议)支持…

企业员工上班摸鱼行为老板怎么管?

在数字化时代&#xff0c;员工摸鱼现象成为企业普遍面临的挑战。摸鱼不仅会降低工作效率&#xff0c;影响企业的正常运营&#xff0c;还可能引发数据泄露等安全问题。因此&#xff0c;企业需要采取有效的措施来防止员工上班摸鱼。 来百度APP畅享高清图片 一、制定明确的规章制…