With the release of Spring 4.2 version, Three new classes have been introduced to handle Requests Asynchronously of the Servlet Thread. Which are;
  1. ResponseBodyEmitter
  2. SseEmitter
  3. StreamingResponseBody
ResponseBodyEmitter enables to send DeferredResult with a compatible HttpMessageConverter. Results can be emitted from threads which are not necessarily the Servlet Request Thread of the Servlet Container.
 
SseEmitter is used to send Server Sent Events to the Client. Server Sent Events has a fixed format and the response type for the result will be text/event-stream.
 
StreamingResponseBody is used to send raw unformatted data such as bytes to the client asynchronously of the Servlet Thread.
 
ResponseBodyEmitter and SseEmitter has a method named complete to mark its completion and StreamingResponseBody will complete when there is no more data to send. 
 
All three options will be keeping alive a connection to the endpoint until the end of the request.
 
StreamingResponseBody is particularly useful for streaming large files such as Media Files as writing of the bytes to the Response's OutputStream will be done asynchronously. StreamingResponseBody has a writeTo(OutputStream os) call back method which needs to be overridden inorder to support streaming.
 
I wrote a small Spring Boot Application to showcase the StreamingResponseBody capabilities in terms of Streaming large files. The application source code can be found at www.github.com/shazin/itube. Below is a screen shot of the application.
In order to send the Video files streaming to the Projekktor player in the web page following code snippet is used.
  1. @RequestMapping(method = RequestMethod.GET, value = "/{video:.+}")
  2. public StreamingResponseBody stream(@PathVariable String video)
  3. throws FileNotFoundException {
  4. File videoFile = videos.get(video);
  5. final InputStream videoFileStream = new FileInputStream(videoFile);
  6. return (os) -> {
  7. readAndWrite(videoFileStream, os);
  8. };
  9. }

And a Custom Web Configuration to over ride default timeout behavior to no timeout and finally configuring an AsyncTaskExecutor

  1. @Configuration
  2. public static class WebConfig extends WebMvcConfigurerAdapter {
  3.  
  4. @Override
  5. public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
  6. configurer.setDefaultTimeout(-1);
  7. configurer.setTaskExecutor(asyncTaskExecutor());
  8. }
  9.  
  10. @Bean
  11. public AsyncTaskExecutor asyncTaskExecutor() {
  12. return new SimpleAsyncTaskExecutor("async");
  13. }
  14.  
  15. }

转载自:http://shazsterblog.blogspot.com/2016/02/asynchronous-streaming-request.html

笔者代码:

  1. @RequestMapping(value = "{uuid}.m3u8")
  2. public ResponseEntity<StreamingResponseBody> m3u8Generator(@PathVariable("uuid") String uuid){
  3.  
  4. String key = "media.".concat(uuid);
  5. Map<String, Object> cached = cacheService.getCacheMap(key);
  6. if(CollectionUtils.isEmpty(cached))
  7. {
  8. return new ResponseEntity(null, HttpStatus.OK);
  9. }
  10. String playlist = (String) cached.get("playlist");
  11. String[] lines = playlist.split("\n");
  12.  
  13. //人为在每个MPEG-2 transport stream文件前面加上一个地址前缀
  14. StringBuffer buffer = new StringBuffer();
  15.  
  16. StreamingResponseBody responseBody = new StreamingResponseBody() {
  17. @Override
  18. public void writeTo (OutputStream out) throws IOException {
  19. for(int i = 0; i < lines.length; i++)
  20. {
  21. String line = lines[i];
  22.  
  23. if(line.endsWith(".ts"))
  24. {
  25. buffer.append("/streaming/");
  26. buffer.append(uuid);
  27. buffer.append("/");
  28. buffer.append(line);
  29. }else {
  30. buffer.append(line);
  31. }
  32. buffer.append("\r\n");
  33. }
  34. out.write(buffer.toString().getBytes());
  35. out.flush();
  36. }
  37. };
  38.  
  39. return new ResponseEntity(responseBody, HttpStatus.OK);
  40. }

