Skip to content

Commit

Permalink
Merge branch 'main' into wonjeong#44-improve-image-deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
NARUBROWN authored Jan 29, 2024
2 parents 7f6578a + 46ede8e commit 6c669c4
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 54 deletions.
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ dependencies {
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis:2.7.14'
// spring cache
// Spring cache
implementation 'org.springframework.boot:spring-boot-starter-cache:2.7.14'
// Snappy Java
implementation 'org.xerial.snappy:snappy-java:1.1.10.5'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableRedisRepositories
@EnableRedisRepositories(basePackages = "server.inuappcenter.kr.data.redis")
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import server.inuappcenter.kr.data.utils.ImageUtils;

import javax.persistence.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Entity
@Getter
Expand Down Expand Up @@ -73,11 +72,6 @@ public void isThumbnail() {
this.isThumbnail = true;
}

// 자원의 현재 위치를 반환하는 메소드
public String getLocation(HttpServletRequest request, Image image) {
return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/image/photo/" + image.getId().toString();
}

public Image returnMultipartToEntity(MultipartFile multipartFile) throws IOException {
return new Image(multipartFile.getOriginalFilename(), ImageUtils.compressImage(multipartFile.getBytes()), multipartFile.getSize());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package server.inuappcenter.kr.data.redis.domain;

import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;


@Getter
@RedisHash(value = "image")
public class ImageRedis {
@Id
private Long id;
private final byte[] imageData;

public ImageRedis(Long id, byte[] imageData) {
this.id = id;
this.imageData = imageData;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package server.inuappcenter.kr.data.repository.redis;
package server.inuappcenter.kr.data.redis.repository;

import org.springframework.data.repository.CrudRepository;
import server.inuappcenter.kr.data.dto.response.BoardResponseDto;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package server.inuappcenter.kr.data.redis.repository;

import org.springframework.data.repository.CrudRepository;
import server.inuappcenter.kr.data.redis.domain.ImageRedis;

public interface ImageRedisRepository extends CrudRepository<ImageRedis, Long> {
}
45 changes: 9 additions & 36 deletions src/main/java/server/inuappcenter/kr/data/utils/ImageUtils.java
Original file line number Diff line number Diff line change
@@ -1,48 +1,21 @@
package server.inuappcenter.kr.data.utils;

import java.io.ByteArrayOutputStream;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import org.xerial.snappy.Snappy;
import java.io.IOException;

public class ImageUtils {

public static byte[] compressImage(byte[] data) {
Deflater deflater = new Deflater();
deflater.setLevel(Deflater.BEST_COMPRESSION);
deflater.setInput(data);
deflater.finish();

ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4*1024];

while (!deflater.finished()) {
int size = deflater.deflate(tmp);
outputStream.write(tmp, 0, size);
}

try {
outputStream.close();
} catch (Exception ignored) {

}
public class ImageUtils {

return outputStream.toByteArray();
public static byte[] compressImage(byte[] data) throws IOException {
return Snappy.compress(data);
}

public static byte[] decompressImage(byte[] data) {
Inflater inflater = new Inflater();
inflater.setInput(data);
ByteArrayOutputStream outputSteam = new ByteArrayOutputStream(data.length);
byte[] tmp = new byte[4*1024];

try {
while (!inflater.finished()) {
int count = inflater.inflate(tmp);
outputSteam.write(tmp, 0, count);
}
outputSteam.close();
} catch (Exception ignored) {
return Snappy.uncompress(data);
} catch(Exception e) {
throw new RuntimeException(e.getMessage());
}
return outputSteam.toByteArray();
}

}
19 changes: 17 additions & 2 deletions src/main/java/server/inuappcenter/kr/service/ImageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import server.inuappcenter.kr.data.domain.board.Board;
import server.inuappcenter.kr.data.domain.board.Image;
import server.inuappcenter.kr.data.repository.BoardRepository;
import server.inuappcenter.kr.data.redis.domain.ImageRedis;
import server.inuappcenter.kr.data.redis.repository.ImageRedisRepository;
import server.inuappcenter.kr.data.repository.ImageRepository;
import server.inuappcenter.kr.data.utils.ImageUtils;
import server.inuappcenter.kr.exception.customExceptions.CustomNotFoundException;
Expand All @@ -20,11 +22,24 @@
public class ImageService {
private final ImageRepository imageRepository;
private final BoardRepository<Board> boardRepository;
private final ImageRedisRepository imageRedisRepository;

@Transactional(readOnly = true)
public byte[] getImage(Long id) {
Image foundImage = imageRepository.findById(id).orElseThrow(() -> new CustomNotFoundException("The requested ID was not found."));
return ImageUtils.decompressImage(foundImage.getImageData());
return imageRedisRepository.findById(id)
.map(imageRedis -> ImageUtils.decompressImage(imageRedis.getImageData()))
.orElseGet(() -> {
Image foundImage = imageRepository.findById(id).orElseThrow(() -> new CustomNotFoundException("The requested ID was not found."));
ImageRedis imageRedis = new ImageRedis(foundImage.getId(), foundImage.getImageData());
imageRedisRepository.save(imageRedis);
return ImageUtils.decompressImage(foundImage.getImageData());
});
}

@Transactional
public void deleteByImageId(Long id) {
imageRedisRepository.deleteById(id);
imageRepository.deleteById(id);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import server.inuappcenter.kr.data.domain.board.Image;
import server.inuappcenter.kr.data.dto.request.BoardRequestDto;
import server.inuappcenter.kr.data.dto.response.BoardResponseDto;
import server.inuappcenter.kr.data.redis.repository.ImageRedisRepository;
import server.inuappcenter.kr.data.repository.BoardRepository;
import server.inuappcenter.kr.data.repository.ImageRepository;
import server.inuappcenter.kr.data.repository.redis.BoardResponseRedisRepository;
import server.inuappcenter.kr.data.redis.repository.BoardResponseRedisRepository;
import server.inuappcenter.kr.exception.customExceptions.CustomNotFoundException;

import javax.servlet.http.HttpServletRequest;
Expand All @@ -26,6 +27,7 @@ public class BoardService {
private final ImageRepository imageRepository;
private final HttpServletRequest request;
private final BoardResponseRedisRepository<BoardResponseDto> boardResponseRedisRepository;
private final ImageRedisRepository imageRedisRepository;

@Transactional(readOnly = true)
public BoardResponseDto findBoard(Long id) {
Expand All @@ -47,13 +49,15 @@ public CommonResponseDto saveBoard(BoardRequestDto boardRequestDto) {

@Transactional
public CommonResponseDto deleteBoard(Long id) {
boardResponseRedisRepository.deleteById(id);
boardRepository.findById(id).orElseThrow(() -> new CustomNotFoundException("ID에 해당되는 보드가 없습니다."));
boardRepository.deleteById(id);
return new CommonResponseDto("id: " + id + " has been successfully deleted.");
}

@Transactional
public CommonResponseDto updateBoard(Long board_id, List<Long> image_id, BoardRequestDto boardRequestDto) {
// 캐시에서 보드를 삭제한다.
boardResponseRedisRepository.deleteById(board_id);
Board foundBoard = boardRepository.findById(board_id).orElseThrow(() -> new CustomNotFoundException("The requested ID was not found."));
// 사용자가 multipart를 같이 보냈는지 확인
Expand All @@ -74,6 +78,9 @@ public CommonResponseDto updateBoard(Long board_id, List<Long> image_id, BoardRe
foundImageIds.add(image.getId());
}

// 캐시에서 이미지를 삭제한다.
imageRedisRepository.deleteAllById(foundImageIds);

// 찾아진 ID 목록에 존재하지 않는 ID를 얻어야 하기 때문에 없는 이미지 ID 목록을 만들어줌
List<Long> missingImageIds = new ArrayList<>();
for (Long id : image_id) {
Expand Down
10 changes: 5 additions & 5 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
spring:
redis:
port: 5379
host: na2ru2.me
port: 6379
host: 192.168.55.22
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: dev
url: jdbc:mysql://na2ru2.me:6306/appcenter
url: jdbc:mysql://192.168.55.22/appcenter
password: test1234
jpa:
hibernate:
Expand All @@ -20,5 +20,5 @@ spring:
mode: always
servlet:
multipart:
maxFileSize: 50MB
maxRequestSize: 50MB
maxFileSize: 15MB
maxRequestSize: 15MB
2 changes: 1 addition & 1 deletion src/test/java/server/inuappcenter/kr/RedisTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.springframework.boot.test.context.SpringBootTest;
import server.inuappcenter.kr.data.dto.response.BoardResponseDto;
import server.inuappcenter.kr.data.dto.response.FaqBoardResponseDto;
import server.inuappcenter.kr.data.repository.redis.BoardResponseRedisRepository;
import server.inuappcenter.kr.data.redis.repository.BoardResponseRedisRepository;
import server.inuappcenter.kr.exception.customExceptions.CustomNotFoundException;

import java.time.LocalDateTime;
Expand Down

0 comments on commit 6c669c4

Please sign in to comment.