一 解决方案
修改 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;
- }
- }
总结
虽然只是寥寥几句 但是我走完这几步也花了一下午时间 哈哈哈 技术有限技术有限
希望能帮助到你 如果你的问题得到解决 请给个推荐点个赞 这样能帮助到更多人 毕竟搜索不到解决方案的时候太痛苦了
来源: https://www.cnblogs.com/huangyi-427/p/9742000.html