38.1 Extract Profile Image operation into separate ProfileImageService (#38 save profile images to S3)

This commit is contained in:
Art
2021-09-28 23:17:58 +03:00
parent 65b29ce2a1
commit ebcb900cdf
7 changed files with 103 additions and 38 deletions

View File

@ -22,7 +22,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.io.IOException;
import java.util.UUID;
import static org.springframework.http.HttpStatus.OK;
@ -110,7 +109,7 @@ public class UserResource {
}
@GetMapping(path = "{userId}/profile-image/{filename}", produces = MediaType.IMAGE_JPEG_VALUE)
public byte[] getProfileImageByUserId(@PathVariable UUID userId, @PathVariable String filename) throws IOException {
public byte[] getProfileImageByUserId(@PathVariable UUID userId, @PathVariable String filename) {
return userService.getImageByUserId(userId, filename);
}

View File

@ -117,8 +117,8 @@ public class ExceptionHandling {
return createHttpResponse(NOT_FOUND, exception.getMessage());
}
@ExceptionHandler(IOException.class)
public ResponseEntity<HttpResponse> iOException(IOException exception) {
@ExceptionHandler({IOException.class, ImageStorageException.class})
public ResponseEntity<HttpResponse> fileRelatedException(Exception exception) {
log.error(exception.getMessage());
return createHttpResponse(INTERNAL_SERVER_ERROR, ERROR_PROCESSING_FILE);
}

View File

@ -0,0 +1,11 @@
package net.shyshkin.study.fullstack.supportportal.backend.exception.domain;
public class ImageStorageException extends RuntimeException {
public ImageStorageException(String message) {
super(message);
}
public ImageStorageException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,61 @@
package net.shyshkin.study.fullstack.supportportal.backend.service;
import lombok.extern.slf4j.Slf4j;
import net.shyshkin.study.fullstack.supportportal.backend.exception.domain.ImageStorageException;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
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.util.UUID;
import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant.*;
@Slf4j
@Service
@Profile("!image-s3")
public class FileSystemProfileImageService implements ProfileImageService {
@Override
public byte[] retrieveProfileImage(UUID userId, String filename) {
Path userProfileImagePath = Paths
.get(USER_FOLDER, userId.toString(), filename);
try {
return Files.readAllBytes(userProfileImagePath);
} catch (IOException exception) {
throw new ImageStorageException("Can not retrieve image for user " + userId + " from file " + filename, exception);
}
}
@Override
public String persistProfileImage(UUID userId, MultipartFile profileImage, String filename) {
Path userFolder = Paths.get(USER_FOLDER, userId.toString());
try {
if (Files.notExists(userFolder)) {
Files.createDirectories(userFolder);
log.debug(DIRECTORY_CREATED);
}
profileImage.transferTo(userFolder.resolve(USER_IMAGE_FILENAME));
log.debug(FILE_SAVED_IN_FILE_SYSTEM + profileImage.getOriginalFilename());
} catch (IOException exception) {
throw new ImageStorageException("Can not persist image for user " + userId + " from file " + profileImage, exception);
}
return null;
}
@Override
public void clearUserStorage(UUID userId) {
Path userFolder = Paths.get(USER_FOLDER, userId.toString());
try {
FileSystemUtils.deleteRecursively(userFolder);
} catch (IOException exception) {
throw new ImageStorageException("Can not delete folder for user " + userId, exception);
}
}
}

View File

@ -0,0 +1,15 @@
package net.shyshkin.study.fullstack.supportportal.backend.service;
import org.springframework.web.multipart.MultipartFile;
import java.util.UUID;
public interface ProfileImageService {
byte[] retrieveProfileImage(UUID userId, String filename);
String persistProfileImage(UUID userId, MultipartFile profileImage, String filename);
void clearUserStorage(UUID userId);
}

View File

@ -7,7 +7,6 @@ import org.springframework.data.domain.Pageable;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
public interface UserService extends UserDetailsService {
@ -32,7 +31,7 @@ public interface UserService extends UserDetailsService {
User updateProfileImage(UUID userId, MultipartFile profileImage);
byte[] getImageByUserId(UUID userId, String filename) throws IOException;
byte[] getImageByUserId(UUID userId, String filename);
byte[] getDefaultProfileImage(UUID userId);
}

View File

@ -19,17 +19,12 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@ -55,6 +50,7 @@ public class UserServiceImpl implements UserService {
private final EmailService emailService;
private final UserMapper userMapper;
private final RestTemplateBuilder restTemplateBuilder;
private final ProfileImageService profileImageService;
private RestTemplate restTemplate;
@ -188,30 +184,17 @@ public class UserServiceImpl implements UserService {
throw new NotAnImageFileException(profileImage.getOriginalFilename() + " is not an image file. Please upload an image");
}
Path userFolder = Paths.get(USER_FOLDER, user.getUserId().toString());
try {
if (Files.notExists(userFolder)) {
Files.createDirectories(userFolder);
log.debug(DIRECTORY_CREATED);
}
profileImage.transferTo(userFolder.resolve(USER_IMAGE_FILENAME));
log.debug(FILE_SAVED_IN_FILE_SYSTEM + profileImage.getOriginalFilename());
user.setProfileImageUrl(generateProfileImageUrl(user.getUserId()));
userRepository.save(user);
String imageUrl = profileImageService.persistProfileImage(user.getUserId(), profileImage, USER_IMAGE_FILENAME);
} catch (IOException exception) {
log.error("Can't save to file", exception);
}
if (imageUrl == null)
imageUrl = generateProfileImageUrl(user.getUserId());
user.setProfileImageUrl(imageUrl);
userRepository.save(user);
}
private void deleteProfileImageFolder(User user) {
Path userFolder = Paths.get(USER_FOLDER, user.getUserId().toString());
try {
FileSystemUtils.deleteRecursively(userFolder);
} catch (IOException exception) {
log.error("Can't delete folder", exception);
}
private void clearUserStorage(User user) {
profileImageService.clearUserStorage(user.getUserId());
}
@Override
@ -243,7 +226,7 @@ public class UserServiceImpl implements UserService {
.findByUserId(userId)
.orElseThrow(() -> new UserNotFoundException("User was not found"));
deleteProfileImageFolder(userToBeDeleted);
clearUserStorage(userToBeDeleted);
userRepository.delete(userToBeDeleted);
}
@ -270,15 +253,12 @@ public class UserServiceImpl implements UserService {
}
@Override
public byte[] getImageByUserId(UUID userId, String filename) throws IOException {
public byte[] getImageByUserId(UUID userId, String filename) {
if (!userRepository.existsByUserId(userId)) {
throw new UserNotFoundException(USER_NOT_FOUND_MSG);
}
Path userProfileImagePath = Paths
.get(USER_FOLDER, userId.toString(), filename);
return Files.readAllBytes(userProfileImagePath);
return profileImageService.retrieveProfileImage(userId, filename);
}
@Override