SpringBoot 一个接口同时支持 form 表单、form-data、json 的优雅写法

SpringBoot 同一个接口同时支持 form 表单、form-data、json 的优雅写法 网上很多代码都是千篇一律的 cvs,相信我只要你认真看完我写的这篇,你就可以完全掌握这个知识点,这篇文章不适合直接 cvs,一定要先理解。 最近重写个项目遇到个比较棘手的问题,老项目是 PHP 接口,这个接口同时兼容 POST json 和 form 表单,更骚的是连 form-data 也兼容。。。因为写 PHP 请求的对接方代码不严谨。详见这里。 而在 Java 中,一个接口只支持一种content-type,json 就用 @RequestBody,form 表单就用 @RequestP... 阅读详情

最近重写个项目遇到个比较棘手的问题,老项目是 PHP 接口,这个接口同时兼容 POST json 和 form 表单,更骚的是连 form-data 也兼容。。。因为写 PHP 请求的对接方代码不严谨。

而在 Java 中,一个接口只支持一种 content-type,json 就用 @RequestBody,form 表单就用 @RequestParam 或不写,form-data 就用 MultipartFile。

兼容版本

如果要把在一个接口中同时兼容三种,比较笨的办法就是获取 HttpServletRequest,然后自己再写方法解析。类似如下:

private Map<String, Object> getParams(HttpServletRequest request) {

    String contentType = request.getContentType();
    if (contentType.contains("application/json")) {
        // json 解析...
        return null;
    } else if (contentType.contains("application/x-www-form-urlencoded")) {
        // form 表单解析 ...
        return null;
    } else if (contentType.contains("multipart")) {
        // 文件流解析
        return null;
    } else {
         throw new BizException("不支持的content-type");
    } 

}

但是这样写有弊端

  • 代码很丑,具体到解析代码又臭又长

  • 只能返回固定 map 或者自己重新组装参数类

  • 无法使用 @Valid 校验参数,像我这种几十个参数都要检验的简直是灾难

优雅版本

网上有 form 表单和 json 同时兼容的版本,但是没有兼容 form-data,我在这做一下补充。

1. 自定义注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GamePHP {
}

2. 自定义注解解析

public class GamePHPMethodProcessor implements HandlerMethodArgumentResolver {

    private GameFormMethodArgumentResolver formResolver;
    private GameJsonMethodArgumentResolver jsonResolver;

    public GamePHPMethodProcessor() {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        PHPMessageConverter PHPMessageConverter = new PHPMessageConverter();
        messageConverters.add(PHPMessageConverter);

        jsonResolver = new GameJsonMethodArgumentResolver(messageConverters);
        formResolver = new GameFormMethodArgumentResolver();
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        GamePHP ann = parameter.getParameterAnnotation(GamePHP.class);
        return (ann != null);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        ServletRequest servletRequest = nativeWebRequest.getNativeRequest(ServletRequest.class);
        String contentType = servletRequest.getContentType();
        if (contentType == null) {
            throw new IllegalArgumentException("不支持contentType");
        }

        if (contentType.contains("application/json")) {
            return jsonResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }

        if (contentType.contains("application/x-www-form-urlencoded")) {
            return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }

        if (contentType.contains("multipart")) {
            return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }

        throw new IllegalArgumentException("不支持contentType");
    }
}

3. 添加到 spring configuration

    @Bean
    public MyMvcConfigurer mvcConfigurer() {
        return new MyMvcConfigurer();
    }

    public static class MyMvcConfigurer implements WebMvcConfigurer {
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
            resolvers.add(new GamePHPMethodProcessor());
        }
    }

4. form-data 的特殊处理

引入 jar 包

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>

新增解析 bean

@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver(){
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    resolver.setDefaultEncoding("UTF-8");
    resolver.setResolveLazily(true);//resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
    resolver.setMaxInMemorySize(40960);
    resolver.setMaxUploadSize(50*1024*1024);//上传文件大小 50M 50*1024*1024
    return resolver;
}

特殊说明,GameJsonMethodArgumentResolver 和 GameFormMethodArgumentResolver 是我们自定义的 json 和 form 解析,如果你没有自定义的,使用 spring 默认的 ServletModelAttributeMethodProcessor 和 RequestResponseBodyMethodProcessor 也可以。

只需将 @RequestParam 注解改为 @GamePHP,接口即可同时兼容三种 content-type。

其流程为,spring 启动的时候,MyMvcConfigurer 调用 addArgumentResolvers 方法将 GamePHPMethodProcessor 注入,接到请求时,supportsParameter 方法判断是否使用此 resolver,如果为 true,则进入 resolveArgument 方法执行。

