SpringMVC 完美解决PUT请求参数绑定问题(普通表单和文件表单)
一 解决方案
修改web.xml配置文件 将下面配置拷贝进去(在原有的web-app节点里面配置 其它配置不变)
<!-- 处理PUT提交参数(只对基础表单生效) -->
<filter>
<filter-name>httpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpPutFormContentFilter</filter-name>
<!-- 拦截所有 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
写一个PostAndPutCommonsMultipartResolver继承CommonsMultipartResolver 重写isMultipart()
/**
* 处理PUT提交参数(只对文件表单生效)
* Created by Hy on 2018/9/30.
*/
public class PostAndPutCommonsMultipartResolver extends CommonsMultipartResolver { @Override
public boolean isMultipart(HttpServletRequest request) {
if ("POST".equalsIgnoreCase(request.getMethod()) || "PUT".equalsIgnoreCase(request.getMethod())) {
return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
}
return false;
} }
修改spring-mvc.xml配置文件 将下面配置拷贝进去(在原有的beans节点里面配置 其它配置不变)
<!-- 配置文件上传实现类 -->
<bean id="multipartResolver" class="com.hy.mm.manager.resolver.PostAndPutCommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8" />
<!-- 文件上传大小(单位B) 30M = 30 * 1024 * 1024 -->
<property name="maxUploadSize" value="31457280" />
</bean>
写一个Controller
/**
* PUT请求
* Created by Hy on 2018/9/30.
*/
@Controller
public class PutController { @PutMapping("/put/normal") @ResponseBody
public String normalForm(String name, Integer age) {
System.out.println("name = " + name);
System.out.println("age = " + age);
return "ok";
} @PutMapping("/put/file") @ResponseBody
public String fileForm(String name, MultipartFile file) throws Exception {
System.out.println("name = " + name);
if (null != file && !file.isEmpty()) {
System.out.println("file = " + file.getSize());
// 保存图片
String fileName = UUID.randomUUID().toString().replace("-", ""); //文件名
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); //扩展名 不包含(.)
file.transferTo(new File("/Users/HUANGYI/Downloads/" + fileName + "." + extension));
return "ok";
}
return "error";
} }
以上就能完美解决PUT请求参数绑定问题 赶时间的老哥可以忽略下文
二 解决思路
先bb一下起因
我最近再重构一个自己的项目 打算把接口交互修改成RESTful风格 浅显的说一下RESTful风格 增删改查对应POST DELETE PUT GET请求
环境
客户端: Android 使用Retrofit发起请求
服务端: Java 使用SpringMVC处理请求
思路
客户端使用PUT请求发送表单数据 不管是普通表单还是文件表单 服务端Controller层参数绑定均为null
但是 客户端使用PUT请求发送非文件数据携带在Url上(类似GET请求) 服务端Controller层参数就能接收到
为了避免重复造轮子 我用Google解决了普通表单数据接收不到 也就是使用上面说的org.springframework.web.filter.HttpPutFormContentFilter就可以解决该问题
但是 文件表单数据还是接收不到 Google也不好用了 不知道是不是我姿势不对
自己尝试解决吧
先验证文件表单数据到底写入请求体没有?
我用logging-interceptor和Charles观察了好几遍请求 确认了数据确实已经写入了请求体
那么 问题肯定就出现在SpringMVC的文件参数绑定上
仔细观察org.springframework.web.multipart.commons.CommonsMultipartResolver

其中 isMultipart()是一个比较重要的方法 用来判断请求是否包含多部分内容 也就是判断是否是文件表单 深入观察一下该方法的实现

