欢迎关注方志朋的博客,回复”666“获面试宝典

来源:https://juejin.cn/post/7054441239839506446

最近重写个项目遇到个比较棘手的问题,老项目是 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");} }

但是这样写有弊端

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

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

  3. 无法使用 @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();}@Overridepublic boolean supportsParameter(MethodParameter parameter) {GamePHP ann = parameter.getParameterAnnotation(GamePHP.class);return (ann != null);}@Overridepublic 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*1024return resolver;
}

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

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

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

热门内容:

  • HashMap夺命14问,你能坚持到第几问?

  • 干掉visio,这个画图神器真的绝了!!!

  • 尽快卸载这两款恶意浏览器插件!已有近 50 万用户安装

  • UUID正在被NanoID取代?

  • 新来了个技术总监:谁再用 @Async 创建线程以后就不用来了!!

  • 最新 955 不加班的公司名单(2022版)

  • 我妈今年 70 岁,受不了Windows蓝屏,用了 21 年的 Linux!YYDS!

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡

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

  1. form表单序列化转换为json对象

    form表单序列化转换为json对象 //form表单序列化转换为json对象 (function($){$.fn.serializeJson=function(){var serializeObj= ...

  2. 一个页面上多个form表单的用json数据格式提交到后台

    在项目开发中遇到多个表单需要提交到后台,而且其中包含一些table数据,所以最后经过查询资料总结出以下方法:(我用的前端框架是layui其他的思想应该是一样的) 在看代码之前先说一下我的思路,因为代码 ...

  3. form表单ajax提交json数据

    前端页面: <form id="userInfo" ><div class="weui-cell"><div class=&quo ...

  4. form表单序列化成json数据 将空值用空字符串代替(form表单中checkBox数据会用逗号隔开拼接成字符串)...

    2019独角兽企业重金招聘Python工程师标准>>> $.fn.notEmptyserializeJson = function () {var o = {};var a = th ...

  5. 细说 Form (表单)

    细说 Form (表单) Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源.虽然Asp.net WebForms框架为了帮助我 ...

  6. 细说 Form (表单)(转)

    细说 Form (表单) Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源. 虽然Asp.net WebForms框架为了帮助 ...

  7. html+form+提交json数据,form表单提交json格式数据

    我的实践整理.java 方式一: 发送数据web $(':submit').on('click',function(){ $.ajax({ url:"buy", type:&quo ...

  8. form表单提交json格式数据

    参考自 jQuery实现ajax提交form表单(可以是提交json),用springmvc接收.图文详解 个人实践整理. 方式一: 发送数据 <script type="applic ...

  9. JavaScript基础(九)form表单、事件、3D

    form表单.事件.3D form表单 form表单操作 event事件对象 案例 事件冒泡 事件的绑定与解绑 键盘事件 默认事件 面试题 选项卡 javascript实现 jQuery实现 3D 3 ...

  10. HTML中的form表单及其提交原理

    HTML中的form表单 form属性 表单内容数据类型 表单控件 input表单控件 type属性 其他属性 button表单控件 label表单控件 表单组件 select option 表单提交 ...

最新文章

  1. Gradle 使用指南 -- 基础配置
  2. 基于 FPGA 的并行全比较排序算法,topK
  3. 从IBM“廉政”说企业内控
  4. shell处理mysql增、删、改、查
  5. 统一建模语言UML整理之开篇
  6. 解决后退,清空验证码(其它文本框保留)
  7. 利用InfoPath生成XML资源文件
  8. Java System.getProperty()
  9. 图文介绍进程和线程的区别
  10. python 微博自动点赞软件_python3 爬虫学习: 自动给你心上人的微博点赞
  11. cs python_python_13(前端—cs)
  12. 最全面的Kano模型详解,及Kano模型为何是5种需求?
  13. 怎么查看电脑连接的wifi密码?2种方法分享给大家!
  14. 线上Request method ‘GET‘ not supported 问题
  15. 凉茶澄清过滤膜分离技术阐述
  16. 云海F150-32UE使用说明
  17. 材料介电常数和导磁率常用测试方案
  18. vue项目对要显示的富文本数据中的图片处理----去掉或控制图片大小
  19. [随便写写] 数字转汉字翻译器
  20. MISRA C指导指南解读系列4(MISRA C规则20-32)

热门文章

  1. Java中如何合并有个具有相同key的Map
  2. python类不支持多继承_Java和C#等不允许多继承类,但是Python是可以的
  3. mysql5.6热升级_mysql 5.6 后热数据的加载
  4. jupyter notebook运行没反应_搭建Jupyter Notebook远程云服务器(Jupyter配置)
  5. nginx的gzip压缩功能
  6. ArcMap 通过DEM获取高程值
  7. 定制简单的Linux系统
  8. 基于最短路方法的生物序列比对问题研究
  9. php 基于socket的基本通信
  10. tomcat在服务器上改了8080的端口之后所带来的问题