【问题标题】:How to handle multiple document open request fire in servlet如何在 servlet 中处理多个文档打开请求触发
【发布时间】:2013-10-19 02:20:33
【问题描述】:

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

我的代码 sn-p 如下。

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"
                        />

谁能建议我在这段代码中需要修改什么?

【问题讨论】:

  • 最好能看到至少一个错误。

标签: java servlets tomcat6


【解决方案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();
 }

【讨论】:

    【解决方案2】:

    出现该错误的原因有多种:

    • 服务器尝试通信时网络中断。
    • 用户取消了请求。
    • 数据库已关闭或拒绝连接。

    你需要做的是按这个顺序关闭:

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

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

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

      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

      • 发布(一部分)您的异常堆栈跟踪您正在发布有关异常的问题

      【讨论】:

        【解决方案4】:

        您已经在 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);
        }
        

        【讨论】:

          猜你喜欢
          • 2017-11-20
          • 2012-04-02
          • 2022-01-14
          • 2019-02-28
          • 2012-12-04
          • 1970-01-01
          • 1970-01-01
          • 2011-12-22
          相关资源
          最近更新 更多