Spring Cloud中FeignClient支持上傳文件的同時提交表單數據

前不久才解決的,Spring Cloud中FeignClient中上傳文件的問題,今天項目組其他同事就又發現了別的問題。

FeignClient發送post請求時,參數聲明都加了@RequestParam,這個註解,表明參數以查詢字符串形式傳遞,即拼在url後面,但有時參數太長就會在被調用端報請求頭太長的錯:request header is too large,這時就得把請求參數放在請求體裏,因爲url長度是有限制的,大概就在一千多字符的樣子吧,(我記得chrome和IE對url長度的限制是這樣的,chrome可能略長些,但也相差不大,至於後臺的限制估計應該是差不多的)而post的請求體長度就要大得多了,沒查過具體有沒有限制,但即使有,也很難達到這個極限吧

所以就讓同事把比較長的參數放請求體裏傳,即去掉@RequestParam,默認就會放在請求體裏了,或者改用@RequestPart註解也是一樣的,改完之後又報了一個新錯誤:Too many body parameters,也就是說只能有一個沒註解或用@RequestPart註解的,然後百度怎麼在FeignClient裏傳表單數據,有解決方案,但是我這個接口還要上傳文件,用不了那個方案,於是只好再去看前一次解決的上傳文件引的庫的源碼,研究了下,試着再對其進行下擴展,加入對Map類型的參數的判斷,測試了下,對參數值爲null的有報錯,所以又加了段代碼去掉了值爲null的參數,測試通過了,下面是這次擴展後的代碼:

@Override
    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
        if (((ParameterizedTypeImpl) bodyType).getRawType().equals(Map.class)) {
            val data = (Map<String, Object>) object;
            Set<String> nullSet = new HashSet<>();
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                if (entry.getValue() == null) {
                    nullSet.add(entry.getKey());
                }
            }
            for (String s : nullSet) {
                data.remove(s);
            }
            super.encode(data, MAP_STRING_WILDCARD, template);
            return;
        } else if (bodyType.equals(MultipartFile.class)) {
            val file = (MultipartFile) object;
            val data = singletonMap(file.getName(), object);
            super.encode(data, MAP_STRING_WILDCARD, template);
            return;
        } else if (bodyType.equals(MultipartFile[].class)) {
            val file = (MultipartFile[]) object;
            if (file != null) {
                val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
                super.encode(data, MAP_STRING_WILDCARD, template);
                return;
            }
        }
        super.encode(object, bodyType, template);
    }

而FeignClient裏的方法聲明爲:

 @ResponseBody
    @RequestMapping(value = "/ctstestcase/updateTestCase", method = {RequestMethod.POST},consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
    Map<String, Object> updateTestCase(Map<String, Object> data);

需要放在請求體裏傳遞的參數都用的存到Map<String,  Object>類型的集合裏即可


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章