【问题标题】:How to download a pdf file from oracle database using servlets without corrupting the file?如何使用 servlet 从 oracle 数据库下载 pdf 文件而不损坏文件?
【发布时间】:2019-03-11 09:07:31
【问题描述】:

我有一个 servlet,我在其中根据 id 从 oracle 数据库中检索 pdf 文件并将其写入响应流。但是当我尝试这样做时,下载的文件已损坏并且文件大小为零。 Adobe 阅读器提示“Adobe 无法打开“myfile.pdf”,因为它不是受支持的类型...”。

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.sql.Blob;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;

    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;



    @MultipartConfig( fileSizeThreshold = 1024 * 1024,
    maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 5 * 5)

    public class DBFileDownloadServlet extends HttpServlet {


        private static final long serialVersionUID = 1L;
        // size of byte buffer to send file
        private static final int BUFFER_SIZE = 4096;   



        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            // get file id from URL's parameters
            String course_code = request.getParameter("course_code");

            Connection conn = null; // connection to the database

            try {
                        // connects to the database
                Connection con = JDBCfile.getOracleConnection();


                // queries the database
                String sql = "SELECT * FROM course_syllabus WHERE course_code = ?";

             PreparedStatement statement = con.prepareStatement(sql);
                    statement.setString(1, course_code);

                ResultSet result = statement.executeQuery();

            if (result.next()) {
                    // gets file name and file blob data

            String fileName = result.getString("file_name");
                    Blob blob = result.getBlob("syllabus_file");
                    InputStream inputStream = blob.getBinaryStream();
                    int fileLength = inputStream.available();

                    System.out.println("fileLength = " + fileLength);

                    ServletContext context = getServletContext();

                    // sets MIME type for the file download
                    String mimeType = context.getMimeType(fileName);
                    if (mimeType == null) {        
                        mimeType = "application/octet-stream";
                    }              

                    // set content properties and header attributes for the response
                    response.setContentType(mimeType);
                    response.setContentLength(fileLength);
                    String headerKey = "Content-Disposition";
                    String headerValue = String.format("attachment; filename=\"%s\"", fileName);
                    response.setHeader(headerKey, headerValue);

                    // writes the file to the client
                    OutputStream outStream = response.getOutputStream();

                    byte[] buffer = new byte[BUFFER_SIZE];
                    int bytesRead = -1;

                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outStream.write(buffer, 0, bytesRead);
                    }

                    inputStream.close();
                    outStream.close();             
                } else {
                    // no file found
                    response.getWriter().print("File not found for the file id: " + course_code);  
                }
            }catch (SQLException ex) {
                ex.printStackTrace();
                response.getWriter().print("SQL Error: " + ex.getMessage());
            } catch (IOException ex) {
                ex.printStackTrace();
                response.getWriter().print("IO Error: " + ex.getMessage());
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                JDBCfile.cleanup(con,statement); //closes connection      
            }
        }
    }

course_syllabus 表有以下列:course_code varchar,file_name varchar,syllabus_file (blob)

一切都执行得很完美,但我下载的文件的字节为零,没有可读取的内容。我是 servlet 编程的新手,有人知道吗? 请也发布一个有效的解决方案。提前致谢。

【问题讨论】:

    标签: java servlets oracle11g


    【解决方案1】:

    这里有个问题:

    int fileLength = inputStream.available();
    

    available() 不返回流中的总字节数。它只返回可以在不阻塞的情况下读取多少字节。来自documentation

    请注意,虽然InputStream 的某些实现会返回流中的总字节数,但很多不会。 使用此方法的返回值来分配用于保存此流中所有数据的缓冲区是不正确的。

    改用Blob.length()

    long fileLength = blob.length();
    // ...
    response.setContentLengthLong(fileLength);
    

    另一个问题是您的错误处理。如果方法没有成功,请不要表现得像方法成功一样。如果您的方法无法成功获取文件,您希望 HTTP 调用返回错误。

    首先,删除 catch (IOException ex) 块。如果存在 IOException,您希望它传播,因此 HTTP 调用将失败。

    其他两个块需要传播它们的错误:

    } catch (SQLException ex) {
        throw new ServletException(ex);
    } catch (ClassNotFoundException e) {
        throw new ServletException(e);
    

    同样,您要做的不仅仅是在 ResultSet 为空时打印“找不到文件”。有一个 HTTP 响应代码专门用于指示由于未找到请求的资源而导致 HTTP 请求失败:

    if (result.next()) { 
        // ...
    } else {
        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        response.getWriter().print("File not found for the file id: " + course_code);  
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      • 2015-10-12
      • 1970-01-01
      • 2011-04-20
      相关资源
      最近更新 更多