如何使用servlet从Oracle数据库下载PDF文件而不会损坏文件



我有一个servlet,我在其中根据id从oracle数据库中检索PDF文件并将其写入响应流。但是,当我尝试这样做时,下载的文件被损坏,文件大小为零。Adobe Reader给出一个错误,说" 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编程的新手,有人知道吗?也请发布一个工作解决方案。预先感谢。

一个问题在这里:

int fileLength = inputStream.available();

可用()不会返回流中字节的总数。它只是返回可以读取多少个字节而不会阻止。从文档中:

请注意,尽管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);

同样,您要做的不仅仅是当结果集为空时打印"找不到的文件"。有一个HTTP响应代码专门表示HTTP请求失败,因为找不到请求资源:

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

最新更新