jfinal-4.9 自定义render,返回音频文件

[产生背景]

刚一开使用renderFile(file);前端使用audio标签播放,播放时后台总是出现异常

前台audio标签

<audio id="audioPlay" src="/litongjava-windows-tts/tts?text=很多文本"></audio>

后台异常

九月 06, 2020 10:16:50 上午 com.jfinal.core.ActionHandler error
严重: /tts?text=省略内容
com.jfinal.render.RenderException: java.io.IOException: 远程主机强迫关闭了一个现有的连接。
at com.jfinal.render.FileRender.rangeRender(FileRender.java:244)
at com.jfinal.render.FileRender.render(FileRender.java:123)
at com.jfinal.core.ActionHandler.handle(ActionHandler.java:111)
at com.litong.jfinal.handler.ActionSuffixHandler.handle(ActionSuffixHandler.java:28)
at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:90)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

请求返回的状态码,并且点击一次播放按钮,播放了3次

image.png

异常的具体原因我没有找到,但是我认为和renderFile默认弹出下载框有关系

[解决思路]

自定义的一个render,读取文件流,输出到response

controller调用

render(new InputStreamRender(file));

render代码

package com.litong.jfinal.render;
import java.io.File;
import java.io.IOException;
import com.jfinal.render.Render;
import com.litong.utils.io.StreamUtils;
/**
 * @author bill robot
 * @date 2020年9月6日_上午9:56:51 
 * @version 1.0 
 * @desc
 */
public class InputStreamRender extends Render {
  private File srcfile;
  public InputStreamRender(File srcfile) {
    this.srcfile = srcfile;
  }
  @Override
  public void render() {
    if (srcfile != null) {
      try {
        StreamUtils.copy(srcfile, response.getOutputStream());
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}

工具类

package com.litong.utils.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
 * @author bill robot
 * @date 2020年8月22日_上午1:08:25 
 * @version 1.0 
 * @desc
 */
public class StreamUtils {
  public static final int BUFFER_SIZE = 4096;
  public static int copy(InputStream in, OutputStream out) throws IOException{
    int byteCount = 0;
    byte[] buffer = new byte[BUFFER_SIZE];
    int bytesRead = -1;
    while ((bytesRead = in.read(buffer)) != -1) {
      out.write(buffer, 0, bytesRead);
      byteCount += bytesRead;
    }
    return byteCount;
  }
  public static void copy(File file, OutputStream outputStream) {
    FileInputStream fileInputStream=null;
    try {
      fileInputStream = new FileInputStream(file);
      copy(fileInputStream, outputStream);
    } catch (IOException e) {
      e.printStackTrace();
    }finally {
      IOUtils.closeQuietly(fileInputStream);
    }
  }
}

再次测试,可以返回200

image.png

评论区

JFinal

2020-09-06 12:54

这个分享不错,开发可播放背景音乐的站点很有用,点赞 + 收藏

zzutligang

2020-09-07 08:55

还需要加入支持用户拖动进度条的功能,后台支持rang参数。

李通

2020-09-07 10:13

@zzutligang 增加audio标签增加control属性即可