至此我们可以得出一个结论,PHP 是世界上最垃圾的语言。写代码一时爽,维护火葬场。

电力电子技术(13)——大功率可控整流电路 目录引言2.6.1 带平衡电抗器的双反星形可控整流电路电路结构的特点接平衡电抗器的原因平衡电抗器使得两组三相半波整流电路同时导电的原理分析谐波分析2.6.2 多重化整流电路概述原理目标1)移相多重联结2)多重联结电路的顺序控制3重晶闸管整流桥顺序控制带平衡电抗器的双反星形可控整流电路(是多重化整流电路的重要形式之一)的特点:适用于低电压、大电流的场合。多重化整流电路的特点:绕组的极性相反的目的:消除直流磁通势如图所示,虽然两组相电流的瞬时值不同,但是平均电流相等而绕组的极性相反,所以直流安匝(电流*匝数)互 阅读详情

相关推荐

手把手拆解固态电池成本:2030年真能比液态电池便宜30%吗?

本文深度解析固态电池成本结构,探讨2030年实现比液态电池便宜30%的可行性路径。通过拆解正极材料、负极材料和固态电解质的成本演变,分析关键技术对降本的影响,并预测产业链协同效应下的成本优化趋势。文章指出,在材料创新、设备国产化和政策支持等多重因素推动下,固态电池有望在2030年实现显著降本目标。

kite3的博客 400

SpringBoot 请求同一个方法兼容form格式与requestbody json格式

前言 最近在重构一个旧服务,遇见这么一个问题,旧服务是PHP服务,PHP的controller方法可以同时兼容form的请求格式与requestbody json的请求格式,但是在SpringBoot中,是不可以的,只可以支持单一模式,使用form提交就不可以使用@RequestBody注解去接收,但是这个问题必须需要解决。 问题现象 在这里演示一下所说的问题: 首先是如果使用form格式的请求:...

wtopps的专栏 1万+

一种解决STM32多串口同时收发的方法

在做项目中,遇到了同时调用串口通信时程序崩溃的问题,在项目中,串口1用作调试串口,串口2用作MQTT通信串口,串口3用作下位机通信串口, 串口1重定向以后,用库函数自带的printf函数打印字符串 串口2使用自己写的u2_printf函数,即va_list这套变参宏定义后使用vsprintf函数打印字符串 串口3刚开始使用串口2一样的打印方式,程序在调试调用到串口3打印函数时直接崩溃,后续将串口3改用dma转存输出,仍然无法正常调用 多次研究以后,采用三个串口都使用重定向后的库函数自带的printf

Zxp0605的博客 8796

Springboot接收 Form 表单数据的示例详解

除了在 Controller 里单独定义预处理方法外,我们还可以通过@ControllerAdvice结合@InitBinder来定义全局的参数预处理方法,方便各个Controller使用。(4)如果传递的参数有前缀,且前缀与接收实体类的名称相同,那么参数也是可以正常传递的:来源地址:https://www.yii666.com/blog/298384.html。(2)我们可以结合@InitBinder解决这个问题,通过参数预处理来指定使用的前缀为 u.2,使用 Bean 对象来接收数据。

weixin_44917365的博客 4690

ABAP HANA BP主数据批导

SAPhana官方推荐的创建bp主数据的类是CL_MD_BP_MAINTAIN 客户的创建具体示例代码如下: DATA: LT_RETURN_MAP TYPE MDG_BS_BP_MSGMAP_T. DATA: LS_RETURN_MAP TYPE MDG_BS_BP_MSGMAP. DATA: LS_MESSAGE_MAP TYPE MDG_BS_BP_MSGMAP_KEY. DATA: LT_DATA TYPE CVIS_EI_EXTERN_.

IamRunjiang的博客 4143

高通Camera HAL3调试实战:如何用camxoverridesettings.txt高效抓取日志与dump图像数据

本文深入探讨了高通Camera HAL3调试中camxoverridesettings.txt文件的高效应用,重点介绍了如何通过该文件精准控制日志输出级别与dump图像数据,帮助开发者快速定位移动影像系统中的问题。文章详细解析了日志分级配置、图像数据捕获技巧及典型问题排查流程,为高通Camera HAL3项目开发提供了实用技术点。

weixin_30315905的博客 861

post请求设置表单form-data格式的几种方式

我用默认的post方法发送数据的时候发现后端获取不到数据,然而在network中看到参数是的确传出去的了。而且用postman测试的时候也是可以的,比较了下两个的不同发现是postman使用的是form-data格式,于是用form-data格式再次请求,发现OJBK 这两种格式都是无法使用的: 方法一:配置transformRequest 缺点:其他请求格式的数据也会被重新格式化(PUT,PATCH) import axios from "axios" //引入 //设置axios.

