使用@Aspect和@Before注解以及全局异常拦截

记录:390

场景:使用aspectjweaver包的@Aspect和@Before注解拦截自定义注解@VerifyCity。自定义注解@VerifyCity作用在Controller的方法上。实现在执行Controller的方法前,先拦截注解校验必要参数。使用@RestControllerAdvice和@ExceptionHandler注解拦截异常,实现优雅返回异常信息。

版本:JDK 1.8,SpringBoot 2.6.3

AOP:Aspect Oriented Programming,面向切面编程。

AOP:将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。

AOP:取横向抽取机制,取代了传统纵向继承体系的重复性代码,主要应用在事务处理、日志管理、权限控制、异常处理等方面。

1.自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface VerifyCity {
    String value() default "";
}

2.使用@Aspect和@Before实现拦截自定义注解

2.1代码

@Aspect
@Order(0)
@Component
@Slf4j
public class VerifyCityAspect {
  @Before("@annotation(verifyCity)")
  public void beforeVerify(VerifyCity verifyCity) {
    RequestAttributes reqAttributes = RequestContextHolder.currentRequestAttributes();
    HttpServletRequest httpReq = ((ServletRequestAttributes) reqAttributes).getRequest();
    String httpCityName = httpReq.getHeader("cityName");
    String annotationCityName = verifyCity.value();
    log.info("从http请求头中获取的城市名称,cityName=" + httpCityName);
    log.info("从Controller的方法上的@VerifyCity注解获取的城市名称,cityName=" + annotationCityName);
    if (!StringUtils.equals(httpCityName, annotationCityName)) {
      log.info("校验失败,不执行Controller.");
      throw new VerifyException("校验城市编码失败.");
    }
    log.info("校验成功,执行Controller.");
  }
}

2.2解析

@Aspect,标记实现AOP。

@Before("@annotation(verifyCity)"),标记拦截注解@VerifyCity。

StringUtils.equals(httpCityName, annotationCityName),比对从请求头中获取的cityName的值与从注解@VerifyCity中获取的值,相等则验证通过,否则抛出一个异常,结束程序。

throw new VerifyException("校验城市编码失败."),抛出定义异常,结束本次请求,也就是不会执行@VerifyCity标记的Controller的方法了。

3.自定义异常

自定义VerifyException继承RuntimeException。

public class VerifyException extends RuntimeException {
  private String errorCode = "";
  public VerifyException(String message) {
      super(message);
      this.errorCode = "500";
  }
  public String getErrorCode() {
      return errorCode;
  }
}

4.自定义全局拦截器

4.1代码

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
  @ExceptionHandler(value = VerifyException.class)
  public String bizExceptionHandler(HttpServletRequest req, VerifyException e) {
    String errMsg = "异常编码: " + e.getErrorCode() + ";异常信息: " + e.getMessage();
    log.error(errMsg);
    return errMsg;
  }
}

4.2解析

@RestControllerAdvice,标记全局异常。

@ExceptionHandler(value = VerifyException.class),指定拦截的异常类型。

返回值类型String,抛出异常后,会组装成字符串信息返回,而不是一连串报错异常。

5.使用自定义注解

在Controller类使用注解@VerifyCity("Hangzhou")。

@Slf4j
@RestController
@RequestMapping("/hub/example/city")
public class CityController {
  @VerifyCity("Hangzhou")
  @PostMapping("/queryCityByCityCode")
  public Object queryCityByCityCode(String cityCode) {
      log.info("入参cityCode = "+cityCode);
      return "执行成功";
  }
}

6.使用Postman测试

6.1请求地址与入参

地址:http://127.0.0.1:18200/hub-200-base/hub/example/city/queryCityByCityCode

入参:cityCode=310001

请求头:cityName=Hangzhou

返回值:执行成功

6.2优雅拦截异常返回

返回值:异常编码: 500;异常信息: 校验城市编码失败.

6.3不使用全局拦截异常返回

把VerifyCityAspect中抛出异常改为:

throw new RuntimeException("校验城市编码失败.");

不优雅返回值:

{
  "timestamp": "2023-03-23T23:03:4127+08:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/hub-200-base/hub/example/city/queryCityByCityCode"
}

或者

java.lang.RuntimeException: 校验城市编码失败.
  at com.hub.example.aspect.VerifyCityAspect.beforeVerify(VerifyCityAspect.java:37) ~[classes/:na]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
  at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]

7.核心依赖包

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.19</version>
</dependency>

以上,感谢。

2023年3月23日

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

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

相关文章

I2C和SPI总线以及通信

通讯属性 概括 Serial/parallel 串行/并行Synchronous/asynchronous 同步/异步Point-to-point / bus 点对点 总线Half-duplex/full-duplex 半双工/全双工Master-slave/ equal partners 主从/对等single-ending / differential 单端/差分 点对点和总线 点对点通讯 只有两个通…

Springboot Long类型数据太长返回给前端,精度丢失问题 复现、解决

前言 惯例&#xff0c;收到兄弟求救&#xff0c;关于long类型丢失精度的问题&#xff1a; 存在一个初学者不会&#xff0c;就会有第二个初学者不会&#xff0c;所以我出手。 正文 不多说&#xff0c;开搞。 如题&#xff0c; 后端返回的数据 给到 前端&#xff0c; Long类型数…

DevOps系列文章 - K8S构建Jenkins持续集成平台

k8s安装直接跳过&#xff0c;用Kubeadm安装也比较简单安装和配置 NFSNFS简介NFS&#xff08;Network File System&#xff09;&#xff0c;它最大的功能就是可以通过网络&#xff0c;让不同的机器、不同的操作系统可以共享彼此的文件。我们可以利用NFS共享Jenkins运行的配置文件…

一文了解Jackson注解@JsonFormat及失效解决

背景 项目中使用WRITE_DATES_AS_TIMESTAMPS: true转换日期格式为时间戳未生效。如下&#xff1a; spring:jackson:time-zone: Asia/Shanghaiserialization:WRITE_DATES_AS_TIMESTAMPS: true尝试是否关于时间的注解是否会生效&#xff0c;使用JsonForma和JsonFiled均失效。 常…

功能测试转型测试开发年薪27W,又一名功能测试摆脱点点点,进了大厂

咱们直接开门见山&#xff0c;没错我的粉丝向我投来了喜报&#xff0c;从功能测试转型测试开发&#xff0c;进入大厂&#xff0c;摆脱最初级的点点点功能测试&#xff0c;拿到高薪&#xff0c;遗憾的是&#xff0c;这名粉丝因为个人原因没有经过指导就去面试了&#xff0c;否则…

字节跳动测试岗面试记:二面被按地上血虐,所幸Offer已到手...

在互联网做了几年之后&#xff0c;去大厂“镀镀金”是大部分人的首选。大厂不仅待遇高、福利好&#xff0c;更重要的是&#xff0c;它是对你专业能力的背书&#xff0c;大厂工作背景多少会给你的简历增加几分竞争力。 但说实话&#xff0c;想进大厂还真没那么容易。最近面试字…

webpack——使用、分析打包代码

世上本无nodejs js最初是在前端浏览器上运行的语言&#xff0c;js代码一旦脱离了浏览器环境&#xff0c;就无法被运行。直到nodejs的出现&#xff0c;我们在电脑上配置了node环境&#xff0c;就可以让js代码脱离浏览器&#xff0c;在node环境中运行。 浏览器不支持模块化 nodej…

2万字带你精通MySQL索引

文章目录一、MySQL三层逻辑架构1、第一层负责连接管理、授权认证、安全等等。2、第二层负责解析查询3、第三层是存储引擎二、对比InnoDB与MyISAM1、存储结构2、 存储空间3、 可移植性、备份及恢复4、 事务支持5、 AUTO_INCREMENT6、 表锁差异7、 全文索引8、表主键9、表的具体行…

编写软件界面的方式

本文重点解决如下问题&#xff1a;编写软件的界面有哪几种方式&#xff1f;通常情形下&#xff0c;界面对于一个程序来说非常重要。比尔盖茨为操作系统加了一个界面就产生了微软。这样的说法或许有些夸张&#xff0c;但足以证明了界面对于提升软件的友好性、易用性、便捷性的重…

