当前位置: 首页 > 知识库问答 >
问题:

如何将文件上传集成到Spring Data REST存储库中?

宦子琪
2023-03-14

我想将文件上传和下载集成到Spring Data REST存储库中。

我有一个<code>DataFile</code>类(见下面的实现),它总是伴随着一些元数据。有一个DataFileRepository来存储有关元数据和文件之间关系的信息。

用户应该能够以web应用程序的形式上载文件和元数据。元数据应存储在html" target="_blank">数据库表中,同时文件被上传到某个文件存储,然后文件路径再次存储在实体中。

我想使用Spring Data REST执行此操作。我的方法是在DataFile实体中包含一个MultipartFile并将其标记为@瞬态@RestResource(导出=false),这样它就不在实体的任何表示中,但可以上传。上传时,AbstractRepositoryEventListener会覆盖onBeforeCreate并在此步骤中上传文件。

但是使用这种方法,我很难将文件包含在HTTP请求体中(一个< code>DataFile的JSON表示)。

其他方法包括实现一个< code > @ rest repository controller 来扩充< code>DataFileRepository,但前面提到的方法是我最喜欢的。

使用SpringDataREST(存储库)进行文件上传的最佳实践是什么?

@Data
@Entity
@Table(name = "data_files")
public class DataFile {
    @Id
    @GeneratedValue
    @Setter(AccessLevel.NONE)
    private long identifier;

    @NotBlank
    @Column(name = "path")
    @RestResource(exported = false)
    private String path;

    @Embedded
    private Metadata metadata;

    public DataFile() {
        metadata = new Metadata();
    }

    public DataFile(Metadata metadata) {
        this.metadata = metadata;
    }
}

共有1个答案

唐钊
2023-03-14

我没有找到只使用SpringDataREST的方法,但这个解决方案很好地集成到存储库中,不需要太多手写代码。

下面是针对与问题不同的项目的此类解决方案的示例,但您应该明白这一点。

基本上创建一个@BasePathAwareController,使其适应您可能为Spring Data REST设置的基本路径。然后在控制器内创建具有适当路径的映射。在本例中,有一个@PostMapping,其中包含指向导师存储库的路径和在此上载的相关附件的子路径。

您可以在这个方法中进行验证,或者在存储库的save方法中引入一个方面。

在这种情况下,我使用了一个方面将处理应用于存储库的 save() 方法的每次调用。

@BasePathAwareController
@ExposesResourceFor(Tutor.class)
public class TutorRepositoryController {
    private AttachmentAssembler attachmentAssembler;

    private AttachmentRepository attachmentRepository;

    private TutorRepository tutorRepository;

    private RepositoryEntityLinks entityLinks;

    @Autowired
    public TutorRepositoryController(AttachmentAssembler attachmentAssembler,
                                     AttachmentRepository attachmentRepository,
                                     TutorRepository tutorRepository,
                                     RepositoryEntityLinks entityLinks) {
        this.attachmentAssembler  = attachmentAssembler;
        this.attachmentRepository = attachmentRepository;
        this.tutorRepository      = tutorRepository;
        this.entityLinks          = entityLinks;
    }

    @PostMapping(value = "/tutors/{id}/attachments/{name}")
    public ResponseEntity<EntityModel<Attachment>> saveAttachment(@RequestParam("data") MultipartFile file,
                                                                  @PathVariable long id,
                                                                  @PathVariable String name) {
        Tutor thisTutor = tutorRepository.findById(id);
        File tempFile;
        try {
            tempFile = File.createTempFile(FilenameUtils.getBaseName(file.getOriginalFilename()),
                                           FilenameUtils.getExtension(file.getOriginalFilename()));

            StreamUtils.copy(file.getResource().getInputStream(), new FileOutputStream(tempFile));
        } catch (IOException e) {
            throw new RuntimeException("Could not create temporary file of uploaded file.");
        }

        Attachment saved =
                    attachmentRepository.save(new Attachment(name, thisTutor, tempFile, file.getOriginalFilename()));

        return ResponseEntity.created(entityLinks.linkForItemResource(Attachment.class, saved.getIdentifier())
                                                  .toUri()).body(attachmentAssembler.toModel(saved));
    }
}

这是处理文件上载的方面的代码。

@Aspect
@Component
public class TutorRepositoryAspect {
    private Logger log = LoggerFactory.getLogger(TutorRepositoryAspect.class.getName());

    private AttachmentRepository attachmentRepository;

    private ApplicationConfiguration configuration;

