Java 如何使用JPA从PostgreSQL读取bytea图像数据?
我有PostgreSQL数据库,有数据类型为“bytea”的“image”列。我无法修改列或数据库配置。JPA注释的POJO包含以下映射Java 如何使用JPA从PostgreSQL读取bytea图像数据?,java,hibernate,postgresql,jpa,bytea,Java,Hibernate,Postgresql,Jpa,Bytea,我有PostgreSQL数据库,有数据类型为“bytea”的“image”列。我无法修改列或数据库配置。JPA注释的POJO包含以下映射 @Column(name="image") private byte[] image; 返回的数据采用以下格式(这只是一个示例) 当我将这些数据写入文件(.jpeg)时,照片查看器会显示“这是损坏的文件”。我也知道实际的图像字节数据看起来和上面的示例不同。我读过一些博客,其中提到PostgreSQL将十六进制转换应用于bytea数据。如何将其恢复为原始数据(
@Column(name="image")
private byte[] image;
返回的数据采用以下格式(这只是一个示例)
当我将这些数据写入文件(.jpeg)时,照片查看器会显示“这是损坏的文件”。我也知道实际的图像字节数据看起来和上面的示例不同。我读过一些博客,其中提到PostgreSQL将十六进制转换应用于bytea数据。如何将其恢复为原始数据(带或不带JPA)
数据库-PostgresSQL版本9.5.1
司机
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1205-jdbc41</version>
</dependency>
org.postgresql
postgresql
9.4-1205-jdbc41
插入图像,您可以使用:
//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();
从大型对象检索图像:
//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();
返回的数据看起来像是base64编码的。在写入文件之前,必须将其解码回二进制数据
有关解码look的更多信息,请尝试使用
@Lob
@Lob
@Column(name="image")
private byte[] image;
如果您使用的是hibernate实现,那么也可以在列中添加@Type(Type=“org.hibernate.Type.BinaryType”)
@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;
}
}
package com.example;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ImageRepository extends JpaRepository<ImageEntity, Long> {
}
ImageRepository
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;
}
}
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;
导入org.springframework.data.jpa.repository.JpaRepository;
导入org.springframework.stereotype.Repository;
@存储库
公共接口ImageRepository扩展了JpaRepository{
}
测试
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]);
}
}
}
package.com.example;
导入java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入javax.annotation.Resource;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.springframework.boot.test.SpringApplicationConfiguration;
导入org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
导入junit.framework.TestCase;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(类=TestApplication.class)
公共类映像测试{
@资源
私有图像库;
@试验
public void testImage()引发IOException{
//从磁盘读取图像。假设test.png存在
ByteArrayOutputStream out=新建ByteArrayOutputStream();
try(InputStream in=getClass().getResourceAsStream(“test.png”)){
整数长度;
字节[]缓冲区=新字节[1024];
而((长度=in.read(buffer))!=-1)out.write(buffer,0,length);
}
byte[]image=out.toByteArray();
//将图像存储到数据库
ImageEntity ImageEntry=新的ImageEntity();
设置图像(图像);
long-ImageEntryId=imageRepository.save(ImageEntry.getId();
//从数据库中检索图像
ImageEntity ResultimageEntry=imageRepository.findOne(ImageEntryId);
字节[]resultImage=resultimageEntry.getImage();
//逐字节比较检索到的图像与源图像
for(int i=0;i
它适用于带有9.4.1207.jre7 jdbc驱动程序的Postgres 9.5.0-1。我正在添加可能对其他人有用的完整代码(跳过try/catch)
我正在使用JPA,我不能做所有这些事情,比如回到JDBC。我认为此解决方案仍然无法处理十六进制编码的数据。
bytea
类型和大型对象在PostgreSQL中完全分离。您的示例应该可以工作(如果您不使用@Lob
注释;请参阅)。你到底是怎么得到base64表示的?您确定这不是由视图相关服务输出(并可能转换)的内容吗?(请尝试调试@实体
以查看图像
属性的确切内容&在保存之前,您对该属性设置了什么)。您确定这是图像吗?你怎么储存它?另请检查。@pozs是用apache编解码器Base64类和javax.xml.bind.DatatypeConverter parseBase64Binary()解码的。是的,您是对的,它的64Base ecoded。塔克斯。下面添加了完整的代码,可能对其他人有用。