Marquise Mery
Marquise Mery

Reputation: 140

How to display an image from external folder in a html page

I am working on a project to get thumbnails from a video and then display them in the home page.

The thumbnails are correctly generated in the folder uploads but they are not displayed in the home page. I am getting not found error 404.

Bellow is a code JeutrollServiceImp used to get thumbnails from a video In the html, I am using a hard coding name of the image for test's purprose.

import com.jeutroll.dao.UserRepository;
import com.jeutroll.dao.VideoRepository;
import com.jeutroll.entities.Video;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@Service
@Transactional
public class JeutrollServiceImp implements JeutrollService
{
    public static String uploadDirectory= System.getProperty("user.home") + "/uploads";
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private VideoRepository videoRepository;


    @Override
    public Page<Video> browseVideos(String aInCategory, int page, int size)
    {
        return videoRepository.listVideos(aInCategory, new PageRequest(page, size));
    }

    @Override
    public Video browseVideo(String aTitle)
    {

        return null;
    }

    @Override
    public void uploadVideo(Video aInVideo)
    {

    }

    @Override
    public com.jeutroll.entities.User findUserByEmail(String email)
    {
        return userRepository.findByEmail(email);
    }

    @Override
    public String retriveThumbnailFromVideo(String videoPath)
    {
        String thumbnailPath;
        File lImgFile = null;
        FFmpegFrameGrabber g = new FFmpegFrameGrabber(videoPath);
        try
        {
            g.start();
            // on fait défiler les 10 premières frame
            for (int i = 0; i < 100; i++)
            {
                g.grab();

            }

            Frame lFrame = g.grabImage();
            BufferedImage lBufferedImage = new Java2DFrameConverter().convert(lFrame);
            // on enregistre la 101ième
            Path path = Paths.get(uploadDirectory,"life_" + System.currentTimeMillis() + ".png" );
            //lImgFile = new File("/resources/static/life_" + System.currentTimeMillis() + ".png");
            lImgFile = new File(path.toString());

            ImageIO.write(lBufferedImage, "png", lImgFile);

            // récupération de la durée de la vidéo
            float duration = (float) g.getLengthInTime() / 1000000;

            g.stop();
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            System.err
                    .println("La création de la miniature n'a pas pu être effectuée!");
            e.printStackTrace();
        }
        return lImgFile.getName();
    }

    @Override
    public void uploadVideos(String aInFilePath)
    {
        //        storageService.store(file);
    }
}

WebConfigurer Class

package com.jeutroll.configuration;

import com.jeutroll.service.JeutrollServiceImp;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

