使用RestTemplate调用上传文件且带参数的远程接口

你知道的越多,你不知道的越多
点赞再看,养成习惯
如果您有疑问或者见解,或者没有积分想获取项目和定制项目,欢迎指教:
企鹅:869192208

需求

根据对接的需要,需要请求一个使用 SSM 框架编写的文件上传的接口,该接口的请求方式为Post请求,请求参数全部是以 form-data 表单形式进行提交,包含多个参数,且方法中,文件是由 request 中获取到,示例代码如下:

	@RequestMapping(value = "uploadAttach")
    public void uploadAttach(@RequestParam(value = "tableName", required = false) String tableName,
                             @RequestParam(value = "tableCode", required = false) String tableCode,
                             @RequestParam(value = "configCode", required = false) String configCode,
                             @RequestParam(value = "tableColumn", required = false) String tableColumn,
                             HttpServletResponse response, HttpServletRequest request) {
        Map<String, Object> rtn = new HashMap<String, Object>();
        try {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            Map<String, List<MultipartFile>> multipartFiles = multipartRequest.getMultiFileMap();
            /**业务操作**/
        } catch (Exception e) {
            rtn.put("success", false);
        }
    }

下面提供三种解决方案

方式一:使用 RestTemplate 进行调用
public Object uploadAttach(String tableName, String tableCode, String configCode, String tableColumn, File img) {
        try {
            String uploadAttach = "http://xxx/uploadAttach";
            FileInputStream fileInputStream=new FileInputStream(img);
            //请求头设置为MediaType.MULTIPART_FORM_DATA类型
            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
            //构建请求体
            MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
            CommonInputStreamResource commonInputStreamResource = null;
            try {
                commonInputStreamResource = new CommonInputStreamResource(fileInputStream,img.length(),img.getName());
            } catch (Exception e) {
                log.error("文件输入流转换错误",e);
            }
            requestBody.add("tableName", tableName);
            requestBody.add("tableCode", tableCode);
            requestBody.add("configCode", configCode);
            requestBody.add("tableColumn", tableColumn);
            requestBody.add("file",commonInputStreamResource);
            HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(requestBody, requestHeaders);
            //直接调用远程接口
            ResponseEntity<String> entity = restTemplate.postForEntity(uploadAttach,requestEntity, String.class);
            String responseValue = (String)entity.getBody();
            log.info("---->响应值为:" + responseValue);
        } catch (Exception e) {
            log.error("上传文件接口调用失败",e);
        }
    }

class CommonInputStreamResource extends InputStreamResource {
        private long length;
        private String fileName;
        public CommonInputStreamResource(InputStream inputStream, long length, String fileName) {
            super(inputStream);
            this.length = length;
            this.fileName = fileName;
        }

        /**
         * 覆写父类方法
         * 如果不重写这个方法,并且文件有一定大小,那么服务端会出现异常
         * {@code The multi-part request contained parameter data (excluding uploaded files) that exceeded}
         */
        @Override
        public String getFilename() {
            return fileName;
        }

        /**
         * 覆写父类 contentLength 方法
         * 因为 {@link org.springframework.core.io.AbstractResource#contentLength()}方法会重新读取一遍文件,
         * 而上传文件时,restTemplate 会通过这个方法获取大小。然后当真正需要读取内容的时候,发现已经读完,会报如下错误。
         */
        @Override
        public long contentLength() {
            long estimate = length;
            return estimate == 0 ? 1 : estimate;
        }

