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) object;
            Set nullSet = new HashSet<>();
            for (Map.Entry 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 updateTestCase(Map data);

需要放在请求体里传递的参数都用的存到Map类型的集合里即可


你可能感兴趣的:(JAVA)