如何在servlet中处理多个文件打开请求

时间:2013-10-11 05:19:27

标签: java servlets tomcat6

我正在使用servlet,用于开放文档,如doc,txt,pdf,ppt等。

我的代码段如下。

Documents document = db.getDocument(docCode);
 String contentType = document.getDocMimeType();
 byte[] docContentBytes = document.getDocContentBytes();  

 ServletOutputStream out = response.getOutputStream ();
 response.setHeader("X-UA-Compatible", "IE=8");
 response.setHeader("Content-disposition", "attachment;filename=\"Document\""); 
 response.setHeader("Pragma","private");
 response.setHeader("Cache-Control","must-revalidate, post-check=0, pre-check=0");
 response.setHeader("Content-Transfer-Encoding","binary");

 if(contentType!=null){
     response.setContentType(contentType);
 }else{
     response.setContentType("application/pdf");
 }

 BufferedInputStream bis = null;
 BufferedOutputStream bos = null;
 ByteArrayInputStream bais = null;

 if(docContentBytes != null) {
  try{
         bais = new ByteArrayInputStream(docContentBytes);
         bis = new BufferedInputStream(bais);


         bos = new BufferedOutputStream(out);
         byte[] buff = new byte[2048];
         int bytesRead;
         // Simple read/write loop.
         while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
         bos.write(buff, 0, bytesRead);
         }
 }catch(final MalformedURLException e) {
 System.out.println ( "MalformedURLException." );
 throw e;
 } catch(final IOException e) {
 System.out.println ( "IOException." );
 throw e;
 } finally {
     if (bais != null)
         bais.close();

         if (bis != null)
             bis.close();

         if (bos != null)
             bos.close();
 }
 } 

现在,当我尝试打开多个文档时,经过一段时间后,我将从tomcat服务器中收到管道错误。

我的DataSource实现如下。

<Resource name="jdbc/TEST_DS"
                        auth="Container"
                        type="javax.sql.DataSource"
                        driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
                        url="jdbc:sqlserver://hostName;databaseName=TEST"
                        username="test"
                        password="testPwd"
                        maxPoolSize="50" 
                removeAbandoned="true"
                        removeAbandonedTimeout="1000"
                        logAbandoned="true"
                        />

任何人都可以在此代码中建议我需要修改的内容吗?

4 个答案:

答案 0 :(得分:1)

通过查看答案here,看起来关闭的顺序可能导致问题。

更改此代码......

finally {
     if (bais != null)
         bais.close();

         if (bis != null)
             bis.close();

         if (bos != null)
             bos.close();
 }

要...

finally {
         bais.close();
         bos.close();
         bis.close();
 }

答案 1 :(得分:1)

获得该错误有几个原因:

  • 当服务器尝试通信时,网络会丢失。
  • 用户取消请求。
  • 数据库已关闭或拒绝连接。

您需要做的是按此顺序关闭:

finally {
      if(bos != null)
         bos.close();
      if(bis != null)
         bis.close();
      if(bais != null)
         bais.close();
}

希望这有帮助!

答案 2 :(得分:1)

您不应该关闭响应的输出流。我不确定这是否会导致管道损坏,但我肯定会试一试。

Documents document = db.getDocument(docCode);
String contentType = document.getDocMimeType();
byte[] docContentBytes = document.getDocContentBytes();

ServletOutputStream out = response.getOutputStream();
response.setHeader("X-UA-Compatible", "IE=8");
response.setHeader("Content-disposition", "attachment;filename=\"Document\"");
response.setHeader("Pragma", "private");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Content-Transfer-Encoding", "binary");

if (contentType != null) {
    response.setContentType(contentType);
} else {
    response.setContentType("application/pdf");
}


if (docContentBytes != null) {
    try {
        ByteArrayInputStream bais = new ByteArrayInputStream(docContentBytes);

        byte[] buff = new byte[2048];

        int bytesRead;
        while (-1 != (bytesRead = bais.read(buff))) {
            out.write(buff, 0, bytesRead);
        }
    } finally {
        out.flush();
    }
}

以下是其他一些指示:

  • 缓冲字节数组输入流没有意义;你已经有了内存中的数据

  • 关闭缓冲流也会关闭基础流

  • 关闭字节数组流不会做任何事情

  • 缓冲响应的输出流没有意义,因为您已经使用了 代码中的缓冲机制

  • 在处理流/文件时,例如common-io等第三方库非常有用(例如IOUtils

  • 您的异常堆栈跟踪的帖子(部分)发布了关于异常的问题

答案 3 :(得分:1)

你已经在byte [] docContentBytes内部加载了所有文件内容,那你为什么需要缓冲呢?

但是,如果异常是由tomcat和浏览器/客户端之间的通信错误引起的,请尝试删除缓冲并设置content-length。

否则,如果异常是由tomcat和SQL Server之间的通信错误引起的,那么你的问题就在于:

  • db课程实施
  • Documents实施
  • Microsoft SQL Server安装中的设置/调整

但是这就是我编写这个servlet的方式:

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException
{
    Database db = Database.getInstance();

    String docCode = request.getParameter("docCode");
    if(docCode == null || docCode.isEmpty()) throw new IllegalArgumentException("docCode is null");

    Documents document = db.getDocument(docCode);
    if(document == null) throw new IllegalStateException("invalid docCode: " + docCode);

    byte[] docContentBytes = document.getDocContentBytes();
    if(docContentBytes == null) throw new IllegalStateException("document " + docCode + " has no content");

    String contentType = document.getDocMimeType();
    if(contentType == null) contentType = "application/octet-stream";

    response.setHeader("X-UA-Compatible", "IE=8");
    response.setHeader("Content-disposition", "attachment;filename=\"Document\"");
    response.setHeader("Pragma", "private");
    response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
    response.setHeader("Content-Transfer-Encoding", "binary");
    response.setContentType(contentType);
    response.setContentLength(docContentBytes.length);

    response.getOutputStream().write(docContentBytes);
}