之前一直也没用Feign做过文件下载,文件上传倒是做过,以往都是只返回文件在服务器上地址,再由服务消费者或者客户端去下载,但这两天在做将activiti做成服务,而做过activiti的都知道,流程模型的bpmn.xml文件和图片都是以BLOB存在数据库,所以必须由服务提供者将文件传给客户端。在网上查了一番,发现几乎没有feign做文件下载的博客,想想也是,一般也不会有人这样做。尝试了使用Inputstream以及feign提供的Response类,都没有成功,后来按照springmvc做下载的方式,使用了spring提供的ResponseEntity,居然就可以了。
服务提供的代码:
@GetMapping(value = "/api/activiti/process/resource/read/{resType}/{id}")
public ResponseEntity<byte[]> resourceRead(@PathVariable("resType") String resType, @PathVariable("id") String id) {
ResponseEntity<byte[]> entity = null;
HttpHeaders headers = new HttpHeaders();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
String resourceName = "";
if (resType.equals("image")) {
resourceName = processDefinition.getDiagramResourceName();
} else if (resType.equals("xml")) {
resourceName = processDefinition.getResourceName();
}
try {
InputStream resourceAsStream = processService.resourceRead(id,resType);
byte[] b = new byte[resourceAsStream.available()];
resourceAsStream.read(b);
headers.add("Content-Disposition", "attachment;filename="+resourceName);
HttpStatus status = HttpStatus.OK;
resourceAsStream.close();
entity = new ResponseEntity<byte[]>(b, headers, status);
} catch (Exception e) {
e.printStackTrace();
}
return entity;
}
中间关于activiti的代码可以忽略,主要是try-catch中的代码,在拿到文件的输入流(InputStream)之后,将文件写入到定义的byte[]数组中,再设置httpheader,设置为带有附件,最后返回ResponseEntity<byte[]>对象,客户端拿到这个对象后直接返回即可,就可以下载activiti模型的xml或png文件。
我觉得使用feign实现文件下载的场景并不常见,尤其万一要是文件较大,很容易引起feign超时的问题,所以对于这种activiti的情况,使用倒也没啥问题,但其他情况还是应该返回给消费者或客户端文件的URL比较好,由专门的文件服务器、CDN来做。