一 解決方案web
修改web.xml配置文件 將下面配置拷貝進去(在原有的web-app節點裏面配置 其它配置不變)spring
<!-- 處理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()spring-mvc
/** * 處理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節點裏面配置 其它配置不變)mvc
<!-- 配置文件上傳實現類 -->
<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>
寫一個Controllerapp
/** * 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請求參數綁定問題 趕時間的老哥能夠忽略下文dom
二 解決思路ide
先bb一下原由編碼
我最近再重構一個本身的項目 打算把接口交互修改爲RESTful風格 淺顯的說一下RESTful風格 增刪改查對應POST DELETE PUT GET請求url
環境spa
客戶端: 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; } }
總結
雖然只是寥寥幾句 可是我走完這幾步也花了一下午時間 哈哈哈 技術有限技術有限
但願能幫助到你 若是你的問題獲得解決 請給個推薦點個贊 這樣能幫助到更多人 畢竟搜索不到解決方案的時候太痛苦了