【问题标题】:Java : Rename MultiPartFile with unique name and store it to a folder and save the url to databaseJava:使用唯一名称重命名 MultiPartFile 并将其存储到文件夹并将 url 保存到数据库
【发布时间】:2018-10-23 19:59:40
【问题描述】:

我有一个基于 Spring Boot 的后端,一个基于 Angular 5 的前端。 通过 Angular 接收到 MultiPartFile 后,我想用 唯一名称(表的 ID)并将文件存储到文件夹中,然后将此文件的 URL 放入数据库 PostgreSQL。 请帮助我,我测试了很多方法,没有任何好的结果。 我试图将 MultiPartFile 转换为文件,但我不知道该怎么做。 请帮帮我

这是包含处理 MultiPartFile 方法的类:

package smart.syndic.metier;

import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;

@Service
public class StorageService 
{
Logger logger = LoggerFactory.getLogger(this.getClass().getName());
private final Path rootLocation = Paths.get("fichiers/prestataires");

public void store(MultipartFile file) {
    try {

        Files.copy(file.getInputStream(), 
this.rootLocation.resolve(file.getOriginalFilename()), 
StandardCopyOption.REPLACE_EXISTING);
    } catch (Exception e) {
        throw new RuntimeException("FAIL!");
    }
 }

public Resource loadFile(String filename) {
    try {
        Path file = rootLocation.resolve(filename);
        Resource resource = new UrlResource(file.toUri());
        if (resource.exists() || resource.isReadable()) {
            return resource;
        } else {
            throw new RuntimeException("FAIL!");
        }
    } catch (MalformedURLException e) {
        throw new RuntimeException("FAIL!");
    }
 }

public void deleteAll() {
    FileSystemUtils.deleteRecursively(rootLocation.toFile());
 }
}

这里是 RestController:

package smart.syndic.web;

import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;


import  org.springframework.web.servlet.mvc.method.annotation.
MvcUriComponentsBuilder;
import smart.syndic.dao.PrestatairesRepository;
import smart.syndic.dao.PrestatairesTypesRepository;
import smart.syndic.entities.Prestataires;
import smart.syndic.metier.StorageService;

@RestController
@CrossOrigin("*")
public class PrestatairesRestController 
{
@Autowired
private PrestatairesRepository repository;

@Autowired
private PrestatairesTypesRepository repository2;

@Autowired
private StorageService storageService;

private List<String> files = new ArrayList<String>();

@RequestMapping(value="/prestataires/{id}", 
        method=RequestMethod.GET)
public Prestataires getVilles(@PathVariable Long id)
{
    return repository.findOne(id);
}

@RequestMapping(value="/prestataires", 
        method=RequestMethod.POST)
public Prestataires addVilles(Prestataires p,
        @RequestParam("multipartFile") MultipartFile file)
{
    try{
        storageService.store(file);
        files.add(file.getOriginalFilename());
        p.setPhoto("fichiers/prestataires/"+file.getOriginalFilename());

    }catch(Exception e){
        e.printStackTrace();
    }


 p.setPrestatairesTypes(repository2.findOne(p.getPrestatairesTypes()
 .getId()));

    return repository.save(p);              
}

}

这里是实体 Prestataires:

package smart.syndic.entities;

import java.io.Serializable;
import java.util.Collection;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

@Entity
public class Prestataires implements Serializable 
{
@Id @GeneratedValue
private Long id;
private String nom;
private String email;
private String tele;
private String fax;
private String rib;
private String adresse;
private String taches;
private String photo;

//-------------------Constructors--------------------
//-------------------Getters and Setters--------------------


@ManyToOne
@JoinColumn(name="ID_PRESTATAIRES_TYPES")
private PrestatairesTypes prestatairesTypes;
}

【问题讨论】:

  • 您当前的代码有什么问题?

标签: java spring-boot jakarta-ee


【解决方案1】:

如果文件名只是问题,你的代码很好,你只需要使用一些字符串创建文件名,或者像下面那样清理它

//Create custom filename 
String filename = StringUtils.cleanPath(file.getOriginalFilename());
//remove spaces and make lowercase    
filename = filename.toLowerCase().replaceAll(" ", "-");

String filename = p.getId()+"."+file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);

然后在你的复制方法中

Files.copy(file.getInputStream(), this.rootLocation.resolve(filename),
                StandardCopyOption.REPLACE_EXISTING); 

这里是例子

@Service
public class UploadService {

@Value("${app.image.cdn}")
private String imageCDN;

@Value("${app.upload.path}")
private String uploadPath;

private Path rootLocation;


public String store(MultipartFile file) {

    String storedLocation;
    rootLocation = Paths.get(uploadPath);

    String filename = StringUtils.cleanPath(file.getOriginalFilename());
    filename = filename.toLowerCase().replaceAll(" ", "-");

    try {
        if (file.isEmpty()) {
            throw new StorageException("Failed to store empty file " + filename);
        }
        if (filename.contains("..")) {
            // This is a security check
            throw new StorageException(
                    "Cannot store file with relative path outside current directory "
                            + filename);
        }
        Files.copy(file.getInputStream(), this.rootLocation.resolve(filename),
                StandardCopyOption.REPLACE_EXISTING);

        storedLocation = imageCDN+filename;

    }
    catch (IOException e) {
        throw new StorageException("Failed to store file " + filename, e);
    }


    return storedLocation;
}
}