其他类似功能代码:

  1. //https://www.baeldung.com/spring-mvc-sse-streams
  2. //https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/streaming-response-body.html
  3. //@GetMapping("/{fileName:[0-9A-z]+}")
  4. @GetMapping("/streaming2/{uuid}/{fileName}")
  5. //https://stackoverflow.com/questions/47868352/how-to-stream-large-http-response-in-spring
  6. @ResponseBody
  7. public ResponseEntity<InputStreamResource> get_File2(
  8. @PathVariable String uuid,
  9. @PathVariable String fileName) throws IOException {
  10.  
  11. String dbFile = fileRepository.findByUUID(uuid,fileName);
  12.  
  13. dbFile=String.format("E:/hls/test/%s",fileName);
  14.  
  15. if (dbFile.equals(null)) {
  16. return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  17. }
  18.  
  19. Resource file = storageService.loadAsResource(dbFile);
  20.  
  21. long len = 0;
  22. try {
  23. len = file.contentLength();
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27.  
  28. MediaType mediaType = MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(file.getFile()));
  29.  
  30. // if (filename.toLowerCase().endsWith("mp4") || filename.toLowerCase().endsWith("mp3") ||
  31. // filename.toLowerCase().endsWith("3gp") || filename.toLowerCase().endsWith("mpeg") ||
  32. // filename.toLowerCase().endsWith("mpeg4"))
  33. if(fileName.toLowerCase().endsWith("ts")) {
  34. mediaType = MediaType.APPLICATION_OCTET_STREAM;
  35. }
  36.  
  37. InputStreamResource resource = new InputStreamResource(new FileInputStream(file.getFile()));
  38.  
  39. return ResponseEntity.ok()
  40. .contentType(mediaType)
  41. .contentLength(len)
  42. .header(HttpHeaders.ACCEPT_RANGES, "bytes")
  43. .body(resource);
  44. }
  1. @RequestMapping("/111111")
  2. public StreamingResponseBody handleRequest (HttpServletRequest request) {
  3. return outputStream -> {
  4. Map<String, BigInteger> map = new HashMap<>();
  5. map.put("one", BigInteger.ONE);
  6. map.put("ten", BigInteger.TEN);
  7. try(ObjectOutputStream oos = new ObjectOutputStream(outputStream)){
  8. oos.writeObject(map);
  9. }
  10. };
  11. }
  1. @GetMapping("/media/{uuid}/{fileName}")
  2. @ResponseBody
  3. public ResponseEntity<ByteArrayResource> getStream(@PathVariable String uuid,
  4. @PathVariable String fileName) throws IOException {
  5. String key = "media.".concat(uuid);
  6. String encoded = cacheService.getCachedHashValue(key, fileName, String.class);
  7. byte[] bytes = Base64.getDecoder().decode(encoded);
  8.  
  9. long len = bytes.length;
  10.  
  11. //InputStreamResource resource = new InputStreamResource(new FileInputStream(file.getFile()));
  12. ByteArrayResource resource = new ByteArrayResource(bytes);
  13.  
  14. return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM).contentLength(len).header(HttpHeaders.ACCEPT_RANGES, "bytes").body(resource);
  15. // return ResponseEntity.ok()
  16. // .contentType(MediaType.APPLICATION_OCTET_STREAM)
  17. // .contentLength(len)
  18. // .header(HttpHeaders.ACCEPT_RANGES, "bytes")
  19. // .body(resource);
  20. }