陈新科的博客 1万+

当AI学会写“自传”:OpenClaw 的 SOUL.md 如何把配置文件变成一颗会变形的心

SOUL.md。

步子哥的博客 1308

SpringBoot2.X系列:SpringBoot配置文件详解(4)

前言 Spring Boot配置文件对Spring Boot来说就是入门和基础,经常会用到,基于这一点也必须要普及一下这方面知识点,所以写下做个总结以便日后查看。 配置文件 在我们创建一个新的SrpingBoot项目时,在resources目录下给我们一个默认的全局配置文件 application.properties,打开会发现是一个空的文件,就算我们啥都不配置,一样能启动项目,其实Spring Boot在底层已经把配置都给我们自动配置好了,当在配置文件进行配置时,会修改SpringBoot自动配置的默认

小翔 561

厉害了,华为推出下一代光传送网:fgOTN

2024年10月,在全球信息技术博览会(GITEX Global 2024)上,华为正式发布了其颠覆性的创新产品——端到端细粒度光传送网(fgOTN)解决方案。这一产品组合被誉为行业内首个fgOTN,旨在重塑光传送网络的格局,满足电力运输等行业日益增长的通信需求。在过去的近三十年中,同步数字体系(SDH)技术一直是电信和工业网络的支柱,因其可靠性、稳定性和低延迟而备受青睐。然而,随着数据需求的激增,SDH的最大带宽仅为10 Gbps,逐渐显露出局限性。

网络技术联盟站 634

关于Sybase ASE数据库的license以及试用版过期的问题的解决方案

当用户从Sybase官网上下载了ASE15.0.2以后,如果选择了安装Express Edition或者Developer Edition,基本上不会碰到什么问题,除了有些功能受限以下。 但大多数可能选择了Enterprise Edition for Evaluation类型,即企业版试用。都会碰到这样的问题,即一个月以后,license过期,无法启动server。于是很郁闷,可能大部分人,会选...

iihero@优快云 789

Spring Boot 一个接口同时支持表单表单、form-data、json 的优雅写法

来源:juejin.cn/post/7054441239839506446兼容版本优雅版本1. 自定义注解2. 自定义注解解析3. 添加到 spring configuration4. form-data 的特殊处理❝网上很多代码都是千篇一律的 cvs,相信我只要你认真看完我写的这篇,你就可以完全掌握这个知识点,这篇文章不适合直接 cvs,一定要先理解。❞最近重写个项目遇...

WantFlyDaCheng的博客 438

指纹浏览器指纹工厂(下):基于真实设备数据特征的马尔可夫链生成与校验

本文揭示了静态指纹生成算法在高级风控时序追踪下的致命缺陷,指出违背设备演进马尔可夫性质(如无状态跳跃、因果断裂)是导致指纹存活率骤降的核心原因。通过分析风控系统的时序状态机与多维特征验证机制,提出基于隐马尔可夫模型(HMM)的动态指纹架构:以真实设备的状态转移链为蓝本,构建异步演进的“数字基因熔炉”,通过非均匀时间步长、突发事件响应及微观因果绑定,模拟软硬件独立更新的物理法则。最终实现指纹在时间维度与微观特征上的自洽,规避风控的时序陷阱。

数据知道的博客 415

Spring Boot 一个接口同时支持 form 表单、form-data、json 的优雅写法

原文地址:Spring Boot 一个接口同时支持 form 表单、form-data、json 的优雅写法 网上很多代码都是千篇一律的 cvs,相信我只要你认真看完我写的这篇,你就可以完全掌握这个知识点,这篇文章不适合直接 cvs,一定要先理解。 最近重写个项目遇到个比较棘手的问题,老项目是 PHP 接口,这个接口同时兼容 POST json 和 form 表单,更骚的是连form-data也兼容。。。因为写 PHP 请求的对接方代码不严谨。 而在 Java 中,一个接口只支持一种cont...

u012102536的博客 949

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Spring Boot 一个接口同时支持 form 表单、form-data、json 优雅写法

else if (contentType.contains("multipart")) { // 文件流解析 return null;

代码界的扛把子 656

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

上一篇: 阿里P8熬了一个月肝出这份32W字Java面试手册,在Github标星31K+
下一篇: 程序员新人上午使用 isXxx 形式定义布尔类型,下午就被劝退?
Java5658
博客等级 码龄4年 169粉丝 107原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值