统一处理异常和记录日志

统一处理异常

SpringBoot设计,如果出现错误404或500,自动调用特定路径下的html页面(路径和名字都特定)。/templates/error/404.html、/templates/error/500.html。程序中有错误自动就调用该页面。
但是错误有异步请求错误,也想同时记录日志。则使用统一处理的方式,即全局配置。

@ControllerAdvice 是 Spring MVC 中的一个注解,用于定义全局控制器的通知(advice)。它允许您在整个应用程序范围内定义对控制器的异常处理、绑定属性以及其他全局控制器通知的方法。
具体来说,@ControllerAdvice 通常与 @ExceptionHandler、@InitBinder 和 @ModelAttribute 注解一起使用:

  • @ExceptionHandler: 用于定义在控制器中抛出指定类型异常时的处理方法。
  • @InitBinder: 用于定义在控制器中自定义数据绑定规则的方法。
  • @ModelAttribute: 用于定义在所有请求处理方法之前执行的方法,通常用于在模型中添加公共属性。

通过将 @ControllerAdvice 注解添加到类上,您可以在该类中定义这些通知方法,并在整个应用程序中共享它们,以便统一处理异常、数据绑定和模型属性。这样可以提高代码的重用性和可维护性,并使全局控制器的配置更加简洁和清晰。

	//手动重定向错误页面@RequestMapping(path = "/error", method = RequestMethod.GET)public String getErrorPage() {return "/error/500";}
// 是Controller全局配置类,不用对任何Controller再做配置,可以统一做Controller的全局配置。@ControllerAdvice用来修饰类。
// 异常处理方案@ExceptionHandler、绑定数据方案@ModelAttribute、绑定参数方案@DataBinder. 他们都用来修饰方法。
// 这里只演示,统一处理异常(@ExceptionHandler)
@ControllerAdvice(annotations = Controller.class) // 限定注解@Controller,否则组件扫描所有的bean
public class ExceptionAdvice {private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);@ExceptionHandler({Exception.class})// 处理哪些异常?Exception是所有异常的父类,所有异常都处理// 有异常controller会传过来Exceptionpublic void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {// 记录日志logger.error("服务器发生异常:" + e.getMessage());//异常的概括for (StackTraceElement element : e.getStackTrace()) {//把异常所有栈的信息都记录下来logger.error(element.toString());}// 给浏览器响应// 要看是什么请求,想要服务器返回网页html/异步请求JSON(xml).从请求的消息头获取。String xRequestedWith = request.getHeader("x-requested-with");if ("XMLHttpRequest".equals(xRequestedWith)) {// 异步请求response.setContentType("application/plain;charset=utf-8");PrintWriter writer = response.getWriter();// 输出流writer.write(CommunityUtil.getJSONString(1,"服务器异常!"));// 输出JSON字符串}else{// 请求html,重定向到错误页面response.sendRedirect(request.getContextPath() + "/error");}}
}

统一记录日志

记录日志,不一定有异常。拦截器也是针对控制器的。没有对业务组件、数据访问层统一处理。

想对业务层统一记录日志,而统一记录日志是系统功能,不要和业务功能混在一起实现。否则在想对记录日志的位置进行改变时,将会非常麻烦,因为业务bean有很多个,需要修改的时候得一个个改。

由此引入了AOP的方式,即面向切面编程,切面是一个一个组件。业务Bean是一个一个target。我们要先声明切点的位置,再通知要做什么事。只需要对切面组件编程即可,不需要再进到业务Bean中去改,提升了编程效率。
Aspect切面:

  • 注解@Component @Aspect
  • 声明切点的位置@Pointcut(切点的位置:返回值 包.类.方法.参数) pointcut()
  • 通知具体逻辑,5个注解@Before @After AfterReturning @AfterThrowing @Around
    Target: 是业务Bean
    在这里插入图片描述
    AOP实现有两种:
    AspectJSpring AOP。一般用后者即可。它是运行时织入,通过代理的方式,只在方法处有连接点。Spring AOP(面向切面编程)通常通过代理的方式来实现,主要有以下几个原因:
  • 无侵入性: 通过代理方式实现 AOP 可以避免对现有代码的侵入性。即使目标类没有实现任何接口,也可以通过 Spring AOP实现切面功能。
  • 动态性: 代理方式允许在运行时动态地应用切面。这意味着可以在运行时决定是否应用切面,以及如何应用切面,而无需在编译时硬编码切面逻辑。
  • 单一职责原则: 通过代理方式实现 AOP可以使目标类专注于自身的业务逻辑,而将横切关注点(如日志记录、事务管理等)从目标类中解耦出来,符合单一职责原则。
  • 多个切面组合:代理方式允许将多个切面组合应用于目标类,而无需修改目标类的代码。这种灵活性使得可以根据需求组合不同的切面,实现更加复杂的功能。
  • 易于管理: 通过代理方式实现的切面可以集中管理,例如在配置文件中声明切面和通知的关系,而无需在每个目标类中显式地声明切面逻辑。

统一记录日志示例

@Component
@Aspect
public class ServiceLogAspect {private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")public void pointcut() {}@Before("pointcut()")public void before(JoinPoint joinPoint) {// 参数:连接点// 用户[1.2.3.4],在[xxx],访问了[com.nowcoder.community.service.xxx()].ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String ip = request.getRemoteHost();String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());String target = joinPoint.getSignature().getDeclaringTypeName() + "." +joinPoint.getSignature().getName();// 得到该连接点的类名和方法名logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));}@After("pointcut()")public void after() {System.out.println("after");}@AfterReturning("pointcut()")public void afterRetuning() {System.out.println("afterRetuning");}@AfterThrowing("pointcut()")public void afterThrowing() {System.out.println("afterThrowing");}@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 参数:连接点System.out.println("around before");Object obj = joinPoint.proceed();// 连接点调用目标组件的方法,返回目标组件的返回值System.out.println("around after");return obj;}
}

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

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

相关文章

Windows系统安装WinSCP结合内网穿透实现公网远程SSH本地服务器

List item 文章目录 1. 简介2. 软件下载安装:3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 ​ Winscp是一个支持SSH(Secure SHell)的可视化SCP(Secure Copy)文件传输软件,它的主要功能是在本…

公司电脑如何对文件进行加密?

在现代企业中,文件加密是确保敏感数据安全的关键。使用华企盾DSC数据安全防泄密系统,公司电脑可以轻松地对文件进行加密,以防止未授权的访问和数据泄露。以下是对文件进行加密的步骤和方法: 智能半透明加密:这种模式允…

IntelliJ IDEA(WebStorm、PyCharm、DataGrip等)设置中英文等宽字体,英文为中文的一半(包括标点符号)

1.设置前(idea默认字体为 JetBrains Mono) 2.设置后(楷体)

Vue3 使用ElementUI 显示异常

element提供的样例不能正常显示,需要进行配置 1.npm install element-plus --save 2.main.js // main.ts import { createApp } from vue import ElementPlus from element-plus //全局引入 import element-plus/dist/index.css import App from ./App.vue const …

list的常用接口底层实现与介绍

目录 概念: list的基本结构: list的迭代器⭐❤: 自定义类型的完善: const的迭代器: insert erase: size empty push_back 、push_front 、pop_back、pop_front swap 、operator 析构函数…

【CSS】CSS三大特性、盒子模型

目录 CSS三大特性 1、层叠性 2、继承性 3、优先级 盒子模型 1、网页布局的本质 2、盒子模型(Box Model)组成 3、边框(border) 3.1、边框的使用 3.2、表格的细线边框 3.3、边框会影响盒子实际大小 4、内边距&#xff0…

Unity 九宫格

1. 把图片拖拽进资源文件夹 2.选中图片,然后设置图片 3.设置九宫格 4.使用图片,在界面上创建2个相同的Image,然后使用图片,修改Image Type 为Sliced

前端开发基础(HTML5 + CSS3)【第一篇】:HTML标签之文字排版、图片、链接、音频、视频 涵盖了两个综合案例 做到了基础学得会,实战写的出

点击前往前端开发基础专栏: 文章目录 HTML5 CSS3 开发一、开发环境搭建下载 VS Code1. 2 插件的下载1.3 项目和文件的下载 二、 什么是 HTML2.1 标签的语法2.2 代码演示:2.3 小结 三 、HTML基本骨架3.1 快捷键生成HTML骨架3.2 代码展示3.3 小结 四、标…

第十四讲:C语言字符函数和字符串函数

目录 1. 字符分类函数 2、字符转换函数 3. strlen的使⽤和模拟实现 4. strcpy 的使⽤和模拟实现 5. strcat 的使⽤和模拟实现 6. strcmp 的使⽤和模拟实现 7. strncpy 函数的使⽤ 8. strncat 函数的使⽤ 9. strncmp函数的使⽤ 10. strstr 的使⽤和模拟实现 11. strt…

Redis的持久化

目录 一、RDB(Redis DataBase) 二、AOF(Append Only File) Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中 的数据库状态也会消失。所以 Redis 提供…

从文字到思维:呆马GPT在人工智能领域的创新之旅

引言 生成式预训练变换器(Generative Pre-trained Transformer,简称GPT)领域是人工智能技术中的一大革新。自OpenAI推出第一代GPT以来,该技术经历了多代发展,不断提升模型的规模、复杂度和智能化程度。GPT模型通过在大…

【Linux】vim 编辑器

Linux 系统自带了 gedit 和 vi 编辑器,gedit 是图形化界面的操作,而 vi 由比较难用,所以建议安装 vim 编辑器,vim 是从 vi 发展出来的一个文本编辑器,相当于增强版的 vi ,其代码补完、编译及错误跳转等功能…

从路由器syslog日志监控路由器流量

路由器是关键的网络基础设施组件,需要随时监控,定期监控路由器可以帮助管理员确保路由器通信正常。日常监控还可以清楚地显出通过网络的流量,通过分析路由器流量,安全管理员可及早识别可能发生的网络事件,从而避免停机…

负荆请罪将相和之后的廉颇蔺相如,下场如何?

“将相和”的故事相信许多人都听说过, 这个故事来自于司马迁的《史记》,并被许多版本的语文教科书所收录,而“完璧归赵”“负荆请罪”等成语也都是出自这个故事。但是这个故事并没有讲“将相和”之后的内容,实际上,蔺相…

C语言面试题之合法二叉搜索树

合法二叉搜索树 实例要求 实现一个函数,检查一棵二叉树是否为二叉搜索树; 示例 1: 输入:2/ \1 3 输出: true 示例 2: 输入:5/ \1 4/ \3 6 输出: false 解释: 输入为: [5,1,4,null,null,3,6]。根节点的值为 5 ,但是其右子节点值为 4 …

VS2022使用属性表快速设置OpenCV工程属性

1.创建C控制台应用 2.配置工程 3.打开工程后,为工程添加属性表 打开属性管理器窗口,选择Debug|x64 然后右击选择添加新的项目属性表 并命名为opencv490_debug_x64 点击添加 Debug版本属性表添加成功 使用相同方法添加Release版本属性表 双击debug版本属性表并添加包含目录 添…

90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装)

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…

Github第一Star数的国产免费开源防火墙--雷池社区版初步体验

前言 近期准备搭建一个博客网站,用来存储工作室同学们的学习笔记。服务器准备直接放在公网上,方便大家随时随地的上传和浏览,为了防止网站被人日穿成为肉鸡,一些防御措施还是要部署的。 首先明确自己的需求: 零成本…

【Python】控制台进度条

在Python开发中,有时需要向用户展示一个任务的进度,以提供更好的交互体验。下面我将展示如何使用Python来创建一个简单的控制台进度条。 效果: 代码: import time import sys def print_progress_bar(completed, total, length…

Windows搭建Jellyfin影音服务结合内网穿透实现公网访问本地视频文件

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…