前言
今天有个需求要跨服务调用一个导出excel的接口,两个服务都在同一注册中心上,所以使用Feign调用较为方便,下面记录一下
Feign调用
Feign调用导出接口的方法的出参不是和提供端的方法出入参一样就可以了,一般我们的导出接口都是无返回,直接将内容输出到response中,所以我们调用导出接口的feignt方法需要使用feign提供的Response来接收响应,如下
Feign方法:
import feign.Response;
/**
* 使用Feign调用导出接口
**/
@RequestMapping(value = "/xxxx", method = RequestMethod.POST,consumes = "application/json;charset=UTF-8")
Response exportOrderList(HttpRequest<JSONObject> request);
Feign端controller方法:
@PostMapping(value = "/exportOrderList")
@ResponseBody
public void exportOrderGatherVoList1(@RequestBody HttpRequest<JSONObject> request, HttpServletResponse response) throws Exception {
//调用feign方法,获取响应
Response resp = orderService.exportOrderList(request);
String date = LocalDate.now().toString();
String fileName="订单列表-"+date;
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition",
"attachment;filename*=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
Response.Body body = resp.body();
//将响应转为InputStream输入流
try (InputStream inputStream = body.asInputStream();
OutputStream outputStream = response.getOutputStream()) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024*5];
int n = 0;
while (-1 != (n = inputStream.read(buffer))) {
output.write(buffer, 0, n);
}
//获取输入流的长度
byte[] b = output.toByteArray();
//将输入流的数据读取到字节数组b中
inputStream.read(b);
//将字节数组b中的数据写到响应输出流中
outputStream.write(b);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("IO流异常", e);
}
}
上面为了方便把处理过程写在了controller层,在实际开发中应该放到业务处理层,下面是我拆分的方法
//获取InputStream输出流的byte字节数组
public static byte[] getByteArrayForInputStream (InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024*5];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
return output.toByteArray();
}
//导出方法
public static void export(Response resp,HttpServletResponse response,String fileName) throws Exception {
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition",
"attachment;filename*=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
Response.Body body = resp.body();
try (InputStream inputStream = body.asInputStream();
OutputStream outputStream = response.getOutputStream()) {
byte[] b = getByteArrayForInputStream (inputStream);
inputStream.read(b);
outputStream.write(b);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
throw new Exception("IO流异常", e);
}
}
抽出两个方法后,我们的controller就可以简化成以下代码
@PostMapping(value = "/exportOrderList")
@ResponseBody
public void exportOrderGatherVoList1(@RequestBody @Validated HttpRequest<JSONObject> request, HttpServletResponse response) throws Exception {
Response resp = orderService.exportOrderList(request);
FeignUtil.export(resp,response,"列表导出");
}
流程
Feign调用其他服务的导出服务,主要流程是通过Feign的Response来接收提供端导出接口的响应,然后通过resp.body()获取响应体,将响应体通过asInputStream方法转为InputStream 输入流,最主要的过程就是将输入流的内容写入到Feign客户端的response输出流中即可。