SpringBoot统一功能处理,拦截器,统一数据格式,捕捉异常

news2024/11/15 11:38:39

 

目录

拦截器:是Spring框架提供的核心功能之一,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码:

自定义拦截器

统一数据格式,要包含状态码,错误信息​编辑

出现针对String类型的错误​​​​​​​

为什么要统一

统一功能来实现捕捉到异常。​编辑

@ControllerAdvice源码分析


数据结构面试:HashMap,ConcurrentHashMap,ThreadLocal要看(建议看源码)

网络:TCP,UDP,HTTP

并发编程:线程创建方式,线程的状态,锁,synchronized,volatile

数据库 基本操作,关键字,

JVM-内存结构,GC

Linux

引入拦截器的原因。

拦截器:是Spring框架提供的核心功能之一,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码:

(指定在哪些方法前后执行)

JDK17把之前Java的包都换为Jakarta。

指定方法:——指我们登录验证的某些方法(比如图书的增删改查),怎样可以不用动太多代码,实现这个功能

预先设定的代码:对用户是否登录进行验证

拦截器的实现分为两步:(作用维度以url为维度)

1.定义一个拦截器

2.把拦截器注册到项目中

自定义拦截器:实现HandlerInterceptor接口,并重写所有方法

拦截器的定义

自定义拦截器