Asynchronous Streaming Request Processing in Spring MVC 4.2 + Spring Boot(SpringBoot中处理异步流请求 SpringMvc4.2以上)的更多相关文章

  1. 2017.3.31 spring mvc教程(六)转发、重定向、ajax请求

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  2. Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)

    当我们在非Controller类中应用service的方法是会报空指针,如图: 这是因为Spring MVC普通类或工具类中调用service报空null的解决办法(调用service报java.la ...

  3. Spring MVC 零配置 / Spring MVC JavaConfig

    1. Spring MVC的核心就是DispatcherServlet类,Spring MVC处理请求的流程如下图所示: 2. Spring MVC中典型的上下文层次 当我们初始化一个Dispatch ...

  4. spring mvc注解和spring boot注解

    1 spring mvc和spring boot之间的关系 spring boot包含spring mvc.所以,spring mvc的注解在spring boot总都是可以用的吗? spring b ...

  5. java之spring mvc之初始spring mvc

    1. mvc : mvc框架是处理 http请求和响应的框架 2. mvc 做的事情有哪些: 将 url 映射到一个java的处理方法上 将表单数据提交到 java 类中 将后台 java 类处理的结 ...

  6. Spring MVC mapping[From Spring MVC Beginner's Guide]

    In a Spring MVC application, the URL can logically be divided into five parts (see the following fig ...

  7. Spring MVC 学习笔记 spring mvc Schema-based configuration

    Spring mvc 目前支持5个tag,分别是 mvc:annotation-driven,mvc:interceptors,mvc:view-controller, mvc:resources和m ...

  8. Spring MVC(十六)--Spring MVC国际化实例

    上一篇文章总结了一下Spring MVC中实现国际化所需的配置,本文继上一文举一个完整的例子,我选择用XML的方式.我的场景是这样的: 访问一个页面时,这个页面有个表格,对表头中的列名实现国际化. 第 ...

  9. 玩转spring mvc(四)---在spring MVC中整合JPA

    关于在Spring MVC中整合JPA是在我的上一篇关于spring mvc基本配置基础上进行的,所以大家先参考一下我的上一篇文章:http://blog.csdn.net/u012116457/ar ...

随机推荐

  1. thinkpadT470P安装问题

    [问题描述]: 最近在将Thinkpad E430c的ubuntu系统重装成windows 7的过程中,出现了装好win7系统后,开机自动进入boot menu界面的问题,而且不论你选择从光驱还是硬盘 ...

  2. Kubernetes 学习22 kubernetes容器资源需求资源限制及HeapSter(翻车章节)

    一.概述 1.接下来介绍在k8s上运行pod对象时我们如何去监控我们系统级的资源指标以及业务级别的资源指标.数据如何获取和监控.在此之前先介绍一下Pod对象的资源请求和资源限制.即容器的资源需求和资源 ...

  3. sql server vs mysql

    1.中文: my.ini [mysqld] character-set-server=utf8 character-set-client=utf8 data\testdb\db.opt default ...

  4. noi.ac #30 思维

    \(des\) 给定升序数组 \(A, B\) 对于任意两个集合 \(a, b\) 分别是 \(A, B\) 的子集,总价值为较小的集合的和, 总代价为 \((|a| + |b|) \times w\ ...

  5. Pytorch在colab和kaggle中使用TensorBoard/TensorboardX可视化

    在colab和kaggle内核的Jupyter notebook中如何可视化深度学习模型的参数对于我们分析模型具有很大的意义,相比tensorflow, pytorch缺乏一些的可视化生态包,但是幸好 ...

  6. Angular动态组件

    一.主页面: app.component.html: <button (click)="load();">动态</button> 2<div #dom ...

  7. github上项目的目录结构说明

    build 构建脚本 dist 编译出来的发布版 docs 文档 examples 示例文件 src 源码 test 测试脚本 .babelrc Babel 交叉编译的配置 .eslintrc ESL ...

  8. 金蝶kis 16.0专业版-破解01

    Kingdee.KIS.MobAppSer>MainViewModel 经过反混淆后,找到导入LIcense文件后的验证函数. 下面仅需进行逆向生成即可,为什么一定要进行生成lic文件方式进行破 ...

  9. Java 操作Redis封装RedisTemplate工具类

    package com.example.redisdistlock.util; import org.springframework.beans.factory.annotation.Autowire ...

  10. fluent-动网格-动态层

    模型算例来源:http://blog.sina.com.cn/s/blog_599d8faa0100w4uj.html ​原视频下载地址:http://yunpan.cn/cujM2FxLuGdLK ...