Spring RestTemplate 下载文件

原创
2016/05/28 15:33
阅读数 1.9W

1、思考

面向服务编程中,我们经常需要通过HttpClient请求服务器获取对应的数据服务,如果你使用RestTemplate,肯定会在会他的 上传、下载,因为一般的Json数据请求都比较简单。下面就分享一下如何使用 RestTemplate 进行文件下载。

2、组件封装

package com.hnust.common.controller;

import com.hnust.common.rest.client.RestClient;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.support.HttpRequestWrapper;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Heweipo on 2016/5/26.
 *
 * 资源下载通用控制器
 */
@RestController
public class DownloadController extends BaseController {


    /**
     * 发送/获取 服务端数据
     * 注意 URL 、HttpMethod 都与当前请求保持一致
     *
     * @return 返回结果(响应体)
     */
    protected ResponseEntity<byte[]> export() {
        return export(null, null);
    }

    /**
     * 主要是 GET、DELETE 请求不能发在body体
     *
     * @param uri 相对路径
     * @return 返回结果(响应体)
     */
    protected ResponseEntity<byte[]> export(String uri) {
        return export(uri, null);
    }

    /**
     * 添加参数
     *
     * @param params 请求body体
     * @return 返回结果(响应体)
     */
    protected ResponseEntity<byte[]> export(Map<String, Object> params) {
        return export(null, params);
    }

    /**
     * 下载通用方法
     *
     * @param params 请求参数
     * @return 下载流
     */
    protected ResponseEntity<byte[]> export(String uri, Map<String, Object> params) {
        // RestClient.getServiceServerUrl() 服务器的URL : http://localhost:8080/service
        String url = RestClient.getServiceServerUrl() + request.getRequestURI();
        if (!StringUtils.isEmpty(uri)) {
            url = RestClient.getServiceServerUrl() + uri;
        }

        HttpMethod httpMethod = getMethod();
        if(params == null) params = new HashMap<>();
        url = processParams(url,httpMethod,params);

        return export(url, httpMethod, params);
    }



    /**
     * 下载通用方法
     * @param url 地址
     * @param method 方法
     * @param params 参数
     * @return 下载流
     */
    protected ResponseEntity<byte[]> export(String url, HttpMethod method, Map<String, Object> params) {
        ClientHttpRequestInterceptor interceptor = new DownloadInterceptor();
        List<ClientHttpRequestInterceptor> list = new ArrayList<>();
        list.add(interceptor);

        restTemplate.setInterceptors(list);

        // 请求头
        HttpHeaders headers = new HttpHeaders();
        ObjectMapper mapper = new ObjectMapper();
        String str = null;
        try {
            if (params != null) {
                str = mapper.writeValueAsString(params);
            }
        } catch (JsonProcessingException e) { // 这个异常不处理
            e.printStackTrace();
        }

        // 发送请求
        HttpEntity<String> entity = new HttpEntity<>(str, headers);
        ResponseEntity<byte[]> obj = restTemplate.exchange(url, method, entity, byte[].class);

        return obj;

    }


    /**
     * Spring RestTemplate 下载组件
     */
    public static class DownloadInterceptor implements ClientHttpRequestInterceptor{

        /**
          * 媒体类型,给个默认值
         */
        private MediaType headerValue = MediaType.ALL;

        /**
         * 获取媒体类型
         * @return 媒体类型
         */
        public MediaType getHeaderValue() {
            return headerValue;
        }

        /**
         * 设置媒体类型
         * @param headerValue 媒体类型
         */
        public void setHeaderValue(MediaType headerValue) {
            this.headerValue = headerValue;
        }


     /**
      * Intercept the given request, and return a response. The given {@link ClientHttpRequestExecution} allows
      * the interceptor to pass on the request and response to the next entity in the chain.
      * <p>
      * <p>A typical implementation of this method would follow the following pattern:
      * <ol>
      * <li>Examine the {@linkplain HttpRequest request} and body</li>
      * <li>Optionally {@linkplain HttpRequestWrapper wrap} the request to filter HTTP attributes.</li>
      * <li>Optionally modify the body of the request.</li>
      * <li><strong>Either</strong>
      * <ul>
      * <li>execute the request using {@link ClientHttpRequestExecution#execute(HttpRequest, byte[])},</li>
      * <strong>or</strong>
      * <li>do not execute the request to block the execution altogether.</li>
      * </ul>
      * <li>Optionally wrap the response to filter HTTP attributes.</li>
      * </ol>
      *
      * @param request   the request, containing method, URI, and headers
      * @param body      the body of the request
      * @param execution the request execution
      * @return the response
      * @throws IOException in case of I/O errors
      */
     @Override
     public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
         HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
         List<MediaType> list = new ArrayList<>();
         list.add(headerValue);
         requestWrapper.getHeaders().setAccept(list);
         return execution.execute(requestWrapper, body);
     }
 }



}

3、组件调用

package com.hnust.workbench.common.questionbank.paper.controller;

import com.hnust.common.controller.DownloadController;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * 
 * Created by Heweipo on 2016/2/26.
 */
@RestController
public class ClientController extends DownloadController {

    /**
     * 下载
     * 
     */
    @RequestMapping(value = "/download", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getBatchAnswer(){
       return export();
    }
}

4、注意

1)RestTemplate 在这里只是做了一下转发,因为真正的文件是从另一个服务URL那里获取

2)RestTemplate 还有就是上传以及文本数据获取,项目中使用一般都会进行封装,方便调用

展开阅读全文
打赏
0
12 收藏
分享
加载中
如果文件比较大, 使用ResponseEntity<byte[]>会造成内存溢出吧?
2017/04/24 11:22
回复
举报
learn_more博主

引用来自“岳法祥”的评论

RestClient是啥呀?😜
项目中就是一个常量类,RestClient.getServiceServerUrl() 就是这个值 http://localhost:8080/service
2017/02/17 19:19
回复
举报
RestClient是啥呀?😜
2017/02/15 11:37
回复
举报
learn_more博主

引用来自“_白羊”的评论

资料给万完整了啊!不然都跑不起来啊!
你说的是BaseController吧?这个类就一个声明式的类,里面的方法也是非常简单,你可以把这个类去掉不要
2016/10/20 11:21
回复
举报
资料给万完整了啊!不然都跑不起来啊!
2016/10/19 10:13
回复
举报
更多评论
打赏
5 评论
12 收藏
0
分享
返回顶部
顶部