简体   繁体   中英

Getting Object from database containing byte array image

I am working on my blog and have some problem. First of all, I am able to upload any image and later find this image by id and convert byte[] to String and display it in the browser. I just have something like this

Image imagesObj = imageService.getImage(id); 
byte[] encode = Base64.getEncoder().encode(imagesObj.getImage());
model.addAttribute("image", new String(encode, "UTF-8"));
<img th:src="*{'data:image/jpg;base64,'+ image" alt="#" />

I got Post entities and Image entities, mapped @OneToOne. When I make new post, id from Image is also assigned to Post. Now the problem is, when I want to display all my post on the main page with:

 @GetMapping("/")
    public String mainPage(Model model) {
        model.addAttribute("posts", postService.findAll());
        return "main";

    }

I am giving back whole Post Object and it contains postTitle, postContent and byte[] array. I found similar problem on this question How to display byte array from a model in Thymeleaf From this post I came with something like this:

   @GetMapping("image/{id}")
    public void getImageDetails(@PathVariable Long id, HttpServletResponse response) throws IOException {

        response.setContentType("image/jpeg");
        Image image = imageService.getImage(id);
        InputStream is = new ByteArrayInputStream(image.getImage());
        IOUtils.copy(is, response.getOutputStream());
        //IOUtils(is, response.getOutputStream());
    }


Thymeleaf

   <img th:src="@{'image/{id}' + @{post.image()}}" alt="#">

I tried also with post.getImage(). I am thinking about this for some time now, and do not know how should I take this problem. Thank you

UPDATE

I managed to find solution, but it is not a good way of doing it. I read bytes from file and later convert it to String and save image as String in database. Later when I use findAll() I am able to read image in thymeleaf.

byte[] image = file.getBytes();
byte[] encodeBase64 = Base64.getEncoder().encode(image);
String s = new String(encodeBase64, "UTF-8");

Saving String s to database.

And in Thymeleaf I just loop over Post object and check if values are not null

<img  th:src="@{'data:image/jpeg;base64,'+${post?.getImage()?.getImageString()}}" alt="#"/>

If you have any hints to make it better, please let me now

You should take a look at the community project Spring Content . This project gives you a Spring Data API and development approach to content. It is to unstructured data (documents, images, videos, etc), what Spring Data is to structured data. You could add it with something like the following:-

pom.xml (Spring Boot starters also available)

   <!-- Java API -->
   <dependency>          
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-jpa</artifactId>
      <version>0.11.0</version>
   </dependency>
   <!-- REST API -->
   <dependency>
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-rest</artifactId>
      <version>0.11.0</version>
   </dependency>

Configuration

@Configuration
@EnableJpaStores
@Import("org.springframework.content.rest.config.RestConfiguration.class") <!-- enables REST API)
public class ContentConfig {

   <!-- specify the resource specific to your database --> 
   @Value("/org/springframework/content/jpa/schema-drop-h2.sql")
   private ClasspathResource dropBlobTables;

   <!-- specify the resource specific to your database --> 
   @Value("/org/springframework/content/jpa/schema-h2.sql")
   private ClasspathResource createBlobTables;

   @Bean
   DataSourceInitializer datasourceInitializer() {
     ResourceDatabasePopulator databasePopulator =
            new ResourceDatabasePopulator();

     databasePopulator.addScript(dropBlobTables);
     databasePopulator.addScript(createBlobTables);
     databasePopulator.setIgnoreFailedDrops(true);

     DataSourceInitializer initializer = new DataSourceInitializer();
     initializer.setDataSource(dataSource());
     initializer.setDatabasePopulator(databasePopulator);

     return initializer;
   }
}

NB: this configuration is not needed if you use the relevant Spring Boot starter.

To associate content, add Spring Content annotations to your Image entity.

Post.java

@Entity
public class Post {

   ...

   @OneToOne
   private Image image;

Image.java

@Entity
public class Image {

   // replace @Lob/byte array field with:

   @ContentId
   private String contentId;

   @ContentLength
   private long contentLength = 0L;

   @MimeType
   private String mimeType;

Create a "store" for your images:

ImageContentStore.java

public interface ImageContentStore extends ContentStore<Image, String> {
}

This is all you need to create REST endpoints @ /image/{imageId} . When your application starts, Spring Content will look at your dependencies (seeing Spring Content JPA/REST), look at your ImageContentStore interface and inject an implementation of that interface for JPA.It will also inject a @Controller that forwards http requests to that implementation. This saves you having to implement any of this yourself.

So...

curl -X POST /image/{imageId} -F 'data=@path/to/local/file'

will store the content of file path/to/local/file in the database and associate it with the post entity whose id is postId .

curl /image/{imageId}

will fetch it again and so on...supports full CRUD.

There are a couple of getting started guides and videos here . The reference guide is here .

HTH

You should take a look at the community project Spring Content . This project gives you a Spring Data API and development approach to content. It is to unstructured data (documents, images, videos, etc), what Spring Data is to structured data. You could add it with something like the following:-

pom.xml (Spring Boot starters also available)

   <!-- Java API -->
   <dependency>          
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-jpa</artifactId>
      <version>0.11.0</version>
   </dependency>
   <!-- REST API -->
   <dependency>
      <groupId>com.github.paulcwarren</groupId>
      <artifactId>spring-content-rest</artifactId>
      <version>0.11.0</version>
   </dependency>

Configuration

@Configuration
@EnableJpaStores
@Import("org.springframework.content.rest.config.RestConfiguration.class") <!-- enables REST API)
public class ContentConfig {

   <!-- specify the resource specific to your database --> 
   @Value("/org/springframework/content/jpa/schema-drop-h2.sql")
   private ClasspathResource dropBlobTables;

   <!-- specify the resource specific to your database --> 
   @Value("/org/springframework/content/jpa/schema-h2.sql")
   private ClasspathResource createBlobTables;

   @Bean
   DataSourceInitializer datasourceInitializer() {
     ResourceDatabasePopulator databasePopulator =
            new ResourceDatabasePopulator();

     databasePopulator.addScript(dropBlobTables);
     databasePopulator.addScript(createBlobTables);
     databasePopulator.setIgnoreFailedDrops(true);

     DataSourceInitializer initializer = new DataSourceInitializer();
     initializer.setDataSource(dataSource());
     initializer.setDatabasePopulator(databasePopulator);

     return initializer;
   }
}

NB: this configuration is not needed if you use the relevant Spring Boot starter.

To associate content, add Spring Content annotations to your Image entity.

Post.java

@Entity
public class Post {

   ...

   @OneToOne
   private Image image;

Image.java

@Entity
public class Image {

   // replace @Lob/byte array field with:

   @ContentId
   private String contentId;

   @ContentLength
   private long contentLength = 0L;

   @MimeType
   private String mimeType;

Create a "store" for your images:

ImageContentStore.java

@StoreRestResource("images")
public interface ImageContentStore extends ContentStore<Image, String> {
}

This is all you need to create REST endpoints @ /images . When your application starts, Spring Content will look at your dependencies (seeing Spring Content JPA/REST), look at your ImageContentStore interface and inject an implementation of that interface for JPA.It will also inject a @Controller that forwards http requests to that implementation. This saves you having to implement any of this yourself.

So...

curl -X POST /image/{imageId} -F 'data=@path/to/local/file'

will store the content of file path/to/local/file in the database and associate it with the image entity whose id is imageId .

curl /images/{imageId}

will fetch it again and so on...supports full CRUD.

There are a couple of getting started guides and videos here . The reference guide is here .

HTH

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM