SpringBoot统一功能处理——统一数据返回格式

news2024/11/15 11:12:45

目录

一、简单使用

二、存在的问题描述

三、优点


一、简单使用

统一的数据返回格式使用  @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);
 }
}
supports方法: 判断是否要执行beforeBodyWrite方法。true为执行,false不执行。 通过该方法可以选择哪些类或哪些方法的response要进行处理, 其他的不进行处理。
从returnType获取类名和方法名:
//获取执行的类
Class<?> declaringClass = returnType.getMethod().getDeclaringClass();
//获取执行的方法
Method method = returnType.getMethod();
beforeBodyWrite方法: 对response方法进行具体操作处理。

二、存在的问题描述

SpringMVC默认会注册一些自带的 HttpMessageConverter (从先后顺序排列分别为):
  • ByteArrayHttpMessageConverter 
  • StringHttpMessageConverter 
  • SourceHttpMessageConverter 
  • SourceHttpMessageConverter 
  • AllEncompassingFormHttpMessageConverter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
 implements BeanFactoryAware, InitializingBean {
 
 //...
 public RequestMappingHandlerAdapter() {
 this.messageConverters = new ArrayList<>(4);
 this.messageConverters.add(new ByteArrayHttpMessageConverter());
 this.messageConverters.add(new StringHttpMessageConverter());
 if (!shouldIgnoreXml) {
 try {
 this.messageConverters.add(new SourceHttpMessageConverter<>());
 }
 catch (Error err) {
 // Ignore when no TransformerFactory implementation is available
   }
 }
    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
 }
 //...
}
其中AllEncompassingFormHttpMessageConverter 会根据项目依赖情况添加对应的HttpMessageConverter:
public AllEncompassingFormHttpMessageConverter() {
 if (!shouldIgnoreXml) {
 try {
 addPartConverter(new SourceHttpMessageConverter<>());
 }
 catch (Error err) {
 // Ignore when no TransformerFactory implementation is available
 }
 if (jaxb2Present && !jackson2XmlPresent) {
 addPartConverter(new Jaxb2RootElementHttpMessageConverter());
 }
 }
 if (kotlinSerializationJsonPresent) {
 addPartConverter(new KotlinSerializationJsonHttpMessageConverter());
 }
 if (jackson2Present) {
 addPartConverter(new MappingJackson2HttpMessageConverter());
 }
 else if (gsonPresent) {
 addPartConverter(new GsonHttpMessageConverter());
 }
 else if (jsonbPresent) {
 addPartConverter(new JsonbHttpMessageConverter());
 }
 if (jackson2XmlPresent && !shouldIgnoreXml) {
 addPartConverter(new MappingJackson2XmlHttpMessageConverter());
 }
 if (jackson2SmilePresent) {
 addPartConverter(new MappingJackson2SmileHttpMessageConverter());
 }
}
在依赖中引入jackson包后,容器会把 MappingJackson2HttpMessageConverter 自 动注册到messageConverters 链的末尾。
Spring会根据返回的数据类型, 从 messageConverters 链选择合适的 HttpMessageConverter :
  • 当返回的数据是非字符串时, 使用的 MappingJackson2HttpMessageConverter 写入返回对象。
  • 当返回的数据是字符串时,StringHttpMessageConverter 会先被遍历到,这时会认为 StringHttpMessageConverter 可以使用。
