一个接口同时支持 form 表单、form-data、json 的优雅写法
欢迎关注方志朋的博客,回复”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");} }
但是这样写有弊端
代码很丑,具体到解析代码又臭又长
只能返回固定 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();}@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 的优雅写法相关推荐
- form表单序列化转换为json对象
form表单序列化转换为json对象 //form表单序列化转换为json对象 (function($){$.fn.serializeJson=function(){var serializeObj= ...
- 一个页面上多个form表单的用json数据格式提交到后台
在项目开发中遇到多个表单需要提交到后台,而且其中包含一些table数据,所以最后经过查询资料总结出以下方法:(我用的前端框架是layui其他的思想应该是一样的) 在看代码之前先说一下我的思路,因为代码 ...
- form表单ajax提交json数据
前端页面: <form id="userInfo" ><div class="weui-cell"><div class=&quo ...
- form表单序列化成json数据 将空值用空字符串代替(form表单中checkBox数据会用逗号隔开拼接成字符串)...
2019独角兽企业重金招聘Python工程师标准>>> $.fn.notEmptyserializeJson = function () {var o = {};var a = th ...
- 细说 Form (表单)
细说 Form (表单) Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源.虽然Asp.net WebForms框架为了帮助我 ...
- 细说 Form (表单)(转)
细说 Form (表单) Form(表单)对于每个WEB开发人员来说,应该是再熟悉不过的东西了,可它却是页面与WEB服务器交互过程中最重要的信息来源. 虽然Asp.net WebForms框架为了帮助 ...
- html+form+提交json数据,form表单提交json格式数据
我的实践整理.java 方式一: 发送数据web $(':submit').on('click',function(){ $.ajax({ url:"buy", type:&quo ...
- form表单提交json格式数据
参考自 jQuery实现ajax提交form表单(可以是提交json),用springmvc接收.图文详解 个人实践整理. 方式一: 发送数据 <script type="applic ...
- JavaScript基础(九)form表单、事件、3D
form表单.事件.3D form表单 form表单操作 event事件对象 案例 事件冒泡 事件的绑定与解绑 键盘事件 默认事件 面试题 选项卡 javascript实现 jQuery实现 3D 3 ...
- HTML中的form表单及其提交原理
HTML中的form表单 form属性 表单内容数据类型 表单控件 input表单控件 type属性 其他属性 button表单控件 label表单控件 表单组件 select option 表单提交 ...
最新文章
- Gradle 使用指南 -- 基础配置
- 基于 FPGA 的并行全比较排序算法,topK
- 从IBM“廉政”说企业内控
- shell处理mysql增、删、改、查
- 统一建模语言UML整理之开篇
- 解决后退,清空验证码(其它文本框保留)
- 利用InfoPath生成XML资源文件
- Java System.getProperty()
- 图文介绍进程和线程的区别
- python 微博自动点赞软件_python3 爬虫学习: 自动给你心上人的微博点赞
- cs python_python_13(前端—cs)
- 最全面的Kano模型详解,及Kano模型为何是5种需求?
- 怎么查看电脑连接的wifi密码?2种方法分享给大家!
- 线上Request method ‘GET‘ not supported 问题
- 凉茶澄清过滤膜分离技术阐述
- 云海F150-32UE使用说明
- 材料介电常数和导磁率常用测试方案
- vue项目对要显示的富文本数据中的图片处理----去掉或控制图片大小
- [随便写写] 数字转汉字翻译器
- MISRA C指导指南解读系列4(MISRA C规则20-32)
热门文章
- Java中如何合并有个具有相同key的Map
- python类不支持多继承_Java和C#等不允许多继承类,但是Python是可以的
- mysql5.6热升级_mysql 5.6 后热数据的加载
- jupyter notebook运行没反应_搭建Jupyter Notebook远程云服务器(Jupyter配置)
- nginx的gzip压缩功能
- ArcMap 通过DEM获取高程值
- 定制简单的Linux系统
- 基于最短路方法的生物序列比对问题研究
- php 基于socket的基本通信
- tomcat在服务器上改了8080的端口之后所带来的问题