Das Filesystem. Unendliche Weiten. Dies sind die Abenteuer des Paketes java.io… Ich steh nicht so auf Abenteuer beim produktiven Programmieren. Dateirechte, Pfade… um nur einige Probleme zu nennen. Daher wollte ich probieren, Bilder binär in die Datenbank zu schreiben. Daraus ist dieses kurze “HowTo” über das Speichern von binären Daten in PostgreSQL mit dem O/R Mapper Hibernate entstanden. Die Ausgabe erfolgt über ein Servlet und eine JSP.
Das Mapping
Nach einiger Recherche habe ich herausgefunden, dass sich der Postgres-Datentyp bytea
am besten für diese Aufgabe eignet. Das ganze wird in Hibernate einfach wie folgt gemappt:
<property name="imageBlob" type="binary">
<column name="image_blob" />
</property>
Die gemappte Klasse verwendet dann einfach nur den Datentyp byte[]
. Inklusive Get/Set-Methoden sieht das dann so aus:
private byte[] imageBlob;
public byte[] getImageBlob() {
return imageBlob;
}
public void setImageBlob(byte[] imageBlob) {
this.imageBlob = imageBlob;
}
Das Servlet
ByteArray-Streams eignen sich gut zur Weiterverarbeitung. Als Beispiel dient das folgende Servlet, dass einfach das Image wieder ausgibt und eine hochgeladene Datei in die Datenbank schreibt. Für den Upload habe ich das Framework “commons-upload” von Apache.org verwendet.
Zuerst die Get-Methode zur Ausgabe des Bildes:
protected void doGet(
HttpServletRequest request,
HttpServletResponse response) {
String type = request.getParameter("type");
String uid = request.getParameter("uid");
if (type == null) {
response.sendError(404);
return;
}
byte[] byteArray;
if (type.equals("scene")) {
// Get the mapped class
GeScene scene = sceneService.get(Integer.parseInt(uid));
byteArray = scene.getImageBlob();
} else {
response.sendError(404);
return;
}
InputStream in = new ByteArrayInputStream(byteArray);
OutputStream out = response.getOutputStream();
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
in.close();
out.flush();
out.close();
}
Und dann noch die POST Methode des Servlets:
protected void doPost(
HttpServletRequest request,
HttpServletResponse response) {
// Alles zur FileItemFactory kann man aus der
// Doku zu commons-upload erfahren.
ServletFileUpload upload = new ServletFileUpload(
newDiskFileItemFactory(getServletContext(), new File("tmp")));
String uid = request.getParameter("uid");
try {
List<FileItem> files = upload.parseRequest(request);
for (FileItem fileItem : files) {
if (!fileItem.isFormField()) {
GeScene scene = sceneService.get(Integer.parseInt(uid));
scene.setImageBlob(fileItem.get());
sceneService.update(scene);
}
}
} catch (Exception e) {
// Error Handler
} finally {
RequestDispatcher disp =
request.getRequestDispatcher("imageservice.jsp");
disp.forward(request, response);
}
}
Das JSP
Fehlt noch das passende JSP für den Upload:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%
String uid = request.getParameter("uid");
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<img src="ImageService?type=scene&uid=<%=uid %>"
width="100" height="100" />
<form action="ImageService?type=scene&uid=<%=uid %>"
enctype="multipart/form-data" method="post">
<input type="file" name="file">
<button>Submit</button>
</form>
</body>
</html>
Fazit:
Das Mapping funktioniert denkbar einfach, auch die Verarbeitung artet keineswegs in Probleme aus. Nun wird sich im Laufe der Zeit zeigen, ob das ganze auch performant ist.
[ad#artikel-werbung]