真相大白 该方法默认POST请求才可能包含多部分内容
使用上面说的PostAndPutCommonsMultipartResolver就可以解决该问题
Android客户端核心代码
/**
* ...
* Created by Hy on 2018/9/30.
*/
public interface PutApi { @PUT("/put/normal") @FormUrlEncoded
Call<ResponseBody> normal(@Field("name") String name, @Field("age") Integer age); @PUT("/put/file") @Multipart
Call<ResponseBody> file(@Part("name") String name, @Part MultipartBody.Part file);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.normal:
Call<ResponseBody> normalCall = mApi.normal("黄祎", 18);
normalCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.i("HUANG", "code = " + response.code());
if (null != response.body())
Log.i("HUANG", "body = " + response.body().string()); } catch (IOException e) {
e.printStackTrace();
}
} @Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("HUANG", "t = " + t.getMessage());
}
}); break; case R.id.file:
RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), copy());
MultipartBody.Part body = MultipartBody.Part.createFormData("file", "a.mp4", fileBody);
Call<ResponseBody> fileCall = mApi.file("黄祎", body);
fileCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.i("HUANG", "code = " + response.code());
if (null != response.body())
Log.i("HUANG", "body = " + response.body().string()); } catch (IOException e) {
e.printStackTrace();
}
} @Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("HUANG", "t = " + t.getMessage());
}
});
break;
}
}
总结
虽然只是寥寥几句 但是我走完这几步也花了一下午时间 哈哈哈 技术有限技术有限
希望能帮助到你 如果你的问题得到解决 请给个推荐点个赞 这样能帮助到更多人 毕竟搜索不到解决方案的时候太痛苦了
SpringMVC 完美解决PUT请求参数绑定问题(普通表单和文件表单)的更多相关文章
- SpringMVC 请求参数绑定
什么是请求参数绑定 请求参数格式 默认是key/value格式,比如:http:xxxx?id=1&type=2 请求参数值的数据类型 都是字符串类型的各种值 请求参数值要绑定的目标类型 Co ...
- springmvc:请求参数绑定集合类型
一.请求参数绑定实体类 domain: private String username; private String password; private Double money; private ...
- Spring MVC请求参数绑定
所谓请求参数绑定,就是在控制器方法中,将请求参数绑定到方法参数上 @RequestParam 绑定单个请求参数到方法参数上 @RequestParam("id") Integer ...
- 阶段3 3.SpringMVC·_02.参数绑定及自定义类型转换_1 请求参数绑定入门
请求参数的绑定 参数绑定 创建新的页面 给方法加上注解 前面没有斜线 重新部署项目 传递一个username的值 后台方法接收 重新部署项目 再传一个password的值 再输出password ja ...
- Springmvc中 同步/异步请求参数的传递以及数据的返回
转载:http://blog.csdn.net/qh_java/article/details/44802287 注意: 这里的返回就是返回到jsp页面 **** controller接收前台数据的方 ...
- SpringMVC【参数绑定、数据回显、文件上传】
前言 本文主要讲解的知识点如下: 参数绑定 数据回显 文件上传 参数绑定 我们在Controller使用方法参数接收值,就是把web端的值给接收到Controller中处理,这个过程就叫做参数绑定.. ...
- SpringMVC学习(二)———— 参数绑定
一.参数绑定 1.1.什么是参数绑定? 客户在浏览器端会提交一些参数到服务器端,比如用户的登录等,就会传username 和 password过来,springmvc则通过参数绑定组件将请求参数的内容 ...
- springmvc中同步/异步请求参数的传递以及数据的返回
注意: 这里的返回就是返回到jsp页面 **** controller接收前台数据的方式,以及将处理后的model 传向前台***** 1.前台传递数据的接受:传的属性名和javabean的属性相同 ...
- Spring MVC请求参数绑定 自定义类型转化 和获取原声带额servlet request response信息
首先还在我们的框架的基础上建立文件 在domian下建立Account实体类 import org.springframework.stereotype.Controller; import org. ...
随机推荐
- IDL创建泰森多边形
结果图: 附加源码: PRO testVoronoi idx = 0 ; 创建离散点 CASE idx OF ; 随机离散点 0: BEGIN N = 36 X = RANDOMN(seed, N) ...
- 面向对象课程 - 寒假第三次作业 - C++计算器项目初始部分
C++计算器项目初始部分 零.项目源文件地址 传送门:calculator 一.项目信息相关: 项目:Calculator 版本:1.0 日期:2016.2.16 实现: 基本的操作界面 对四则运算表 ...
- log4jnet不记录日志的问题解决
背景:dll文件从别人项目里复制过来的,配置文件是从别的项目里配置过来的.然后就是不写日志. 最后经过搜索原项目,发现需要在AssemblyInfo.cs文件里加一段话, [assembly: log ...
- 如何动态调用 C 函数
JSPatch 支持了动态调用 C 函数,无需在编译前桥接每个要调用的 C 函数,只需要在 JS 里调用前声明下这个函数,就可以直接调用: require('JPEngine').addExtensi ...
- 1297. [SCOI2009]迷路【矩阵乘法】
Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同 ...
- Apache HttpComponents中的cookie匹配策略
Apache HttpComponents中的cookie匹配策略 */--> pre.src {background-color: #292b2e; color: #b2b2b2;} pre. ...
- openvpn-在Linux中安装和配置OpenVPN Server的最简便方法!(转)
在Linux中安装和配置OpenVPN Server 出于本文的需要,我将使用两个运行CentOS 7 64位版本的系统.一个充当OpenVPN服务器,另一个充当OpenVPN客户机.下面是测试系统的 ...
- JavaScript跨源资源共享
CORS(跨 源资源共享)基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应式应该成功还是失败 IE对CORS的实现 IE8引入了XDR类型,与XHR类似,但可以实现安 ...
- 文字属性和div容器盒的使用基础
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- hive--数据仓库
1.1.1 hive是什么? Hive是基于 Hadoop 的一个数据仓库工具: 1. hive本身不提供数据存储功能,使用HDFS做数据存储: 2. hive也不分布 ...