2016-02-19 53 views
3

我有postgresSQL數據庫,並有數據類型'bytea'列'圖像'。我無法修改列或數據庫配置。 JPA註解POJO包含followign映射如何用JPA從postgresSQL讀取bytea圖像數據?

@Column(name="image") 
private byte[] image; 

返回的數據以以下格式(這只是一個樣本)

WF5ClN6RlpLZ0hJTUdNQ1FJWmkwcFVGSUdNQ0lDWUE5TUEvanRFeElwK2x0M2tBQUFBQVNVVk9SSzVDWUlJPQo= 

當我寫這篇文章的數據文件(JPEG格式),圖片瀏覽器說:「這已損壞的文件「。我也明白,實際圖像字節數據看起來不同於上面的示例。我讀過一些博客,其中提到PostgreSQL將byteade數據應用於十六進制轉換。如何使用或不使用JPA將其恢復爲原始數據?

數據庫 - PostgreSQL的9.5.1版

驅動

<dependency> 
    <groupId>org.postgresql</groupId> 
    <artifactId>postgresql</artifactId> 
    <version>9.4-1205-jdbc41</version> 
</dependency> 
+0

你的榜樣應該工作(如果你不使用'@ Lob'註釋;見[此相關問題](http://stackoverflow.com/questions/3677380/proper-hibernate-annotation-for-byte))。你是如何完全得到base64表示的?你確定這不是什麼東西,這是由一個視圖相關的服務輸出(並可能轉換)?(請嘗試調試'@ Entity'來查看,確切地說,返回到'image'屬性以及您在保存之前對該屬性設置了什麼)。 – pozs

+0

你確定這是一個圖像嗎?你如何儲存它?另請檢查[this](http://stackoverflow.com/q/17667480/1700321)。 –

+0

@pozs使用apache編解碼器Base64類和javax.xml.bind.DatatypeConverter parseBase64Binary()解碼。 – Bhushan

回答

3

返回的數據看起來好像是base64編碼。寫入文件之前,您必須將其解碼爲二進制數據。

更多信息解碼看here

+0

我試了一下,不幸的是它沒有工作 – Bhushan

+0

是的,你是對的,它的64Base ecoded。感謝名單。在下面添加完整的代碼,可能對其他人有用。 – Bhushan

0

插入圖片,你可以使用:

//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(); 

從大對象檢索圖像:

// 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(); 
+0

我正在使用JPA,我不能像回到JDBC那樣做所有這些事情。我認爲這個解決方案仍然不能用十六進制編碼的數據。 – Bhushan

+0

'bytea'類型和大對象在PostgreSQL中完全分離。 – pozs

1

嘗試,如果你正在使用Hibernate實現,你可以在列添加@Type(type="org.hibernate.type.BinaryType")太註釋您實體@Lob

@Lob 
@Column(name="image") 
private byte[] image; 

@Lob 
@Column(name="image") 
@Type(type="org.hibernate.type.BinaryType") 
private byte[] image; 
2

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

測試

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]); 
     } 

    } 

} 

它使用9.4.1207.jre7 jdbc驅動程序對抗Postgres 9.5.0-1。

0

我加入了完整的代碼可能是其他人(跳過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();