当前位置:   article > 正文

B机器获取A机器的流对象_body.asinputstream

body.asinputstream

需求是这样的:

公司的图片服务器在 OSS 上,前端拿到地址就可以访问 图片文件

前端需要将已经发送给OSs的图片,重新发送给第三方系统,前端只可以传图片路径,后台需要这个路径从OSs 获取文件流(InputStream 对象),然后 直接将这个流对象 返给ftp 服务器(没错第三方系统用的就是 ftp 协议)

但是实际检验发现行不通:

调用A系统 实际返回结果:

A系统代码如下:

原因:

InputStream  这个对象很特殊,不像 Student 这些实体类有自己的属性,计算机系统之间交互的时候可以通过序列号,另一台机器就可以拿到属性值一样的对象,而 InputStream  对象没有自己的属性,他属于流对象 ,另一台机器要拿到相同 的流对象,不可以直接返回 InputStream  接口子类的实例,而是要 把流里的字节内容 通过 输出流 传给另一台机器。

  案例:

搭建两个简单的springboot 项目

服务提供者 端口是 8091

服务消费者端口是 8092

请求方式 用 Spring 提供的 

RestTemplate 发送请求

注意:

RestTemplate springboot 不会自动装配,需要手动装配

服务消费者启动类:

  1. @SpringBootApplication
  2. //@MapperScan({"com.example.demo.mapper","com.example.demo.mapper"})
  3. // @MapperScan 代替 @Mapper的
  4. @MapperScan("com.example.demo.mapper")
  5. // 开启缓存
  6. @EnableCaching
  7. public class DemoApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(DemoApplication.class, args);
  10. }
  11. @Bean
  12. RestTemplate restTemplate(){
  13. return new RestTemplate();
  14. }
  15. }

先看效果图: 

需求:

向 系统B 传入 文件 path ,系统B 通过 RestTemlate 向系统A发送请求,系统A根据 path 得到 InputStream 流(这个流在系统A里,不能直接返给 B,这样B拿不到 流),系统A将 InputStream的内容写入到 输出流里,并刷给 系统B,系统B 就这样得到 系统A的输出流(对于B 就是输入流,B读取A的输出流)

① path 为图片:

E:\\test1\\doc\\郑宇_20200908162125_退款确认书_032CE223-AB92-4F68-A1A6-91CAF06F7051.JPG

返回结果:

② path 为PDF 文件

不能预览,需要下载查看

代码如下:

