2010-06-05 51 views
10

我正在以最佳性能將圖像寫入servlet響應。任何建議,做法,經驗?以最佳性能將圖像寫入servlet響應

+0

我將圖像保存在當前項目的數據庫中。特定的彈簧控制器從DB獲取圖像的字節數組並將它們寫入到servlet響應中。還有一個servlet容器前面的web服務器。 據我所知可能會導致一些性能問題。現在我沒有麻煩,但希望知道是否有一些好的解決方案。例如。一些緩存做法,特定的標題等。 有關DB和FileSystem作爲圖像存儲的一些經驗值得讚賞。在數據庫中存儲圖像對我來說似乎更舒適。 – tabdulin 2010-06-05 11:41:43

回答

22

爲了獲得最佳性能和效率,請不要將整個內容放入byte[]。每個byte吃的,是的,從Java的內存中的一個字節。設想100個併發用戶請求每個100KB的10個圖像,這已經消耗掉了100MB的Java內存。

獲取使用ResultSet#getBinaryStream()圖像作爲來自DB的InputStream,它包裝在一個BufferedInputStream並將其寫入通過小byte[]緩衝包裝在一個BufferedOutputStream響應的OutputStream

假設你在數據庫鍵標識選擇圖像,使用你的HTML:

<img src="images/123"> 

創建它在web.xml映射在/images/*url-pattern一個Servlet類並實現其doGet()方法如下:

Long imageId = Long.valueOf(request.getPathInfo().substring(1)); // 123 
Image image = imageDAO.find(imageId); // Get Image from DB. 
// Image class is just a Javabean with the following properties: 
// private String filename; 
// private Long length; 
// private InputStream content; 

response.setHeader("Content-Type", getServletContext().getMimeType(image.getFilename())); 
response.setHeader("Content-Length", String.valueOf(image.getLength())); 
response.setHeader("Content-Disposition", "inline; filename=\"" + image.getFilename() + "\""); 

BufferedInputStream input = null; 
BufferedOutputStream output = null; 

try { 
    input = new BufferedInputStream(image.getContent()); 
    output = new BufferedOutputStream(response.getOutputStream()); 
    byte[] buffer = new byte[8192]; 
    for (int length = 0; (length = input.read(buffer)) > 0) { 
     output.write(buffer, 0, length); 
    } 
} finally { 
    if (output != null) try { output.close(); } catch (IOException logOrIgnore) {} 
    if (input != null) try { input.close(); } catch (IOException logOrIgnore) {} 
} 

ImageDAO#find()你可以使用ResultSet#getBinaryStream()來獲取圖像作爲InputStream來自數據庫。

+0

在這方面的一個小變化可能是允許ImageDAO寫回響應,或者可能使用類似樣式的回調(請考慮spring JdbcTemplate或HibernateTemplate)。否則,從ImageDAO.find()返回後,JDBCConnection和ResultSet將不得不保持打開狀態,以使Image#content InputStream正常工作。 – 2010-06-05 14:12:10

+0

嗨,雖然你說「不要使用byte []」,你可以使用byte [] buffer = new byte [8192];',那有什麼意義? – hguser 2014-07-09 02:16:56

+0

@hguser:我澄清了答案。 – BalusC 2014-07-09 05:18:05

0

如果存在Blob類型的數據庫中,則可以使用servlet的圖像的數組類型字節。

byte[] image; 

或者還有一種方法,但它有點複雜。當你打電話給你的servlet時,所以在你之前你需要確定這個電話是用於圖像的還是正常的。如果這是一個正常的調用,那麼你可以繼續調用servlet,但是如果它調用了圖像,那麼不要調用servlet,但是你可以將圖像引用存儲在計算機中的某個物理位置並檢索它。

但是,如果你有數據庫中的圖像,這種方法將不起作用,而你可以在數據庫中有相對路徑,然後你可以從該路徑獲取圖像。

0

如果圖像是靜態的,請記住,最快的響應是在它到達之前處理的。

你可以站在你的Tomcat服務器前的Apache的httpd。您可以使用緩存邊緣服務器的其他變體。這些線有很多技巧。

當然,這個假設你的應用程序是寫在URL有效映射到一個圖像的方式,很容易緩存。如果你的應用程序缺乏這些,那麼好處就足以考慮重組。