-
背景介绍
新项目开发,需要将老项目的历史数据迁移过来,出于种种原因,最终决定不真正迁移老项目的附件,而是在新项目中调用老项目的接口下载附件、查看附件。 -
分析
新老项目的服务端都是基于SpringMvc的java web项目,因此考虑在新项目的服务端使用RestTemplate去调用老项目的下载接口,获取到附件的byte[]
这个过程中主要考虑两个问题:
1.需要解决访问老项目下载接口的权限问题
2.需要了解老项目下载接口返回的数据格式,以便新项目接收数据后进行处理 -
解决步骤
针对问题1有两个解决方法:
1.在老项目中放开下载接口的权限验证,比如在过滤器中将下载接口URL设置为免验证,此方法不安全
2.在老项目中提供外部系统访问下载接口的专用用户,在新项目中首先使用此专用用户通过权限验证(比如登录),然后再访问下载接口 -
下面提供方法2的具体实现代码:
1.首先配置RestTemplate到Spring容器中,可以指定远程调用的超时时间
<!-- 配置RestTemplate -->
<!--Http client Factory-->
<bean id="httpClientFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="connectTimeout" value="${restTemplate.connectTimeout}"/>
<property name="readTimeout" value="${restTemplate.readTimeout}"/>
</bean>
<!--RestTemplate-->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="httpClientFactory"/>
</bean>
2.使用RestTemplate先登录获取cookie再请求下载接口
//1.先登录,获取权限验证后的cookie
String loginUrl = "http://localhost:8888/plat/login";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> loginMap = new LinkedMultiValueMap<>();//POST方式传参
loginMap.add("username", "xxx");
loginMap.add("password", "xxx");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(loginMap, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(loginUrl, request, String.class);
String cookie = responseEntity.getHeaders().get("Set-Cookie").get(0);//拿到登录的cookie
//2.携带cookie再请求下载接口
List<String> cookies = new ArrayList<>();
cookies.add(cookie);
HttpHeaders downHeaders = new HttpHeaders();
downHeaders.put(HttpHeaders.COOKIE, cookies);//请求下载接口时携带cookie
HttpEntity<MultiValueMap<String, Integer>> downRequest = new HttpEntity<>(null, downHeaders);//GET请求,这里即使把null改为map传参,服务端也获取不到数据
String url = "http://localhost:8888/plat/attach/download?id=" + 888;//GET请求,在url后拼接传参
ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.GET, downRequest, byte[].class);
byte[] data = exchange.getBody();//附件数据
3.老项目中下载接口返回值类型是void,通过OutputStream流输出数据,因此使用RestTemplate的exchange方法。如果老项目下载接口返回值类型是ResponseEntity,可能就不是调exchange方法了(本人未再继续测试验证,欢迎大家在评论区给出答案~~)
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
outputStream.write(data);
outputStream.flush();
} catch (IOException e) {
throw new RuntimeException("文件下载失败", e);
} finally {
IOUtils.close(outputStream);
}
ps:如果不需要header与传参,requestEntity可以传递null,没有问题。
//exchange方法源码
@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, method, requestCallback, responseExtractor, uriVariables);
}
//实际调用
ResponseEntity<byte[]> response = restTemplate.exchange(url, HttpMethod.GET, null, byte[].class);//传递null