public abstract class AbstractMessageConverterMethodProcessor extends
AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler {

//...代码省略
protected <T> void writeWithMessageConverters(@Nullable T value,
MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse
outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException,
HttpMessageNotWritableException {

//...代码省略
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter
instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter)
converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {

//getAdvice().beforeBodyWrite 执⾏之后, body转换成了Result类型的结果
body = getAdvice().beforeBodyWrite(body, returnType,
selectedMediaType,
(Class<? extends HttpMessageConverter<?>>)
converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
   if (genericConverter != null) {
 genericConverter.write(body, targetType, 
selectedMediaType, outputMessage);
 }
 else {
 //此时cover为StringHttpMessageConverter
 ((HttpMessageConverter) converter).write(body, 
selectedMediaType, outputMessage);
 }
 }
 else {
 if (logger.isDebugEnabled()) {
 logger.debug("Nothing to write: null body");
 }
 }
 return;
 }
 }
 }
 //...代码省略
 
 }
 //...代码省略
}
((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. 有利于后端技术部门的统一规范的标准制定, 不会出现稀奇古怪的返回内容。

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

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

相关文章

【jQuery】入门学习篇

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、jQuery简介及使用详解&#xff1a;☀️☀️☀️2.1 jQuery简介2.2 引入jQuery① 第一种引入方式&#xff1a;直接路径引入② 第二种引入方式&#xff1a;使用第三方CDN 后序还在更新中~~~三、总结&#xff1a;&am…

C++_基本语法笔记_类和对象

对于有Java基础的思想不过多记录&#xff0c;仅看语法 创建和封装对象 类似Java中的set操作&#xff0c;可以写一个赋值操作用于给实例化对象赋属性值 三种权限&#xff1a;public &#xff0c; protect &#xff0c;private Class和Struct区别 Struct默认为public权限cla…

SpringBoot统一功能处理——拦截器

目录 一、什么是拦截器&#xff1f; 二、拦截器使用 2.1 定义拦截器 2.2 注册配置拦截器 三、拦截器详解 3.1 拦截器的拦截路径配置 3.2 拦截器执行流程 一、什么是拦截器&#xff1f; 拦截器是Spring框架提供的核心功能之一, 主要用来拦截用户的请求, 在指定方法前后,…

C语言 | Leetcode C语言题解之第332题重新安排行程

题目&#xff1a; 题解&#xff1a; char* id2str[26 * 26 * 26];int str2id(char* a) {int ret 0;for (int i 0; i < 3; i) {ret ret * 26 a[i] - A;}return ret; }int cmp(const void* _a, const void* _b) {int **a (int**)_a, **b (int**)_b;return (*b)[0] - (*…

python网络爬虫使用代理

Python网络爬虫使用代理的实用指南 在网络爬虫的开发过程中&#xff0c;使用代理是一个非常重要的环节。代理不仅可以帮助爬虫绕过反爬虫机制&#xff0c;还能保护开发者的隐私。本文将介绍如何在Python中使用代理进行网络爬虫&#xff0c;包括基本的设置和示例代码。 1. 代理…

手机短视频素材网站有哪些啊?手机视频素材库网站分享

在当今的数字时代&#xff0c;智能手机与社交媒体平台的融合推动了手机短视频的兴起。这种形式的媒体已经渗透到我们的日常生活中&#xff0c;无论是作为娱乐手段、教育工具还是商业推广手段&#xff0c;优质的短视频都具有极高的吸引力和广泛的应用价值。因此&#xff0c;选择…

『 C++ 』智能指针 ( 万字梳理 )

文章目录 智能指针概念内存泄漏的危害RAII与智能指针智能指针的赋值auto_ptr 管理权转移auto_ptr 的对象悬空问题 unique_ptr 防拷贝unique_ptr 简单实现 shared_ptr 引用计数shared_ptr 简单实现shared_ptr 的循环引用问题与 weak_ptr 智能指针的自定义删除器 智能指针概念 智…

【独家原创】基于NRBO-Transformer多特征分类预测【24年新算法】 (多输入单输出)Matlab代码

【独家原创】NRBO-Transformer分类 Matlab代码 基于牛顿拉夫逊优化算法优化Transformer的数据分类预测&#xff0c;Matlab代码&#xff0c;可直接运行&#xff0c;适合小白新手 NRBO优化的超参数为&#xff1a;自注意力机制中的头数、正则化系数、初始化学习率 1.程序已经调试…

《知识点扫盲 · Redis 分布式锁》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

数据库索引设计原则

1. 概述 索引是优化数据库性能最重要的工具之一。但是&#xff0c;创建过多的索引或索引错误的列也会对性能产生负面影响。因此&#xff0c;在设计索引时遵循一定的原则很重要。 2. 原则A - 根据工作负载创建索引 创建高效索引最重要的原则是根据您的工作负载而不是表结构创…

数据库连接池的深入学习

为什么需要数据库连接池&#xff1f; 正常操作数据库需要对其进行连接&#xff0c;访问数据库&#xff0c;执行sql语句&#xff0c;断开连接。 创建数据库连接是一个昂贵的过程&#xff0c;在高并发的情况下&#xff0c;频繁的创建数据库的连接可能会导致数据库宕机。 有了连…

Leetcode JAVA刷刷站(8)字符串转换整数

一、题目概述 二、思路方向 要实现这个功能&#xff0c;我们可以遵循以下步骤来编写 myAtoi 函数&#xff1a; 去除前导空格&#xff1a;使用循环或字符串的 trim() 方法&#xff08;虽然直接操作字符串更高效的方式是使用循环&#xff09;。检查符号&#xff1a;记录第一个非…

TGANet部分复现

Kvasir-SEG复现结果 M e t h o d m I o U m D S C R e c a l l P r e c i s i o n F 2 P r a N e t − − − − − − 0.9663704860609511 − − T G A N e t 0.8331 0.8982 0.9132 − − 0.9029 \begin{array}{lccccr} Method&mIoU&mDSC&Recall&Precision&a…

5、Linux : 网络相关

OSI七层网络模型 TCP/IP四层 概念模型 对应网络协议 应用层&#xff08;Application&#xff09; HTTP、TFTP, FTP, NFS, WAIS、 表示层&#xff08;Presentation&#xff09; 应用层 Telnet, Rlogin, SNMP, Gopher 会话层&#xff08;Session&#xff09; SMTP…

ICETEK-DM6437-AICOM——CPU定时器及直流电机控制中断控制

一、设计目的&#xff1a; 1.1 CPU定时器程序设计&#xff1b; 1.2 2直流电机程序设计&#xff1b; 1.3 外中断。 二、设计原理&#xff1a; 2.1 定时器的控制&#xff1a; 在DM6437&#xff08;是一种数字信号处理器&#xff0c;DSP&#xff09;上使用其内部定时器和中断来…

设计模式-动态代理模式

目录 什么是代理模式&#xff1f; 为什么要用代理模式&#xff1f; 有哪几种代理模式&#xff1f; 动态代理&#xff08;jdk自带&#xff09;&#xff1a; 动态代理&#xff08;第三方库-cglib&#xff09;&#xff1a; 什么是代理模式&#xff1f; 代理模式给某一个对象提供…

Windows10不能直接拖拽文件到微信或者钉钉的解决办法【玖毅网】

不知道从何时起,微信、QQ和钉钉等相关软件,无法拖拽文件到对话窗口,拖拽的时候显示一个红色图标,可能是上次更新win之后导致的,所以嘛,系统真的不能设置自动更新,说不准哪些更新就把原设置覆盖或者关闭了,哎,吃一堑长一智吧,赶紧关闭自动更新,emmmm我在说我自己啊。…

日撸Java三百行(day17:链队列)

目录 一、队列基础知识 1.队列的概念 2.队列的实现 二、代码实现 1.链队列创建 2.链队列遍历 3.入队 4.出队 5.数据测试 6.完整的程序代码 总结 一、队列基础知识 1.队列的概念 今天我们继续学习另一个常见的数据结构——队列。和栈一样&#xff0c;队列也是一种操…

零基础5分钟上手谷歌云GCP核心云开发技能 - 利用语音AI服务搭建应用

简介&#xff1a; 欢迎来到小李哥全新谷歌云GCP云计算知识学习系列&#xff0c;适用于任何无云计算或者谷歌云技术背景的开发者&#xff0c;让大家零基础5分钟通过这篇文章就能完全学会谷歌云一个经典的服务开发架构方案。 我将每天介绍一个基于全球三大云计算平台&#xff0…

arcgis(shp)注记转CAD(dwg)文字

arcgis&#xff08;shp&#xff09;注记转CAD&#xff08;dwg&#xff09;文字方法如下&#xff1a; 1、添加shp文件&#xff0c;标注要素&#xff0c;然后选标注转注记 2、 点击文件夹图标打开文件夹&#xff0c;选择保存路径。&#xff08;提前需新建好文件地理数据库、数据…