如何使用Spring-Boot将图像或视频上传到类路径中的持久文件夹?

问题描述 投票:0回答:2

我是Spring-Boot的新手...... 我想上传图片或视频,并将它们存储在服务器中项目的类路径中的持久文件夹“upload-storage”中。我不想将它们存储在数据库中(20 Mo)。 Spring-Boot将它们存储在目标/上传存储中。 功能:我可以通过控制器和Thymeleaf在视图上显示视频。我可以关闭tomcat,关闭浏览器,然后再次打开它们:该功能。 但是第二天,上传存储就消失了! 我认为我没有使用好的过程。 但我发现如何上传图片:好的。我找到了如何在class-path中显示文件夹中的图像:ok。我找到了如何将图像上传到数据库。但没有任何东西可以将上传的图像存储在持久文件夹中。 你能帮助我吗 ?你能告诉我好的过程吗?

一些细节:我有一个实体“视频”来存储视频的名称,扩展名,长度等。 我有“VideoRepository”和“VideoService”来管理“视频”请求。 我有一个“StorageService”和“StorageServiceImpl”来管理视频和图像的上传:它上传视频并将其保存在一个名为“upload-storage”的文件夹中:我将再回到它上面。 我有一个videoForm.html首先用一个表单来选择一个文件并将其发送到“UploadController”,然后另一个表单来显示视频,从视频中提取的数据,修改名称或添加精度,并将此表单发送到保存实体的“VideoController”。 “UploadController”代码的一部分: `@Controller public class UploadController extends BaseController {

private final StorageService storageServiceImpl;

@Autowired
public UploadController(StorageService storageServiceImpl) {
    this.storageServiceImpl = storageServiceImpl;
}

@PostMapping("/upload")
public String recupereUpload(@RequestParam("file") MultipartFile file,Model model){
String filename ="";
try {
    final long limit = 200 * 1024 * 1024;
    if (file.getSize() > limit) {
        model.addAttribute("message", "Taille du fichier trop grand (>200MB)");
        model.addAttribute("ok", false );
    }
    filename = storageServiceImpl.store(file);
    model.addAttribute("filename", filename);
    model.addAttribute("message", "Le téléchargement de " + filename+" est réussi !");
} catch (Exception e) {
    model.addAttribute("message", "FAIL to upload " + filename + "!");
    model.addAttribute("ok", false );
}
Video video = new Video();
model.addAttribute("ok", true ); 
model.addAttribute("video", video);
String baseName =  storageServiceImpl.getBaseName(filename);
String ext = storageServiceImpl.getExtension(filename);
model.addAttribute("nom", baseName);
model.addAttribute("ext", ext); 
model.addAttribute("nomorigin", filename);
model.addAttribute("size", Math.round(file.getSize()/1024));
String typExt = storageServiceImpl.getType(ext);
model.addAttribute("typExt", typExt);
return "elementVideo/videoForm";
}

`

“Storage ServiceImpl”有不同的方法:

getExtension(String filename){...}
getType(String ext){...}
getType(String ext){...}
getBaseName(String filename){...}

主要方法是store(MultipartFile文件){...}:

@Service    
public class StorageServiceImpl implements StorageService {

private final Path storageLocation = Paths.get("upload-storage");

@Override
public String store(MultipartFile file) {
    try {
        // Vérification de l'existence :
        if (file.isEmpty()) {
            throw new Exception("Failed to store empty file " + file.getOriginalFilename() ); 
        }
        // Vérification de la nature et traitement du fichier uploadé :
        String ext = getExtension(file.getOriginalFilename());
        String[] extAutorise = {"mp4", "avi","ogg","ogv","jpg","jpeg","png","gif"};
        String fileNameTarget ="";
        if ( ArrayUtils.contains( extAutorise, ext)) { 

            //Définir le fichier destination :
            fileNameTarget = file.getOriginalFilename();
            fileNameTarget = fileNameTarget.replaceAll(" ", "_");
            File dir = storageLocation.toFile();
            String serverFile =  dir.getAbsolutePath()  + File.separator + fileNameTarget ;
            try {
                try (InputStream is = file.getInputStream();
                     BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile))
                    ) {
                    int i;
                    while ((i = is.read()) != -1) {
                        stream.write(i);
                    }
                    stream.flush();
                }
            } catch (IOException e) {
                System.out.println("error : " + e.getMessage());
            }
         }
         return fileNameTarget;
    } catch (Exception e) {
        throw new RuntimeException("FAIL!");
    }
}

` 使用此代码,将在项目的根目录中创建“upload-storage”文件夹。 视频已上传到此文件夹中... 但在“videoForm.html”中,代码

<video id="video" th:src="'/upload-storage/'+${filename}" height="60"
                        autoplay="autoplay"></video>

没有显示。我有另一种解决方案。 在Storage ServiceImpl中,我使用代码:

private final String storageLocation = this.getClass().getResource("/static/").getPath();

取代:

private final Path storageLocation = Paths.get("upload-storage");

然后 :

File dir = new File(storageLocation + File.separator + "upload-storage");

取代:

File dir = storageLocation.toFile();

然后 :

File serverFile = new File(dir.getAbsolutePath() + File.separator + fileNameTarget);

取代:

String serverFile =  dir.getAbsolutePath()  + File.separator + fileNameTarget ;

使用此解决方案,将在目标文件夹中创建上载存储。

我使用其他控制器BaseController:

public class BaseController {
    public static final String PARAM_BASE_URL = "baseURL";
    public String getBaseURL(HttpServletRequest request){
        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
    }
}

`UploadController扩展了这个BaseController。 我在recupereUpload()中添加了HttpServletRequest请求:

@PostMapping("/upload")
public String recupereUpload(@RequestParam("file") MultipartFile file,
Model model, HttpServletRequest request ){

我添加了recupereUpload发送的模型:

model.addAttribute(PARAM_BASE_URL, getBaseURL(request));

最后,我可以在videoForm.html中看到我的视频代码:

<video id="video" th:src="${baseURL}+'/upload-storage/'+${filename}" height="60" autoplay="autoplay"></video>

我可以关闭Tomcat,关闭Eclipse,关闭机器,然后再次打开:全部保留,我可以看到视频。 但是过了一段时间:一切都消失了。 必须有一个更好的解决方案。 你能帮助我吗 ?

spring-boot video web upload storage
2个回答
0
投票

为什么不使用Spring Content作为解决方案的视频内容部分?这样您就不需要实现任何视频内容处理。 Spring Content将为您提供此功能。要将Spring Content添加到项目中:

将Spring Content添加到类路径中。

pom.hml

<dependency>
    <groupId>com.github.paulcwarren</groupId>
    <artifactId>spring-content-rest-boot-starter</artifactId>
    <version>0.0.10</version>
</dependency>
<dependency>
    <groupId>com.github.paulcwarren</groupId>
    <artifactId>content-fs-spring-boot-starter</artifactId>
    <version>0.0.10</version>
</dependency>

将内容与您的视频实体相关联。

video.Java

@Entity
public class Video {
   ...

   @ContentId
   private String contentId;

   @ContentLength
   private Long contetLen;

   @MimeType
   private String mimeType;

   ...

设置“持久性文件夹”作为视频商店的根目录。这是存储/流式传输上传视频的地方。还要创建一个VideoStore界面,以便向SC描述您希望如何关联内容。

spring boot application.Java

@SpringBootApplication
public class YourSpringBootApplication {

  public static void main(String[] args) {
    SpringApplication.run(YourSpringBootApplication.class, args);
  }

  @Configuration
  @EnableFilesystemStores
  public static class StoreConfig {
    File filesystemRoot() {
        return new File("/path/to/your/videos");
    }

    @Bean
    public FileSystemResourceLoader fsResourceLoader() throws Exception {
      return new FileSystemResourceLoader(filesystemRoot().getAbsolutePath());
    }
  }

  @StoreRestResource(path="videos")
  public interface VideoStore extends ContentStore<Video,String> {
    //
  }
}

这就是在/videos上创建基于REST的视频服务所需的全部内容。基本上,当您的应用程序启动时,Spring Content将查看您的依赖项(查看Spring Content FS / REST),查看您的VideoStore接口并根据文件系统注入该接口的实现。它还将注入一个控制器,该控制器也会将http请求转发给该实现。这样您就不必自己实施任何此类操作。

所以...

POST /videos/{video-entity-id}

使用multipart / form-data请求将视频存储在/path/to/your/videos中,并将其与id为video-entity-id的视频实体相关联。

GET /videos/{video-entity-id}

将再次获取它。这支持部分内容请求或字节范围;即视频流。

等等...支持完整的CRUD。

有一些入门指南here。参考指南是here。还有一个教程视频here。编码位开始大约1/2路。

HTH


0
投票

您是否通过在application.properties文件中添加以下属性来启用上载?

## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true

我写了一篇关于如何使用thymeleaf在spring boot中上传multipart文件的文章。这是用于上传的服务。

   package com.uploadMultipartfile.storage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Service
public class FileSystemStorageService implements StorageService
{
    private final Path rootLocation;

    @Autowired
    public FileSystemStorageService(StorageProperties properties) {
        this.rootLocation = Paths.get(properties.getUploadDir()).toAbsolutePath().normalize();
        try {
            Files.createDirectories(this.rootLocation);
        } catch (Exception ex) {
            throw new StorageException("Could not create the directory where the uploaded files will be stored.", ex);
        }
    }

    @Override
    public String store(MultipartFile file)
    {
        // Normalize file name
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        try
        {
            if (file.isEmpty())
            {
                throw new StorageException("Failed to store empty file " + file.getOriginalFilename());
            }
            // Copy file to the target location (Replacing existing file with the same name)
            Path targetLocation = this.rootLocation.resolve(fileName);
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
            return fileName;
        }
        catch (IOException e)
        {
            throw new StorageException("Failed to store file " + file.getOriginalFilename(), e);
        }
    }
    @Override
    public void init()
    {
        try
        {
            Files.createDirectory(rootLocation);
        }
        catch (IOException e)
        {
            throw new StorageException("Could not initialize storage", e);
        }
    }
}

这是获取应用程序代码的链接。 http://mkaroune.e-monsite.com/pages/spring/spring-boot-multipart-file-upload.html

© www.soinside.com 2019 - 2024. All rights reserved.