public class WebConfigurer extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/uploads/**").addResourceLocations("file:/" + JeutrollServiceImp.uploadDirectory);
    }

} 

Here I am using a video that already existing in external folder on the disk.

 <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="template1.html">
<head>
    <meta charset="UTF-8">
    <title>Jeutroll</title>
</head>
<body>
<div layout:fragment="content">
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2 text-center">
                <h2 class="section-title uppercase"> Projets Réalisés</h2>
            </div>
        </div>
        <section class="row" th:if="${videos}">
            <div class="col-xs-12 col-sm-3 col-md-4 col-lg-4" th:each="v:${videos}">
                <a href="#" class="thumbnail"><img src="/uploads/life_1549107645227.png" alt="Image 2" width="500px " >
                    <div class="caption">
                        <span class="cat-link">categorie</span>
                        <span class="separator">|</span>
                        <span class="pub-date">6 janvier 2019</span>
                        <span class="glyphicon glyphicon-comment"></span>
                    </div>
                    <div class="rating">

                    </div>
                </a>
            </div>
        </section>
    </div>
</div>
</body>
</html>

Upvotes: 1

Views: 2332

Answers (2)

Paul Warren
Paul Warren

Reputation: 2479

I would suggest you take a look at Spring Content. This community project allows you to associate content (i.e. unstructured data like videos) with Spring Data Entities using the same programming model.

It is pretty simple to add to your existing project and it will give you the same easy programming model as Spring Data, an abstraction over your storage (so it could be store in any Storage Spring Content supports) and a bunch of other features OOTB like the REST endpoint that support video streaming.

In case you are interested here is how I think you could do it (assuming Spring Boot).

Add the dependencies to your project:-

pom.xml

    <!-- Java API --> 
    <dependency>
        <groupId>com.github.paulcwarren</groupId>
        <artifactId>spring-content-fs-boot-starter</artifactId>
        <version>0.5.0</version>
    </dependency>
    <!-- REST API --> 
    <dependency>
        <groupId>com.github.paulcwarren</groupId>
        <artifactId>spring-content-rest-boot-starter</artifactId>
        <version>0.5.0</version>
    </dependency>

Configure your file storage:

StoreConfig.java

@Configuration
@EnableFilesystemStores
public class EnableFilesystemStoresConfig {

    @Bean
    File filesystemRoot() {
        try {
            return new File(JeutrollServiceImp.uploadDirectory);
        } catch (IOException ioe) {}
        return null;
    }

    @Bean
    FileSystemResourceLoader fileSystemResourceLoader() {
        return new FileSystemResourceLoader(filesystemRoot().getAbsolutePath());
    }

}

Associate content with your entity:

    @Entity
    public class Video {
      @Id @GeneratedValue
      private Long id;
      ... other Spring Data fields ...

      // associate the video
      @ContentId
      private UUID contentId;

      @ContentLength
      private Long contentLength;

      @Mimetype
      private String mimeType;

      // associate thumbnails
      private Thumbnail thumbnail;
      ...
   }

   @Entity
   public class Thumbnail {
      @ContentId 
      private UUID contentId;

      @ContentLength 
      private Long contentLength;

      @MimeType 
      private String mimeType;
   }

Create a video store and a thumbnail store:

VideoStore.java/ThumbnailStore.java

  @StoreRestResource(path="videoContent")
  public interface VideoStore extends ContentStore<Video,UUID> {
  }

  public interface ThumbnailStore extends ContentStore<Thumbnail,UUID> {
  }

The spring-content-fs-boot-starter dependency will cause Spring Content to inject filesystem-based implementations so you don't need to worry about implementing these yourself. Moreover, the spring-content-rest dependency will cause Spring Content to also inject implementations of @Controller that forward HTTP requests onto the methods of the VideoStore and ThumbnailStore respectively.

So you will now have a fully functional (POST, PUT, GET, DELETE) REST-based video service at /videoContent that will use your VideoStore to retrieve (and store) videos in JeutrollServiceImp.uploadDirectory on your server.

So:

POST /videoContent/ -F "image=@/some/path/to/a/video.mp4"

will upload video.mp4 and add it to your uploads directory.

GET /videoContent/{videoId}

will get it again and store rest endpoints support Range requests so HTML5 video controls will work appropriately.

For the thumbnails you can add the processing to generate and store the thumbnail in an annotated store event handler:-

@Configuration
public class ThumbnailConfig {

    @Bean
    public StoreEventHandler thumbnailEventHandler() {
        return new ThumbnailEventHandler();
    }

    @StoreEventHandler
    public static class ThumbnailEventHandler {

        @Autowired
        VideoRepository videoRepository;

        @Autowired
        VideoStore videoStore;

        @Autowired
        ThumbnailStore thumnailStore;

        @HandleAfterSetContent
        public void handleAfterSetContent(Video video) {

           BufferedImage img = // use modfied retrieveThumbnailFromVideo(videoStore.getContent(video));

           Thumbnail thumbnail = new Thumbnail();
           thumbnail.setMimeType("png")
           thumbnail.setContent(thumbnail, toInputStream(img))

           video.setThumbnail(thumbnail)
           videoRepository.save(video);
        }
    }
 }

After each video is store its thumbnail will then be available via:

GET /videoContent/{videoId}/thumbnail

or:

GET /videoContent/{videoId}/thumbnail/{contentId}

As we store the mimetype these URLs will be usable as the src in a standard on your HTML.

So:

Becomes:

HTH

Upvotes: 0

Marquise Mery
Marquise Mery

Reputation: 140

After being stuck for hours on this problem, I finally figured it out. The main problem is that I did not added @EnableWebMvc in the class WebConfigurer. The second is the image directory was not correct. I am executing my project on Windows OS and I used System.getProperty("user.home") + "/uploads"; instead of System.getProperty("user.home") + "\uploads";

Because it is a recurrent subject. I have decided to write an example for this case. I home it will help. http://mkaroune.e-monsite.com/pages/spring/get-images-from-external-folder-on-disk.html

@Ahmed Yes the method is returning the correct image path.

Upvotes: 1

Related Questions