        public void setLength(long length) {
            this.length = length;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    }

如果使用 RestTemplate 调用远程接口需要添加请求头,示例如下:

// 获取第三方的authorization
String auth= OAuthContentHelper.getAuthorizationHeader();
HttpHeaders requestHeader=new HttpHeaders();
// 将获取到的authorization添加到请求头
requestHeader.add(AuthConstants.AUTHORIZATION_HEADER,auth);
// 构建请求实体
HttpEntity<Object> requestEntity=new HttpEntity(requestParam,requestHeaders);
// 使用restTemplate调用第三方接口
restTemplate.exchage(url,HttpMethod.POST,requestEntity,responseClass);
方式二:Spring Cloud Feign组件 + MultiValueMap + CommonInputStreamResource
  • feign 接口
@Component
@FeignClient(name = "common", url = "${url}", qualifier = "commonFeignClient",fallback = commonFallBack.class)
public interface CommonFeignClient {    
    /**
     * 附件上传
     */
    @PostMapping(value = "/xxx/uploadAttach",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String attachFileUpload(MultiValueMap<String, Object> multiValueMap);
}
  • 请求部分
@PostMapping("/uploadAttach")
public void uploadAttach(){
    try {
        File file=new File("D:/1.png");
        FileInputStream fileInputStream=new FileInputStream(file); 
        CommonInputStreamResource commonInputStreamResource = null;
        try {
            commonInputStreamResource = new CommonInputStreamResource(fileInputStream,fileInputStream.available(),file.getName());
        } catch (Exception e) {
            log.error("文件输入流转换错误:",e);
        } 
        MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<String, Object>();
        requestBody.add("tableName", tableName);
        requestBody.add("tableCode", tableCode);
        requestBody.add("configCode", configCode);
        requestBody.add("tableColumn", tableColumn);
        requestBody.add("file",commonInputStreamResource);
        String returnInfo = commonFeignClient.attachFileUpload(requestBody);
        JSONObject responseValue = JSONObject.parseObject(returnInfo);
        log.info("---->响应值为:" + responseValue);
    }catch (Exception e){
        log.error("异常:",e);
    }
}

class CommonInputStreamResource extends InputStreamResource {
        private long length;
        private String fileName;
        public CommonInputStreamResource(InputStream inputStream, long length, String fileName) {
            super(inputStream);
            this.length = length;
            this.fileName = fileName;
        }

        /**
         * 覆写父类方法
         * 如果不重写这个方法,并且文件有一定大小,那么服务端会出现异常
         * {@code The multi-part request contained parameter data (excluding uploaded files) that exceeded}
         */
        @Override
        public String getFilename() {
            return fileName;
        }

        /**
         * 覆写父类 contentLength 方法
         * 因为 {@link org.springframework.core.io.AbstractResource#contentLength()}方法会重新读取一遍文件,
         * 而上传文件时,restTemplate 会通过这个方法获取大小。然后当真正需要读取内容的时候,发现已经读完,会报如下错误。
         */
        @Override
        public long contentLength() {
            long estimate = length;
            return estimate == 0 ? 1 : estimate;
        }

        public void setLength(long length) {
            this.length = length;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }
    }
方式三:传统方式
	/**
     * post请求
     * @param url 请求url
     * @param params 普通参数
     * @param file 上传的文件
     * @return
     */
    public static String doPost(String url, Map<String, String> params, File file) throws Exception {
        if (org.apache.commons.lang3.StringUtils.isBlank(url)) {
            return null;
        }
        String resutString;
        HttpClient httpClient = HttpClients.createDefault();
        Charset charset = Charset.forName("UTF-8");//设置编码
        HttpPost httpPost = new HttpPost(url);
        try {
            log.info("finally request url:" + url);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addPart("file", new FileBody(file));
            // 普通字段,指定编码
            for (Map.Entry<String, String> param : params.entrySet()) {
                builder.addPart(param.getKey(), new StringBody(param.getValue(), ContentType.APPLICATION_JSON));// 普通字段,指定编码
            }
            httpPost.setEntity(builder.build());

            HttpResponse httpResponse = httpClient.execute(httpPost);
            /* 读取返回数据 */
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resutString = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
            } else {
                throw new Exception("发送失败:" + httpResponse.getStatusLine().getStatusCode() + " url :" + url);
            }
        } catch (Exception e) {
            throw e;
        }
        return 	resutString;
    }

	public Object uploadAttach(String tableName, String tableCode, String configCode, String tableColumn, File img) {
		try{
			String uploadAttach = "http://xxx/uploadAttach";
			Map<String, String> postParams = new HashMap<>();
	        postParams.put("tableName", tableName);
	        postParams.put("tableCode", tableCode);
	        postParams.put("configCode", configCode);
	        postParams.put("tableColumn", tableColumn);
	
	        log.info("-->请求地址:{},请求参数:{}", uploadAttach, postParams);
	        responseValue = HttpClientUtil.doPost(uploadAttach, postParams, img);
        } catch (Exception e) {
            log.error("上传失败",e);
        }
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值