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

沙海 2022年6月19日09:21:50Java评论25字数 4990阅读16分38秒阅读模式
摘要

智能摘要

速蛙云 - 极致体验,强烈推荐!!!

智能摘要文章源自JAVA秀-https://www.javaxiu.com/66957.html

网上有form表单和json同时兼容的版本,但是没有兼容form-data,我在这做一下补充。只需将@RequestParam注解改为@GamePHP,接口即可同时兼容三种content-type。文章源自JAVA秀-https://www.javaxiu.com/66957.html

原文约 1604 | 图片 2 | 建议阅读 4 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/66957.html

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

Java学习者社区 文章源自JAVA秀-https://www.javaxiu.com/66957.html

点击关注公众号,Java干货及时送达?文章源自JAVA秀-https://www.javaxiu.com/66957.html

文章源自JAVA秀-https://www.javaxiu.com/66957.html

Spring Boot 一个接口同时支持 form 表单、form-data、json 的优雅写法文章源自JAVA秀-https://www.javaxiu.com/66957.html

来源:juejin.cn/post/7054441239839506446文章源自JAVA秀-https://www.javaxiu.com/66957.html

网上很多代码都是千篇一律的 cvs,相信我只要你认真看完我写的这篇,你就可以完全掌握这个知识点,这篇文章不适合直接 cvs,一定要先理解。文章源自JAVA秀-https://www.javaxiu.com/66957.html

最近重写个项目遇到个比较棘手的问题,老项目是 PHP 接口,这个接口同时兼容 POST json 和 form 表单,更骚的是连 form-data 也兼容。。。因为写 PHP 请求的对接方代码不严谨。文章源自JAVA秀-https://www.javaxiu.com/66957.html

而在 Java 中,一个接口只支持一种 content-type,json 就用 @RequestBody,form 表单就用 @RequestParam 或不写,form-data 就用 MultipartFile文章源自JAVA秀-https://www.javaxiu.com/66957.html

兼容版本

如果要把在一个接口中同时兼容三种,比较笨的办法就是获取 HttpServletRequest,然后自己再写方法解析。类似如下:文章源自JAVA秀-https://www.javaxiu.com/66957.html

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");    } }

但是这样写有弊端文章源自JAVA秀-https://www.javaxiu.com/66957.html

  • 代码很丑,具体到解析代码又臭又长文章源自JAVA秀-https://www.javaxiu.com/66957.html

  • 只能返回固定 map 或者自己重新组装参数类文章源自JAVA秀-https://www.javaxiu.com/66957.html

  • 无法使用 @Valid 校验参数,像我这种几十个参数都要检验的简直是灾难文章源自JAVA秀-https://www.javaxiu.com/66957.html

优雅版本

网上有 form 表单和 json 同时兼容的版本,但是没有兼容 form-data,我在这做一下补充。文章源自JAVA秀-https://www.javaxiu.com/66957.html

1. 自定义注解

@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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 包文章源自JAVA秀-https://www.javaxiu.com/66957.html

    <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文章源自JAVA秀-https://www.javaxiu.com/66957.html

@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 也可以。文章源自JAVA秀-https://www.javaxiu.com/66957.html

只需将 @RequestParam 注解改为 @GamePHP,接口即可同时兼容三种 content-type文章源自JAVA秀-https://www.javaxiu.com/66957.html

其流程为,spring 启动的时候,MyMvcConfigurer 调用 addArgumentResolvers 方法将 GamePHPMethodProcessor 注入,接到请求时,supportsParameter 方法判断是否使用此 resolver,如果为 true,则进入 resolveArgument 方法执行。文章源自JAVA秀-https://www.javaxiu.com/66957.html

推荐阅读• IntelliJ IDEA快捷键大全 + 动图演示,建议收藏!• MyBatis-Plus 使用这么方便,底层是如何处理的呢?• Mybatis查询结果为空时,为什么返回值为NULL或空集合?• Redis+Guava,性能炸裂!最近面试BATJ,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。

PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持一下呀文章源自JAVA秀-https://www.javaxiu.com/66957.html

继续阅读
文章末尾固定信息...
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定