/* 一级路径    能匹配/user,/book,/login,不能匹配/user/login

/** 任意级路径 能匹配 /user,/user/login,/book

/book/*      /book下的一级路径 能匹配/book/addBook,不能匹配/book/addBook

/book/**    /book下的任意级路径     能匹配/book,/book/addBook,/book/addBook/2...。

正常工作方式

用户调用->(拦截器)->控制器层(Controller)->调用服务层(Service)->数据持久层(Mapper)->数据库

1.添加拦截器后, 执⾏Controller的⽅法之前, 请求会先被拦截器拦截住. 执⾏ preHandle() ⽅法, 

这个⽅法需要返回⼀个布尔类型的值. 如果返回true, 就表⽰放⾏本次操作, 继续访问controller中的 

⽅法. 如果返回false,则不会放⾏(controller中的⽅法也不会执⾏).

2. controller当中的⽅法执⾏完毕后,再回过来执⾏ postHandle() 这个⽅法以及

afterCompletion() ⽅法,执⾏完毕之后,最终给浏览器响应数据

DispatcherServlet(Dispatcher调度器,servlet生命周期)​​​​​​​​​​​​​​

源码环节

适配器模式和门面模式区别

1.适配器模式:是适配两者之间的差异(为了补救设计上的缺陷,应用这种模式也是无心之举),门面模式是统合了底层系统(我认为一个像是七巧板把两个不同的连接起来,门面模式就像是给他装了一个套,它里面不变,只是说可以调用他们两个)我们通过外面的套来调用里面。

统一数据格式,要包含状态码,错误信息


supports⽅法: 判断是否要执⾏beforeBodyWrite⽅法. true为执⾏, false不执⾏. 通过该⽅法可以 选择哪些类或哪些⽅法的response要进⾏处理, 其他的不进⾏处理.

beforeBodyWrite⽅法: 对response⽅法进⾏具体操作处理

出现针对String类型的错误​​​​​​​

 快速⼊⻔ 统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现
@ControllerAdvice 表⽰控制器通知类 添加类 ResponseAdvice , 实现 ResponseBodyAdvice 接⼝, 并在类上添加
@ControllerAdvice 注解
import com.example.demo.model.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import
org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
 }
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, 
MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest 
request, ServerHttpResponse response) {
return Result.success(body);
 }
} 

解决方法:


public class TestController {
@RequestMapping("/t1")
public String t1(){
return "t1";
 }
@RequestMapping("/t2")
public boolean t2(){
return true;
 }
@RequestMapping("/t3")
public Integer t3(){
return 200;
 }
} 
解决⽅案:
import com.example.demo.model.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import
org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@Slf4j
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
private static ObjectMapper mapper = new ObjectMapper();
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
 }
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, 
MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest 
request, ServerHttpResponse response) {
//如果返回结果为String类型, 使⽤SpringBoot内置提供的Jackson来实现信息的序列化
if (body instanceof String){
return mapper.writeValueAsString(Result.success(body));
 }
return Result.success(body);
 }
}

为什么会有这样的错误呢?

SpringMVC默认会注册⼀些⾃带的 HttpMessageConverter (从先后顺序排列分别为

ByteArrayHttpMessageConverter ,

StringHttpMessageConverter , SourceHttpMessageConverter ,

SourceHttpMessageConverter , AllEncompassingFormHttpMessageConverter )

AllEncompassingFormHttpMessageConverter 会根据项⽬依赖情况 添加对应的

HttpMessageConverter

在依赖中引⼊jackson包后,容器会把 MappingJackson2HttpMessageConverter ⾃动注册到

messageConverters 链的末尾.

Spring会根据返回的数据类型, 从 messageConverters 链选择合适的

HttpMessageConverter . 

当返回的数据是⾮字符串时, 使⽤的 MappingJackson2HttpMessageConverter 写⼊返回对象. 

当返回的数据是字符串时, StringHttpMessageConverter 会先被遍历到,这时会认为

StringHttpMessageConverter 可以使⽤

在 ((HttpMessageConverter) converter).write(body, selectedMediaType, 

outputMessage) 的处理中, 调⽤⽗类的write⽅法 

由于 StringHttpMessageConverter 重写了addDefaultHeaders⽅法, 所以会执⾏⼦类的⽅法

然⽽⼦类 StringHttpMessageConverter 的addDefaultHeaders⽅法定义接收参数为String, 此 

时t为Result类型, 所以出现类型不匹配"Result cannot be cast to java.lang.String"的异常

​​​​​​​最终

为什么要统一

1. ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据

2. 降低前端程序员和后端程序员的沟通成本, 按照某个格式实现就可以了, 因为所有接⼝都是这样返回 

的.

3. 有利于项⽬统⼀数据的维护和修改.

4. 有利于后端技术部⻔的统⼀规范的标准制定, 不会出现稀奇古怪的返回内容.

统一功能来实现捕捉到异常。

Spring的代码在书写统一的过程中,不按照顺序。

捕捉异常的时候,看他报什么异常,最贴近哪个,那么就是哪个

不加ResponseBody -她就会把下面那个异常当成一条数据

package com.example.demo.config;

import com.example.demo.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@Slf4j
@ResponseBody
@ControllerAdvice
public class ErrorHandler {
    @ExceptionHandler
    public Result exception(Exception e){
        log.error("发生异常e{}",e);
        return Result.fail("内部错误");
    }
    @ExceptionHandler
    public Result exception(NullPointerException e){
        log.info("发生异常");
        return Result.fail("NullPointerException异常,请联系管理员");
    }
    @ExceptionHandler
    public Result exception(ArithmeticException e){
        log.info("发生异常");
        return Result.fail("ArithmeticException 异常,请联系管理员");
    }



}

Spring容器最开始启动时,会进行初始化的工作,其中会对异常进行处理,当异常项有多个匹配的时候,Spring会对其顺序依次排,找出最符合的报异常。

​​​​​​​

@ControllerAdvice源码分析

述源码可以看出 @ControllerAdvice 派⽣于 @Component 组件, 这也就是为什么没有五 

⼤注解, ControllerAdvice 就⽣效的原因

当Controller抛出异常时, DispatcherServlet 通过

ExceptionHandlerExceptionResolver 来解析异常,⽽

ExceptionHandlerExceptionResolver ⼜通过 ExceptionHandlerMethodResolver 来解析异常, ExceptionHandlerMethodResolver 最终解析异常找到适⽤的@ExceptionHandler标注

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL查询缓存

MySQL查询缓存 MySQL在查询的时候首先会查询缓存,如果缓存命中的话就直接返回结果,不需要解析sql语句,也不会生成执行计划,更不会执行;如果没有命中缓存,则再进行SQL解析以及进行查询,并将结果返…

CodeFuse成功支持通义千问算法大赛,评测方案已开源

前段时间, 首届通义千问AI挑战赛成功举办,CodeFuse 为大赛提供技术支持,模型微调框架 MFTCoder 和 CodeFuseEval 评测框架为大赛保驾护航,助力大赛圆满完成。我们基于leetcode 阿里和蚂蚁最新面试题库建设了“模型赛马”在线打榜的…

NC、NC65、NCC富客户端附件在线预览插件

NC附件目前只支持下载,不支持在线查看 通过二开实现NC的附件可以在线预览 支持的格式包含:doc, docx, xls, xlsx, ppt, pptx, pdf和txt等。

金和OA jc6 UploadFileBlock 任意文件上传漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

使用JDBC连接mysql

JDBC:Java DataBase Connectivity,Java数据库连接。 使用Java语言操作关系型数据库的一套API。 原理:官方(sun公司)定义出一套操作所有关系型数据库的规则,即接口;所有的数据库厂商去实现这套接口,提供数据…

Kubernetes k8s

Kubernetes k8s 一个开源的容器编排引擎,用来对容器化应用进行自动化部署、 扩缩和管理。 从架构设计层面,k8s能很好的解决可用性,伸缩性;从部署运维层面,服务部署,服务监控,应用扩容和故障处…

大数据信用报告查询费用一般要多少钱?

一些不少朋友在申贷的时候被拒贷之后,得到的原因就是因为大数据不良被拒,这时候很多人都反过来查询自己的大数据信用报告,而查询的价格也是不少朋友都比较关注的,那大数据信用报告查询费用一般要多少钱呢?下面本文就为你介绍一下…

C# 读取文件中的配置信息

文章目录 定义使用文件格式代码 C#读取文件并处理&#xff1b;C# 读取文件中的配置信息。 在有的程序中&#xff0c;需要从本地文件中读取配置信息&#xff0c;以进行初始化。 定义 定义一个静态函数来获取文件信息。StreamReader 类。 /// <summary> /// 读取参数文件…

获取真实 IP 地址(一):判断是否使用 CDN(附链接)

一、介绍 CDN&#xff0c;全称为内容分发网络&#xff08;Content Delivery Network&#xff09;&#xff0c;是一种网络架构&#xff0c;旨在提高用户对于网络上内容的访问速度和性能。CDN通过在全球各地部署分布式服务器节点来存储和分发静态和动态内容&#xff0c;从而减少…

MySQL全表扫描:性能杀手的隐患与优化策略

MySQL全表扫描&#xff1a;性能杀手的隐患与优化策略 MySQL数据库作为常用的关系型数据库管理系统之一&#xff0c;全表扫描问题一直困扰着开发者。本文将深入剖析MySQL全表扫描的原理、其对性能的严重影响&#xff0c;同时提供一系列优化策略&#xff0c;助您高效应对MySQL性能…

聊聊比特币----比特币地址

⽐特币地址是⼀个标识符&#xff08;帐号&#xff09;&#xff0c;包含27-34个字母数字拉丁字符&#xff08;0&#xff0c;O&#xff0c;I除外&#xff09;。地址可以以QR码形式表⽰&#xff0c;是匿名的&#xff0c;不包含关于所有者的信息。 地址⽰例&#xff1a;14qViLJfdG…

Linux|Grep 命令的 12 个实用示例

您是否曾经遇到过在文件中查找特定字符串或模式的任务&#xff0c;但不知道从哪里开始查找&#xff1f;那么&#xff0c;grep 命令可以拯救你&#xff01; grep 是一个功能强大的文件模式搜索器&#xff0c;每个 Linux 发行版都配备了它。如果出于某种原因&#xff0c;它没有安…

华为机考入门python3--(8)牛客8-合并表记录

分类&#xff1a;字典排序 知识点&#xff1a; 将输入转成int的列表 my_list list(map(int, input().strip().split( ))) 将列表转为元组 tuple(my_list) 访问元素为元组的列表 for first, second, third in my_list: 对字典进行排序 sorted(my_dict.items())…

如何计算两个指定日期相差几年几月几日

一、题目要求 假定给出两个日期&#xff0c;让你计算两个日期之间相差多少年&#xff0c;多少月&#xff0c;多少天&#xff0c;应该如何操作呢&#xff1f; 本文提供网页、ChatGPT法、VBA法和Python法等四种不同的解法。 二、解决办法 1. 网页计算法 这种方法是利用网站给…

【Vue】指令之内容绑定,事件绑定

Vue指令[1] 内容绑定&#xff0c;事件绑定v-test指令v-html指令v-on基础 内容绑定&#xff0c;事件绑定 v-test指令 作用&#xff1a;设置标签的文本值&#xff08;textContent&#xff09; 默认写法会替换全部内容&#xff0c;使用差值表达式可以替换指定内容内部支持写表达…

springboot整合Sa-Token实现登录认证和权限校验(万字长文)

目前在国内的后端开发中&#xff0c;常用的安全框架有spring security、shiro。现在&#xff0c;介绍一款由国人开发的安全框架Sa-Token。这个框架完全由国人开发&#xff0c;所提供的Api文档和一些设置都是比较符合国人的开发习惯的&#xff0c;本次就来介绍一下如何在spring …

海康威视有插件、无插件播放;webrtc直播;西瓜视频播放器;mpegts.js直播;flvjs直播

Notes 视频播放的几种方式 一、Video mp4链接直接播放 二、海康威视3.3插件版直播、云台控制&#xff0c;资源下载地址 index.html引入hk文件中的js文件双击HCWebSDKPlugin.exe安装插件前端参照文件夹hkCamera中的示例代码 三、海康威视3.2无插件版直播&#xff0c;资源下…

论文阅读-在分布式数据库环境中对哈希算法进行负载均衡基准测试

论文名称&#xff1a;Benchmarking Hashing Algorithms for Load Balancing in a Distributed Database Environment 摘要 现代高负载应用使用多个数据库实例存储数据。这样的架构需要数据一致性&#xff0c;并且确保数据在节点之间均匀分布很重要。负载均衡被用来实现这些目…

【Vue3】源码探索之旅:compiler-core之parseChildren函数(二)

简言 parseChildren函数是在baseParse函数中作为createRoot函数的子节点参数传入的&#xff0c;今天来探索下parseChildren函数。 parseChildren在 compiler-core/src/parse.ts文件内。 parseChildren 这个函数就是用来解析模板字符串内容的 &#xff0c;里面有个while循环…

Jmeter学习系列之四:测试计划元素介绍

测试计划元素 JMeter包含各种相互关联但为不同目的而设计的元素。在开始使用JMeter之前&#xff0c;最好先了解一下JMeter的一些主要元素。 注意:测试计划包含至少一个线程组。 以下是JMeter的一些主要组件: 测试计划&#xff08;Plan&#xff09;线程组(Thread Group)控制器…