还有你的 application.properties

spring.servlet.multipart.max-file-size=20MB
spring.servlet.multipart.max-request-size=20MB

app.upload.path=/uploads
app.image.cdn=http://yourhost.com/uploads/

还有你的 StorageException 类

public class StorageException extends RuntimeException {

  public StorageException(String message) {
    super(message);
  }

  public StorageException(String message, Throwable cause) {
    super(message, cause);
  }
}

【讨论】:

  • 感谢您的回答。我想用 Prestataires 的唯一名称(表中行的 id)id 重命名 MultiPartFile,然后再将其存储到文件夹中。而不是将文件的 URL 保存到数据库中。像这样的 file.renameTo(String.valueOf(p.getId()))。 p 是 Prestataires 的一个实例。
  • @beyyatoabdellah - 重命名是另一种选择。为什么不首先创建正确的名称。检查更新的答案。
  • 我会试试这个,我会通知你结果。谢谢先生。
  • 我在后端有这个错误:smart.syndic.metier.StorageException:无法存储文件 null.png 原因:java.nio.file.NoSuchFileException:\uploads\null.png。我认为 null 的问题是文件用 Prestataires 的 id 重命名为 null,因为它将在 respository.save(p) 的时刻生成;所以在这个操作之前它是空的。我也不想只有一个文件夹来保存文件,我想有多个。
  • 是的,修复空 id 并为多个目录创建文件夹并相应地更改文件名。
【解决方案2】:

这里是 RestController

package smart.syndic.web;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpHeaders;
 import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import smart.syndic.dao.PrestatairesRepository;
import smart.syndic.dao.PrestatairesTypesRepository;
import smart.syndic.entities.Prestataires;
import smart.syndic.metier.StorageService;

@RestController
@CrossOrigin("*")
public class PrestatairesRestController 
{
@Autowired
private PrestatairesRepository repository;

@Autowired
private PrestatairesTypesRepository repository2;

@Autowired
private StorageService storageService;

private List<String> files = new ArrayList<String>();

@RequestMapping(value="/prestataires/{id}", 
        method=RequestMethod.GET)
public Prestataires getVilles(@PathVariable Long id)
{
    return repository.findOne(id);
}

@RequestMapping(value="/prestataires", 
        method=RequestMethod.POST)
public Prestataires addVilles(Prestataires p,
        @RequestParam("multipartFile") MultipartFile file)
{
    Prestataires pp = null;
    try{
        pp = repository.save(p);
        storageService.store(file, "prestataires",pp);
        files.add(file.getOriginalFilename());


    }catch(Exception e){
        e.printStackTrace();
    }

    p.setPrestatairesTypes(repository2.findOne(p.getPrestatairesTypes().getId()));
    updateVilles(p.getId(), p);
    return pp;              
}

@RequestMapping(value="/prestataires/{id}", 
        method=RequestMethod.PUT)
public Prestataires updateVilles(
        @PathVariable Long id,
        @RequestBody Prestataires v)
{

    v.setId(id);
    return repository.save(v);
}
}

存储服务

package smart.syndic.metier;

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

import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
 import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;

import smart.syndic.entities.Prestataires;

@Service
public class StorageService 
{
private String imageCDN = "http://www.yourHost.com/fichiers/";

private Path rootLocation;

public String store(MultipartFile file, String chemin, Prestataires p) {
    String storedLocation = null;
    rootLocation = Paths.get("fichiers/"+chemin+"/");
    String filename = null;

    filename = p.getId()+"."+file.getOriginalFilename()
    .substring(
            file.getOriginalFilename().lastIndexOf(".") + 1);


    try {
        if(file.isEmpty()){
            throw new StorageException("Failed to store Empty"
                    + " File "+filename);
        }
        if(filename.contains(".."))
        {
            throw new StorageException("Cannot store file with relative path "
                    + "outside current directory "+filename);
        }

        Files.copy(file.getInputStream(), this.rootLocation.resolve(filename), 
                StandardCopyOption.REPLACE_EXISTING);
        storedLocation = imageCDN + filename;
    } catch (IOException e) {
        throw new StorageException("Failed to store file " + filename, e);
    }
    p.setPhoto("fichiers/"+chemin+"/"+filename);
    return storedLocation;
}

public Resource loadFile(String filename) {
    try {
        Path file = rootLocation.resolve(filename);
        Resource resource = new UrlResource(file.toUri());
        if (resource.exists() || resource.isReadable()) {
            return resource;
        } else {
            throw new RuntimeException("FAIL!");
        }
    } catch (MalformedURLException e) {
        throw new RuntimeException("FAIL!");
    }
}

public void deleteAll() {
    FileSystemUtils.deleteRecursively(rootLocation.toFile());
}
}

其他类没有变化,包括前端

【讨论】:

  • 在邮递员中测试 api 时出现错误,例如“无法转换类型为 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' 的属性值。请帮助我修复此错误@beyyatoabdellah
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多