SpringMVC 完美解決PUT請求參數綁定問題(普通表單和文件表單)

一 解決方案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;
    }
}

總結

雖然只是寥寥幾句 可是我走完這幾步也花了一下午時間 哈哈哈 技術有限技術有限

但願能幫助到你 若是你的問題獲得解決 請給個推薦點個贊 這樣能幫助到更多人 畢竟搜索不到解決方案的時候太痛苦了

相關文章
相關標籤/搜索