/* * Copyright 2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.greglturnquist.learningspringboot.images; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.Principal; import java.util.UUID; import io.micrometer.core.instrument.MeterRegistry; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.http.codec.multipart.FilePart; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; import org.springframework.util.FileCopyUtils; import org.springframework.util.FileSystemUtils; /** * @author Greg Turnquist */ @Service public class ImageService { private static String UPLOAD_ROOT = "upload-dir"; private final ResourceLoader resourceLoader; private final ImageRepository imageRepository; // tag::metric-1[] private final MeterRegistry meterRegistry; public ImageService(ResourceLoader resourceLoader, ImageRepository imageRepository, MeterRegistry meterRegistry) { this.resourceLoader = resourceLoader; this.imageRepository = imageRepository; this.meterRegistry = meterRegistry; } // end::metric-1[] public Flux<Image> findAllImages() { return imageRepository.findAll() .log("findAll"); } public Mono<Resource> findOneImage(String filename) { return Mono.fromSupplier(() -> resourceLoader.getResource( "file:" + UPLOAD_ROOT + "/" + filename)) .log("findOneImage"); } // tag::metric-2[] public Mono<Void> createImage(Flux<FilePart> files, Principal auth) { return files .log("createImage-files") .flatMap(file -> { Mono<Image> saveDatabaseImage = imageRepository.save( new Image( UUID.randomUUID().toString(), file.filename(), auth.getName())) .log("createImage-save"); // end::metric-2[] Mono<Void> copyFile = Mono.just(Paths.get(UPLOAD_ROOT, file.filename()).toFile()) .log("createImage-picktarget") .map(destFile -> { try { destFile.createNewFile(); return destFile; } catch (IOException e) { throw new RuntimeException(e); } }) .log("createImage-newfile") .flatMap(file::transferTo) .log("createImage-copy") .then(Mono.fromRunnable(() -> meterRegistry .summary("files.uploaded.bytes") .record(Paths.get(UPLOAD_ROOT, file.filename()).toFile().length()) )); return Mono.when(saveDatabaseImage, copyFile) .log("createImage-when"); }) .log("createImage-flatMap") .then() .log("createImage-done"); } // tag::delete[] @PreAuthorize("hasRole('ADMIN') or " + "@imageRepository.findByName(#filename).owner " + "== authentication.name") public Mono<Void> deleteImage(String filename) { // end::delete[] Mono<Void> deleteDatabaseImage = imageRepository .findByName(filename) .log("deleteImage-find") .flatMap(imageRepository::delete) .log("deleteImage-record"); Mono<Object> deleteFile = Mono.fromRunnable(() -> { try { Files.deleteIfExists(Paths.get(UPLOAD_ROOT, filename)); } catch (IOException e) { throw new RuntimeException(e); } }) .log("deleteImage-file"); return Mono.when(deleteDatabaseImage, deleteFile) .log("deleteImage-when") .then() .log("deleteImage-done"); } /** * Pre-load some fake images * * @return Spring Boot {@link CommandLineRunner} automatically run after app context is loaded. */ @Bean CommandLineRunner setUp() throws IOException { return (args) -> { FileSystemUtils.deleteRecursively(new File(UPLOAD_ROOT)); Files.createDirectory(Paths.get(UPLOAD_ROOT)); FileCopyUtils.copy("Test file", new FileWriter(UPLOAD_ROOT + "/learning-spring-boot-cover.jpg")); FileCopyUtils.copy("Test file2", new FileWriter(UPLOAD_ROOT + "/learning-spring-boot-2nd-edition-cover.jpg")); FileCopyUtils.copy("Test file3", new FileWriter(UPLOAD_ROOT + "/bazinga.png")); }; } }