如何将MultipartFile转换为所需的类型byte []

时间:2019-05-01 11:05:10

标签: java hibernate spring-boot spring-mvc

我正在使用Spring Boot使用Spring Data-Jpa。我有一个由多个部分组成的表单,用于将文件上载到具有其他字段(如firstName,lastName,email,photo)的数据库。但是我不断收到此错误消息,将多部分文件转换为所需的byte []类型。如何将图像文件从多部分文件转换为byte []类型?

这是我的ControllerClass:

    @PostMapping("/save")
public String saveUserWithPhoto(@ModelAttribute("user") User user,
                         @RequestParam("file") MultipartFile file) throws IOException {
    String fileName = StringUtils.cleanPath(file.getOriginalFilename());

    if (!(fileName == null) || fileName.contains("..")) {       
        byte[] photoBytes = file.getBytes();     
        user.setPhoto(photoBytes);
        userService.saveUserWithPhoto(user);
        return "redirect:/profile";
    }
    .......
    return "redirect:/new-user";

}

这是我的服务舱:

  @Override
public void saveUserWithPhoto(User theUser){
    userRepository.save(theUser);
}

这是我的EntityClass:

@Entity
@Table(name = "users")
public class User{

    @Id
    @GeneratedValue
    private long id;

    @Column(name = "first_name")
    private String firstName;

   @Column(name = "last_name")
    private String lastName;

    @Column(name = "email")
    private String email;

    @Lob
    @Column(name="photo")
    private byte[] photo;

}

4 个答案:

答案 0 :(得分:0)

MultipartFile 包含内容文件的byte array。您可以通过getBytes()方法使用。

application.properties 中添加:

spring.servlet.multipart.enabled=true

或使用 YAML 可以添加:

spring:
  servlet:
    multipart:
      enabled: true

并且可以像这样从MultipartFile获取字节数组:

MultipartFile  file;
//for your segment file fill from client side(in request)
byte [] content = file.getBytes();

答案 1 :(得分:0)

我可能会误会,但是我相信Spring会尝试自动映射传递到端点的整个“ User”对象,但由于传入的用户对象中没有“ photo”字段而失败,或无法将该字段自动转换为byte []。

为了测试是否是这种情况,您可以执行以下任一操作 1)如果传入的User对象没有照片字段,请将其从User对象中删除 2)如果是,并且作为MultipartFile进入,则从byte []更改为multipartfile。

我知道这些都不会帮助您将其放入数据库,但是它将帮助您确定这实际上是否是您的问题。然后,我很乐意进一步协助。

编辑

好的,我一直在努力使它正常工作,最后我明白了!请在下面查看我的更改。 像这样更改控制器端点

@PostMapping
@ResponseBody
public void postUser(@ModelAttribute User user, @RequestParam("file") MultipartFile file) throws IOException {
        user.setPhotoByteArray(file.getBytes()); 
       //Do Service Call here(user)
    }

我这样更新了User对象。

@Entity(name = "users")
public class User {
    @Id
    @GeneratedValue
    private long id;
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "last_name")
    private String lastName;
    @Column(name = "email")
    private String email;
    @Column(name = "photo")
    private byte[] photoByteArray;

    public User(long id, String firstName, String lastName, String email) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }

就是这样!我通过邮递员发送带有所有必要字段的表单数据请求来验证此工作是否正常,我还添加了以下几行以将文件保存在本地目录中,以便我可以打开它以确认它正确处理了我通过的图像邮递员

FileUtils.writeByteArrayToFile(new File("test.png"), user.getPhotoByteArray());

我还向您的实体添加了一个构造函数,这样当它从model属性创建对象时,它就可以开始为null,以后可以进行设置。

如果您仍然遇到问题或疑问,请告诉我。

答案 2 :(得分:0)

Spring不会将字节存储在类本身中,而是会强制您从该类中打开流。

  

文件内容要么存储在内存中,要么临时存储在磁盘上。   无论哪种情况,用户都有责任将文件内容复制到   会话级别或持久性存储(如果需要)。临时的   在请求处理结束时将清除存储。

我通常使用以下代码将中间存储器存储到文件或内存中:

private final Path rootLocation;
try (InputStream inputStream = file.getInputStream()) {
  byte[] in = StreamUtils.copyToByteArray(inputStream);
  //Files.copy(inputStream, this.rootLocation.resolve(filename),
  //                StandardCopyOption.REPLACE_EXISTING);
}

当然,您可以根据需要使用任何内容来从流中创建byte []。如果您在春季,可以推荐StreamUtils

答案 3 :(得分:0)

作为一种替代方法,我建议您看一下社区项目Spring Content。该项目旨在解决您的问题,为存储非结构化数据提供了一种抽象,为您注入了服务和控制器实现,因此您无需自己实现,也可以将上载的内容与Spring Data实体相关联。

此外,所有Spring Content存储模块(包括JPA)都基于流,因此能够处理byte[]方法无法实现的非常大的文件。

将其添加到项目中将如下所示:

  

pom.xml(假设Maven)

    <!-- Java API -->
    <!-- just change this depdendency if you want to store somewhere else -->
    <dependency>
        <groupId>com.github.paulcwarren</groupId>
        <artifactId>spring-content-jpa-boot-starter</artifactId>
        <version>0.8.0</version>
    </dependency>
    <!-- REST API -->
    <dependency>
        <groupId>com.github.paulcwarren</groupId>
        <artifactId>spring-content-rest-boot-starter</artifactId>
        <version>0.8.0</version>
    </dependency>

定义内容存储库(与Spring Data Repository相同的概念):

  

UserContentStore.java

  @StoreRestResource(path="photos")
  public interface UserPhotoStore extends ContentStore<User, UUID> {
  }

将内容与您的User实体相关联:

@Entity(name = "users")
public class User {
    @Id
    @GeneratedValue
    private long id;
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "last_name")
    private String lastName;
    @Column(name = "email")
    private String email;

    // Spring Content annotations
    @ContentId
    private UUID contentId;

    @ContentLength
    private Long contentLen;

    @MimeType
    private String mimeType;

就是这样。 UserPhotoStore本质上是一个通用的Spring ResourceLoader。 spring-content-jpa-boot-starter依赖关系将导致Spring Content注入该接口的基于jpa的实现,而spring-content-rest-boot-starter依赖关系将导致Spring Content注入@Controller的实现,该实现将HTTP请求转发到UserPhotoStore服务的方法。

现在,您将在/photoso/{userId}处获得基于REST的全功能(POST,PUT,GET,DELETE)文件服务,该服务将使用您的UserPhotoStore将文件存储(并检索)到您的数据库并将它们与您的用户实体相关联。

所以:

curl -F ‘file=@/path/to/local/file.jpg’ /photos/{userId}

将上传/path/to/local/file.jpg,将其存储在您的数据库中,并将其与用户实体userId关联。

并且:

curl /photos/{userId}

将再次检索它。

可以按照in the docs(关联模式)中所述的各种方式来关联内容。

HTH