服务提供者:

  1. /**
  2. * @Description: 单文件上传
  3. * @Param: List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("files");
  4. * @return:
  5. * @Author: guoyiguang
  6. * @Date:
  7. */
  8. @PostMapping("/ftpFileUpload/upload2")
  9. @ResponseBody
  10. public void upload2(HttpServletRequest request,HttpServletResponse response){
  11. // 获取请求消费者参数
  12. String path = request.getParameter("path");
  13. FileInputStream inputStream = null;
  14. OutputStream output = null;
  15. if (StringUtils.isEmpty(path)){
  16. System.out.println("path is empty");
  17. return;
  18. }
  19. //服务器端
  20. try {
  21. //注意: 得到 inputStream 后,不能直接 return inputStream , 消费者是拿不到的 InputStream 这个对象的
  22. //InputStream inputStream = files.get(0).getInputStream();
  23. // FileInputStream inputStream = new FileInputStream("E:\\test1\\doc\\郑宇_20200908162125_退款确认书_032CE223-AB92-4F68-A1A6-91CAF06F7051.JPG");
  24. // inputStream = new FileInputStream("E:\\test1\\pdf\\LeetCode 101 - A LeetCode Grinding Guide (C Version).PDF");
  25. inputStream = new FileInputStream(path);
  26. // 将输入流转化为 输出流 传给消费者,供消费者消费
  27. output = response.getOutputStream();
  28. byte[] bts = new byte[8192];
  29. int len = -1;
  30. while((len=inputStream.read(bts))!=-1){
  31. output.write(bts,0,len);
  32. }
  33. response.setHeader("topic","stream 测试");
  34. // 返给客户端
  35. output.flush();
  36. } catch (IOException e) {
  37. System.out.println("io exception");
  38. }finally {
  39. if(null != inputStream){
  40. try {
  41. inputStream.close();
  42. } catch (IOException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. //
  47. if(null != output){
  48. try {
  49. output.close();
  50. } catch (IOException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. }
  55. }

服务消费者:

  1. package com.example.demo.controller;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.core.io.Resource;
  5. import org.springframework.http.*;
  6. import org.springframework.stereotype.Controller;
  7. import org.springframework.util.LinkedMultiValueMap;
  8. import org.springframework.util.MultiValueMap;
  9. import org.springframework.web.bind.annotation.PostMapping;
  10. import org.springframework.web.client.RestTemplate;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.IOException;
  14. import java.io.InputStream;
  15. import java.io.OutputStream;
  16. /**
  17. * @program: springboot_01
  18. * @description: 文件上传工具类 ftpFileUpload/upload
  19. * @author: guoyiguang
  20. * @create: 2021-06-25 11:50
  21. **/
  22. @Controller
  23. @Slf4j
  24. public class FtpFileUploadController {
  25. @Autowired
  26. private RestTemplate restTemplate;
  27. /**
  28. * @Description: 单文件上传
  29. * @Param: List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("files");
  30. * @return:
  31. * @Author: guoyiguang
  32. * @Date:
  33. */
  34. @PostMapping("/ftpFileUpload/upload")
  35. public void upload(HttpServletRequest request,HttpServletResponse response){
  36. String path = request.getParameter("path");
  37. String robotUrl = "http://192.168.43.161:8091/ftpFileUpload/upload2" ;
  38. HttpHeaders headers = new HttpHeaders();
  39. headers.setContentType(MediaType.APPLICATION_JSON);
  40. MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
  41. requestEntity.add("path", path);
  42. // 调用B 系统 获取输入流(获取流对象,要用 org.springframework.core.io.Resource 对象接收)
  43. ResponseEntity<Resource> entity = restTemplate.postForEntity(robotUrl, requestEntity, Resource.class);
  44. InputStream inputStream = null ;
  45. OutputStream output = null;
  46. try {
  47. inputStream = entity.getBody().getInputStream();
  48. int count = 0;
  49. // 能否使用取决于实现了InputStream这个抽象类的具体子类中有没有实现available这个方法。如果实现了那么就可以取得大小,如果没有实现那么就获取不到。例如FileInputStream就实现了available方法,那么就可以用new byte[in.available()];这种方式。但是,网络编程的时候Socket中取到的InputStream,就没有实现这个方法,那么就不可以使用这种方式创建数组
  50. // 在进行网络操作时往往出错,因为你调用available()方法时,对发发送的数据可能还没有到达,你得到的count0
  51. while (count == 0) {
  52. count = inputStream .available();
  53. }
  54. output = response.getOutputStream();
  55. byte[] bts = new byte[8192];
  56. int len = -1;
  57. while((len=inputStream.read(bts))!=-1){
  58. output.write(bts,0,len);
  59. }
  60. response.setHeader("topic2","stream 测试2");
  61. // 返给客户端输出流
  62. output.flush();
  63. } catch (IOException e) {
  64. e.printStackTrace();
  65. }finally {
  66. if(null != inputStream){
  67. try {
  68. inputStream.close();
  69. } catch (IOException e) {
  70. e.printStackTrace();
  71. }
  72. }
  73. if(null != output){
  74. try {
  75. output.close();
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. }
  81. }
  82. }

如果是在StringCloud中,各系统之间是通过 Feign 接口调用的,那么怎么实现呢?

Feign 接口返回流:

服务提供者 是输出流数据 给服务消费者,用输出流

服务消费者是要 读取流,用 输入流

代码如下:

参考链接:https://www.debug8.com/java/t_22044.html

服务提供者:

  1. @GetMapping("getPictureByPath")
  2. public void queryJobInfoLogDetail(@RequestParam String path, HttpServletResponse response) {
  3. File file = new File(path);
  4. InputStream fileInputStream = new FileInputStream(file);
  5. // 说明:如果是 Linux 上,则换成 Linux 上所在的目录
  6. // 等同于 FileInputStream inputStream = new FileInputStream("E:\\test1\\do\\郑_20200908162125_退款确认书_032CE223-AB92-4F68-A1A6-91CAF06F7051.JPG");
  7. OutputStream outStream;
  8. try {
  9. outStream = response.getOutputStream();
  10. byte[] bytes = new byte[1024];
  11. int len = 0;
  12. while ((len = inputStream.read(bytes)) != -1) {
  13. outStream.write(bytes, 0, len);
  14. }
  15. fileInputStream.close();
  16. outStream.close();
  17. outStream.flush();
  18. } catch (IOException e) {
  19. log.error("exception", e);
  20. }
  21. }

消费端:

feign

  1. @GetMapping(value = "/getPictureByPath", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
  2. feign.Response getPictureByPath(@PathVariable("path") String path);

服务消费端:

  1. @GetMapping("/getPictureByPath")
  2. public void getPictureByPath(@RequestParam String path, HttpServletResponse servletResponse) {
  3. // 消费端 调用 feign 接口
  4. Response response = apiServices.getPictureByPath(path);
  5. Response.Body body = response.body();
  6. InputStream fileInputStream = null;
  7. OutputStream outStream;
  8. try {
  9. fileInputStream = body.asInputStream();
  10. outStream = servletResponse.getOutputStream();
  11. byte[] bytes = new byte[1024];
  12. int len = 0;
  13. while ((len = fileInputStream.read(bytes)) != -1) {
  14. outStream.write(bytes, 0, len);
  15. }
  16. fileInputStream.close();
  17. outStream.close();
  18. outStream.flush();
  19. } catch (Exception e) {
  20. }finally{
  21. // 关闭流
  22. }
  23. }

用最原始的方法读取流对象: HttpURLConnection 

  1. static void update() throws IOException {
  2. URL url = new URL("http://172.16.59.129:8000/update/test.so");
  3. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  4. if(conn.getResponseCode() == 200) {
  5. int totalLength = conn.getContentLength();
  6. BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
  7. byte[] buffer = new byte[512];
  8. int readLength = 0;
  9. int length = 0;
  10. while((length=in.read(buffer)) != -1) {
  11. readLength += length;
  12. //进度条
  13. System.out.println(((float)readLength) /((float)(totalLength)));
  14. }
  15. }
  16. }

方案二: 或者直接返回  字节数组

  1. private ByteArrayOutputStream memoryOutputStream;
  2. public byte[] getData()
  3. {
  4. if (memoryOutputStream != null)
  5. {
  6. return memoryOutputStream.toByteArray();
  7. }
  8. return null;
  9. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/147218
推荐阅读
相关标签
  

闽ICP备14008679号