2010-06-05 7 views
10

Ich schreibe ein Bild Servlet Antwort mit bester Leistung. Irgendwelche Ratschläge, Praktiken, Erfahrung?Schreiben Bild Servlet Antwort mit bester Leistung

+0

Ich speichere Bilder in DB im aktuellen Projekt. Spezielle Federsteuerungen rufen die Byte-Arrays von Bildern von der DB ab und schreiben sie in die Servlet-Antwort. Außerdem wird es einen Webserver vor dem Servlet-Container geben. Wie ich weiß, kann es zu einigen Leistungsproblemen führen. Im Moment habe ich keine Probleme, möchte aber wissen, ob es für den Fall gute Lösungen gibt. Z.B. einige Caching-Praktiken, spezifische Header, etc. Einige Erfahrungen über DB vs FileSystem als Bildspeicher werden geschätzt. Das Speichern von Bildern in einer Datenbank scheint mir angenehmer zu sein. – tabdulin

Antwort

22

Für eine optimale Leistung und Effizienz sollten Sie nicht den gesamten Inhalt in byte[] eingeben. Jeder byte isst, ja, ein Byte aus dem Speicher von Java. Stellen Sie sich 100 gleichzeitige Benutzer vor, die 10 Bilder von jeweils 100 KB anfordern, das sind bereits 100 MB Java-Speicher, die weg gegessen werden.

Holen das Bild als InputStream aus der DB ResultSet#getBinaryStream() verwenden, wickeln in einem BufferedInputStream und schreibt sie an die OutputStream der umwickelten Antwort in einem BufferedOutputStream durch einen kleinen byte[] Puffer.

Unter der Annahme, dass Sie Bilder auswählen, indem Sie den Datenbankschlüssel als Bezeichner, verwenden Sie diese in Ihrem HTML:

<img src="images/123"> 

erstellen Servlet Klasse, die in web.xml auf eine url-pattern von /images/* und implementieren seine doGet() Verfahren abgebildet wird wie folgt .:

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) {} 
} 

In der ImageDAO#find() können Sie ResultSet#getBinaryStream() verwenden Sie das Bild als einzu erhalten 0 aus der Datenbank.

+0

eine geringfügige Variante dazu kann sein, dass der ImageDAO die Antwort zurück schreiben kann oder vielleicht einen Callback-ähnlichen Stil verwendet (denke an Spring JdbcTemplate oder HibernateTemplate).Andernfalls müssen JDBCConnection und ResultSet nach der Rückkehr von ImageDAO.find() geöffnet bleiben, damit der Image # -Content InputStream funktioniert. –

+0

Hallo, während du sagst "benutze kein byte []" verwendest du 'byte [] buffer = new byte [8192];', worauf kommt es dann an? – hguser

+0

@hguser: Ich habe die Antwort geklärt. – BalusC

0

Sie können Byte von Array-Typ für Bild von Servlet verwenden, wenn es dort in Database of Blob Typ ist.

byte[] image; 

oder es gibt noch einen Weg, aber es ist ein bisschen komplex. Wenn Sie Ihr Servlet anrufen, müssen Sie vorher feststellen, ob es sich um ein Bild oder um ein normales Gespräch handelt. Wenn es sich um einen normalen Anruf handelt, können Sie weiter zum Aufruf des Servlets gehen, aber wenn es ein Aufruf für ein Bild ist, rufen Sie kein Servlet auf, aber Sie können die Bildreferenzen an einem physischen Ort im Computer speichern und dasselbe abrufen.

Aber diese Methode wird nicht funktionieren, wenn Sie Bilder in DB haben, Sie können relative Pfade in DB haben und dann können Sie das Bild von diesem Pfad holen.

0

Wenn die Bilder statisch sind, denken Sie daran, dass die schnellste Antwort diejenige ist, die behandelt wird, bevor sie zu Ihnen gelangt.

Sie können Apache httpd vor Ihrem Tomcat-Server aufstehen. Sie können andere Varianten von Caching-Edge-Servern verwenden. Es gibt viele Tricks in diesen Bereichen.

Dies setzt natürlich voraus, dass Ihre Anwendung dort geschrieben wird, wo eine URL effektiv auf ein Bild abgebildet wird, das leicht zwischengespeichert werden kann. Wenn Ihre Anwendung dies nicht enthält, sind die Vorteile groß genug, um eine Umstrukturierung in Erwägung zu ziehen.

Verwandte Themen