制作简单进销存管理系统(C#)

实验三&#xff1a;制作简单进销存管理系统 任务要求&#xff1a; 在进销存管理系统中&#xff0c;商品的库存信息有很多种类&#xff0c;比如商品型号、商品名称、商品库存量等。在面向对象编程中&#xff0c;这些商品的信息可以存储到属性中&#xff0c;然后当需要使用这些…

libvirt零知识学习5 —— libvirt源码编译安装(3)

接前一篇文章libvirt零知识学习4 —— libvirt源码编译安装&#xff08;2&#xff09; 在上篇文章及上上篇文章中构建libvirt的时候遇到了一个问题“ERROR: Problem encountered: YAJL 2 is required to build QEMU driver”。上篇文章讲到即使安装了相应的YAJL库仍然不能解决问…

ring_log环形日志-6M缓冲区_proc接口

文章目录log_tools.clog.cspin_lockseq_putsseq_readseq_writesingle_openmakefiletest.sh测试&#xff1a;运行./test.sh读取日志插入日志echo cat测试参考&#xff1a;log_tools.c #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #includ…

蓝桥杯每日一真题——[蓝桥杯 2021 省 B] 杨辉三角形(二分+规律)

文章目录[蓝桥杯 2021 省 B] 杨辉三角形题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示思路&#xff1a;全部代码&#xff1a;[蓝桥杯 2021 省 B] 杨辉三角形 题目描述 下面的图形是著名的杨辉三角形: 如果我们按从上到下、从左到右的顺序把所有数排成一列&…

已解决AttributeError:module tensorflow no attribute app异常的正确解决方法,亲测有效!!!

已解决AttributeError&#xff1a;module tensorflow no attribute app异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 文章目录报错问题解决方法福利报错问题 粉丝群里面的一个小伙伴敲代码时发生了报错&#xff08;当时他心里瞬间凉了一大截&…

使用STM32F103ZE开发贪吃蛇游戏

目录 前言 一、设置FreeROTS用户任务 &#xff08;1&#xff09;事件event任务 &#xff08;2&#xff09;按键输入方向控制任务 &#xff08;3&#xff09;果实食物任务 &#xff08;4&#xff09;显示任务函数 &#xff08;3&#xff09;开始任务 二、主函数 三、ADC采样…

算法基础-回溯算法

回溯算法大致分为以下几类&#xff1a; 组合&#xff1a;组合、组合总和、电话号码的字母组合 分割&#xff1a;分割回文串、复原IP地址 子集&#xff1a;子集 排列&#xff1a;全排列 棋盘问题&#xff1a;N皇后、解数独 其他&#xff1a;递增子序列、重新安排行程 一、什么是…

什么是Nginx

一.什么是nginxNginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;是一款由俄罗斯的程序设计师Igor Sysoev使用c语言开发的轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;官方测试nginx能够支支撑5万…

css总结9(过渡和2D变换)

目录 过渡 2D变换 3D变换 过渡 属性结构图 过渡补充 ### 过渡多个元素样式属性 transition:style1 duration , style2 duration,...; ### 过渡所有属性 transition: all duration; 简单示例 ### 移入时改变长度且加入过渡效果 div { width:100px; height:100px; …

算法训练营第五十九天|LeetCode647、516

题目连接&#xff1a;647. 回文子串 - 力扣&#xff08;LeetCode&#xff09;个人思路&#xff1a;dp数组的含义是&#xff1a;dp[i][j]&#xff1a;s字符串下标i到下标j的字串是否是一个回文串这里我出现了错误为什么出错呢&#xff1f;代码如下&#xff1a;class Solution {p…

JavaSE进阶之(十六)枚举

十六、枚举16.1 背景16.2 枚举类型16.3 EnumSet 和 EnumMap01、EnumSet02、EnumMap16.1 背景 在 Java 语言中还没有引入枚举类型之前&#xff0c;表示枚举类型的常用模式是声明一组 int 类型的常量&#xff0c;常常用的就是&#xff1a; public static final int SPRING 1; …
最新文章