    private S3Service s3Service;

    @Autowired
    public TutorRepositoryAspect(AttachmentRepository attachmentRepository,
                                 ApplicationConfiguration configuration,
                                 S3Service s3Service) {
        this.attachmentRepository = attachmentRepository;
        this.configuration        = configuration;
        this.s3Service            = s3Service;
    }

    @Pointcut(value = "execution(* com.example.tutor.backend.repository.attachment.AttachmentRepository.save(..)) && args(attachment)")
    private void repositorySave(Attachment attachment) {
    }

    @Before(value = "repositorySave(attachment)", argNames = "attachment")
    private Attachment beforeSave(Attachment attachment) {
        log.info("Received request to add attachment to tutor \"{}\".", attachment.getIdentifier());

        File file = attachment.getFile();

        // Validation

        String filePath = attachment.getAttachedTo().getIdentifier() + "-" + attachment.getName() + "-"
                          + attachment.getOriginalFileName();

        if (s3Service.isFilePresent(filePath)) {
            log.error("Could not upload file as there is a file already with the same name.");
            throw new IllegalArgumentException("File is already present.");
        }

        String s3Path = s3Service.uploadFile(file, filePath);

        attachment.setFilePath(s3Path);

        // This attachment is now being saved to database.
        return attachment;
    }
}
 类似资料:
  • 我不想公开我的模型类(jpa实体),而是用不同的数据传输对象(DTO)公开它们属性的不同子集。这个想法是不切实际的 例子: 实体: JpaRepository: DTO: D到积垢积存物: 实施: 一般: 在本例中,我想用Spring数据REST公开GroupDtoDao。 在其他bean中,我可以自动连接GroupDto和GroupDto,所以两者都由Spring的上下文管理。如果我不使用@Re

  • > 我正在向我的某个 Azure Api 管理 API 发送 POST 请求 在此帖子请求中,有一个 json 正文,其中包含 base64 编码的数据(zip 文件),如以下示例所示: {“foo”:“bar”,“data”:“your-base64-string”} 在API策略中,我想向Azure Storage REST API发送一个单独的请求,将上面提到的base64字符串保存为一个z

  • 我正在尝试上传文件到谷歌存储在多块但签名的URL。 以下是我正在执行的步骤: 使用node.js创建可恢复的上载URL 示例URL: 使用这些标头: HTTPS响应: 使用这些标头: HTTPS响应:包含数据: 根据文档,上述响应应该是,而不是。 我对这些API调用做错了什么?

  • 问题内容: 我试图了解如何使用Node.js在Firebase Storage中上传文件。我的第一次尝试是使用Firebase库: 但是事实证明,Firebase无法从服务器端上传文件,正如在文档中明确指出的那样: Firebase存储不包含在服务器端Firebase npm模块中。相反,您可以使用gcloud Node.js客户端。 在代码中,您可以使用以下方式访问存储分区: 我们可以在没有Go

  • 我目前面临的问题与谷歌云存储, 我能够下载对象上传到谷歌云存储,但当天晚些时候,我开始得到的错误,因为"这个网站无法到达" 我在c#中以编程方式创建了一个bucket,代码如下: 因此,创建存储桶的设置如下: 默认存储类别:多地区 位置:美国(美国多个地区) 公共访问:每个对象 生命周期:无 访问控制模型:存储桶策略

  • 问题内容: 如何复制到外部存储保持,以便以后可以共享首选项。 试图读取并另存为一个文件,创建了类型,但我需要一个。想过遍历应用程序的内部存储和复制文件,然后将其放入外部存储,但这可能太复杂了。 真的很想知道是否存在一种简单而明智的方式来传递`sharedpreferences。 问题答案: 使用此代码, 并取回它, 注意 使用此代码只能处理字符串类型首选项,

  • 我可以使用firebase-admin通过nodejs将一个文件上传到我的firebase存储桶,但当我进入firebase UI时,我无法打开该文件。我注意到,通过firebase UI上传的文件将自动生成访问令牌,但对于通过NodeJS上传的文件没有。 我已经尝试了几种方法,比如用DownloadToken设置元数据,并在上传后将文件公开。没有一个起作用。 我如何通过API调用生成访问令牌,而

  • 如果有人帮我解决这个问题,我会非常感激。 我正在为我的项目使用codeigniter框架。并想将我的图像上传到amazon s3桶中。当我尝试使用S3.php文件时 string(92)“不支持您提供的授权机制。请使用AWS4-HMAC-SHA256。” 有人能帮我解决这个问题吗。