J'ai une base de données PostgreSQL et il y a une colonne 'image' avec le type de données 'bytea'. Je ne peux pas modifier les colonnes ou les configurations de base de données. POJO annoté JPA contient un mappage de suivi
@Column(name="image")
private byte[] image;
Les données retournées sont au format suivant (ce n'est qu'un exemple)
WF5ClN6RlpLZ0hJTUdNQ1FJWmkwcFVGSUdNQ0lDWUE5TUEvanRFeElwK2x0M2tBQUFBQVNVVk9SSzVDWUlJPQo=
Lorsque j'écris ces données dans un fichier (.jpeg), la visionneuse de photos dit "c'est un fichier corrompu". Je comprends également que les données d'octets d'image réelles sont différentes de l'échantillon ci-dessus. J'ai lu certains blogs qui mentionnaient que PostgreSQL applique une conversion hexadécimale aux données de bytea. Comment restaurer les données d'origine avec ou sans JPA?
Base de données - PostgresSQL version 9.5.1
Driver
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1205-jdbc41</version>
</dependency>
Les données renvoyées semblent être codées en base64. Vous devez le décoder de nouveau en données binaires avant d'écrire dans un fichier.
Pour plus d'informations sur le décodage, regardez ici
Essayez d'annoter votre entité avec @Lob
@Lob
@Column(name="image")
private byte[] image;
Si vous utilisez l'implémentation hibernate, vous pouvez également ajouter @Type(type="org.hibernate.type.BinaryType")
dans la colonne.
@Lob
@Column(name="image")
@Type(type="org.hibernate.type.BinaryType")
private byte[] image;
ImageEntity
package com.example;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class ImageEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="image")
private byte[] image;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
}
ImageRepository
package com.example;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ImageRepository extends JpaRepository<ImageEntity, Long> {
}
test
package com.example;
import Java.io.ByteArrayOutputStream;
import Java.io.IOException;
import Java.io.InputStream;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import junit.framework.TestCase;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestApplication.class)
public class ImageDaoTest {
@Resource
private ImageRepository imageRepository;
@Test
public void testImage() throws IOException {
// Read an image from disk. Assume test.png exists
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (InputStream in = getClass().getResourceAsStream("test.png")) {
int length;
byte[] buffer = new byte[1024];
while ((length = in.read(buffer)) != -1) out.write(buffer, 0, length);
}
byte[] image = out.toByteArray();
// Store image to DB
ImageEntity imageEntiry = new ImageEntity();
imageEntiry.setImage(image);
long imageEntiryId = imageRepository.save(imageEntiry).getId();
// Retrieve image from DB
ImageEntity resultImageEntiry = imageRepository.findOne(imageEntiryId);
byte[] resultImage = resultImageEntiry.getImage();
// Compare retrieved image with source image by byte to byte comparison
for (int i = 0; i < resultImage.length; i++) {
TestCase.assertEquals(image[i], resultImage[i]);
}
}
}
Il fonctionne contre Postgres 9.5.0-1 avec le pilote jdbc 9.4.1207.jre7.
J'ajoute du code complet qui peut être utile pour les autres (sauter try/catch),
String base64EncryptedImage = new String(image);
decoded = org.Apache.commons.codec.binary.Base64.decodeBase64(base64EncryptedImage);
ImageOutputStream out = new FileImageOutputStream(new File("D://abc.png"));
out.write(decoded);
out.close();
insérer une image, vous utiliseriez:
//Get the Large Object Manager to perform operations with
LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();
// Create a new large object
int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
// Open the large object for writing
LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
// Now open the file
File file = new File("myimage.gif");
FileInputStream fis = new FileInputStream(file);
// Copy the data from the file to the large object
byte buf[] = new byte[2048];
int s, tl = 0;
while ((s = fis.read(buf, 0, 2048)) > 0) {
obj.write(buf, 0, s);
tl += s;
}
// Close the large object
obj.close();
// Now insert the row into imageslo
PreparedStatement ps = conn.prepareStatement("INSERT INTO imageslo VALUES (?, ?)");
ps.setString(1, file.getName());
ps.setInt(2, oid);
ps.executeUpdate();
ps.close();
fis.close();
// Finally, commit the transaction.
conn.commit();
Récupération de l'image du grand objet:
// All LargeObject API calls must be within a transaction block
conn.setAutoCommit(false);
// Get the Large Object Manager to perform operations with
LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI();
PreparedStatement ps = conn.prepareStatement("SELECT imgoid FROM imageslo WHERE imgname = ?");
ps.setString(1, "myimage.gif");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
// Open the large object for reading
int oid = rs.getInt(1);
LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
// Read the data
byte buf[] = new byte[obj.size()];
obj.read(buf, 0, obj.size());
// Do something with the data read here
// Close the object
obj.close();
}
rs.close();
ps.close();
// Finally, commit the transaction.
conn.commit();