解决Long类型到web端失精度引发的API接口空响应

2024-08-25 21:32

本文主要是介绍解决Long类型到web端失精度引发的API接口空响应,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

          • 事故代码
          • 触发的问题点
          • 解决空响应
          • 为什么写出response的拦截器没注册上
          • 添加@EnableWebMvc和implement WebMvcConfigurer的区别
          • 为什么单纯extends WebMvcConfigurationSupport会引发拦截器未注册
          • 其他

事故代码
@Configuration
public class LongToStringJsonConfig extends WebMvcConfigurationSupport {public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = new ObjectMapper();SimpleModule simpleModule = new SimpleModule();simpleModule.addSerializer(Long.class, ToStringSerializer.instance);simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);objectMapper.registerModule(simpleModule);jackson2HttpMessageConverter.setObjectMapper(objectMapper);converters.add(jackson2HttpMessageConverter);}
}
  • 我最开始项目里,单纯解决Long转String需求时,写的是如上代码。好吧,诚实一点,抄的是以上代码。然而这段代码导致我所有的接口,都是空响应。
触发的问题点
  • 1,Spring的request和response的stream只能读一次,再次读取的时候,stream就为空了。
  • 2,通过debug,项目引入了一个底层包,经过了一个filter。而这个filter做了一件事:
        ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);chain.doFilter(wrapperRequest, wrapperResponse);
  • filter将response包入到了ContentCachingResponseWrapper里边
  • 3,在底层包里,后续有一个interceptor 在afterCompletion方法中,会将ContentCachingResponseWrapper的内容写出去。
  • 4,再次debug,发现写出ContentCachingResponseWrapper的interceptor并未被注入。
解决空响应
  • 最开始的尝试chain.doFilter(wrapperRequest, wrapperResponse);将filter的这行操作,换成chain.doFilter(wrapperRequest, response);此时,接口正常响应。问题是:我项目中的空响应解决了,但底层包里interceptor想要拦截读取一些信息记录的需求实现就被破坏了。PS:虽然我连这个interceptor都没注册上吧。 所以,这个方案,是行不通的。 问题又指向于:为什么没有触发后续的interceptor去调用responseWrapper.copyBodyToResponse()方法写出响应。
  • 慢慢回顾,发现就是多了我新增的一个类,就出现空响应。去掉的话,就是正常响应。仔细看,我的类没什么特别,唯一特别的就是 extends WebMvcConfigurationSupport。 那么WebMvcConfigurationSupport被继承,会发生啥呢?
为什么写出response的拦截器没注册上
  • 我的config代码唯一的不通,就是继承了WebMvcConfigurationSupport。那么这个WebMvcConfigurationSupport是怎么工作的呢?
  • 仔细查代码,或者debug,就可以发现,在WebMvcConfigurationSupport里有个接口获取拦截器:
	/*** Provide access to the shared handler interceptors used to configure* {@link HandlerMapping} instances with.* <p>This method cannot be overridden; use {@link #addInterceptors} instead.*/protected final Object[] getInterceptors() {if (this.interceptors == null) {InterceptorRegistry registry = new InterceptorRegistry();addInterceptors(registry);registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));this.interceptors = registry.getInterceptors();}return this.interceptors.toArray();}
  • 这个接口不可以被重写。而中间有个addInterceptors(registry)方法,所以,interceptor要注册上,至少也得是实现了这个addInterceptors(registry)方法的。 PS:这里还可以看一下WebMvcConfigurationSupport类的作用说明:

This is the main class providing the configuration behind the MVC Java config. It is typically imported by adding {@link EnableWebMvc @EnableWebMvc} to an application {@link Configuration @Configuration} class. An alternative more advanced option is to extend directly from this class and override methods as necessary, remembering to add {@link Configuration @Configuration} to the subclass and {@link Bean @Bean} to overridden {@link Bean @Bean} methods.

  • 在WebMvcConfigurationSupport里,可以看到的是It is typically imported by adding {@link EnableWebMvc @EnableWebMvc} to an application {@link Configuration @Configuration} class。所以,第一个解决拦截器未注册上的方案,也就出来了。就是在我的类上,除了@Configuration外,再加一个注解@EnableWebMvc。 至此,空响应问题解决。第二个解决方案,在我的类中,实现addInterceptors(registry)的方法注入底层包里可以打印出response的interceptor。
  • 通过WebMvcConfigurationSupport 找到@EnableWebMvc和接口WebMvcConfigurer。仔细看WebMvcConfigurer接口的定义。第三个解决方案出来了,让我的类不再继承WebMvcConfigurationSupport类,而改为implement WebMvcConfigurer。
添加@EnableWebMvc和implement WebMvcConfigurer的区别
  • 区别主要从WebMvcConfigurer的addInterceptors(InterceptorRegistry registry)的方法声明定义中可以看出:

Add Spring MVC lifecycle interceptors for pre- and post-processing of controller method invocations. Interceptors can be registered to apply to all requests or be limited to a subset of URL patterns.

Note that interceptors registered here only apply to controllers and not to resource handler requests.To intercept requests for static resources either declare a {@link org.springframework.web.servlet.handler.MappedInterceptor MappedInterceptor} bean or switch to advanced configuration mode by extending {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport WebMvcConfigurationSupport} and then override {@code resourceHandlerMapping}.

  • 通过WebMvcConfigurer的方式,无法拦截静态资源,但可以通过其他方式进行扩展实现。
为什么单纯extends WebMvcConfigurationSupport会引发拦截器未注册
  • 在@SpringBootApplication中,会引入@EnableAutoConfiguration,在什么都不做的时候,指:即不加@EnableWebMvc也不搞implement WebMvcConfigurer的时候,那些拦截器是怎么注册的呢?
  • 通过@EnableWebMvc找到了如下类:
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
  • 可以看到假如没有自定义的WebMvcConfigurationSupport类,类WebMvcAutoConfiguration就会执行。在此类中通过extends DelegatingWebMvcConfiguration ,再有DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport,在DelegatingWebMvcConfiguration类中,实现了addInterceptors(registry)方法。
  • 所以,关键就是WebMvcConfigurationSupport类中的addInterceptors(registry)一定要有实现。如果不继承此类,那么有默认的实现方式,如果用户自己实现类此类,就需要处理addInterceptors(registry)的实现。
其他
  • 我准备再搞搞Spring boot的自动装配,为啥@Configuration一加就妥了呢

这篇关于解决Long类型到web端失精度引发的API接口空响应的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106705

相关文章

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Python中Json和其他类型相互转换的实现示例

《Python中Json和其他类型相互转换的实现示例》本文介绍了在Python中使用json模块实现json数据与dict、object之间的高效转换,包括loads(),load(),dumps()... 项目中经常会用到json格式转为object对象、dict字典格式等。在此做个记录,方便后续用到该方

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

SpringBoot通过main方法启动web项目实践

《SpringBoot通过main方法启动web项目实践》SpringBoot通过SpringApplication.run()启动Web项目,自动推断应用类型,加载初始化器与监听器,配置Spring... 目录1. 启动入口:SpringApplication.run()2. SpringApplicat

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec