Skip to content

Commit

Permalink
Merge pull request #50 from dnd-side-project/main
Browse files Browse the repository at this point in the history
Develop에 Main Merge
  • Loading branch information
min-0 authored Sep 23, 2024
2 parents 1f68274 + 6fc5e97 commit 67b84d6
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 맵땅 Backend
# 맵땅_Backend


![image](https://github.com/user-attachments/assets/25515ba0-251a-4465-b4b6-925a3a99ca14)
Expand Down
12 changes: 2 additions & 10 deletions src/main/java/com/dnd/dndtravel/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ public OpenAPI openAPI() {
.version("1.0.0"))
.addServersItem(new Server().url("/").description("Generated Default Server URL")) //local에서는 http, aws에서는 https로 server url 설정됨
.addSecurityItem(new SecurityRequirement()
.addList("Access Token")
.addList("Refresh Token"))
.addList("Access Token"))
.components(new Components()
.addSecuritySchemes("Access Token", createAccessTokenScheme())
.addSecuritySchemes("Refresh Token", createRefreshTokenScheme()));
);
}

private SecurityScheme createAccessTokenScheme() {
Expand All @@ -34,11 +33,4 @@ private SecurityScheme createAccessTokenScheme() {
.scheme("bearer")
.description("Access Token");
}

private SecurityScheme createRefreshTokenScheme() {
return new SecurityScheme().type(SecurityScheme.Type.HTTP)
.bearerFormat("JWT")
.scheme("bearer")
.description("Refresh Token");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.dnd.dndtravel.map.controller.request.validation.PhotoValidation;
import com.dnd.dndtravel.map.controller.swagger.MapControllerSwagger;
import com.dnd.dndtravel.map.service.MapService;
import com.dnd.dndtravel.map.service.dto.response.AttractionRecordResponse;
import com.dnd.dndtravel.map.service.dto.response.AttractionRecordsResponse;
import com.dnd.dndtravel.map.service.dto.response.RegionResponse;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;

import com.dnd.dndtravel.config.AuthenticationMember;
Expand All @@ -17,6 +18,8 @@
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.SchemaProperty;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down Expand Up @@ -61,12 +64,9 @@ RegionResponse map(
})
@AuthenticationCommonResponse
void memo(
@Parameter(hidden = true)
AuthenticationMember authenticationMember,
@Parameter(description = "사진")
List<MultipartFile> photos,
@Parameter(description = "기록 요청 정보", required = true)
RecordRequest recordRequest
@Parameter(hidden = true) AuthenticationMember authenticationMember,
@Parameter(description = "사진", schema = @Schema(type = "array", format = "binary")) List<MultipartFile> photos,
@Parameter(description = "기록 요청 정보", required = true) RecordRequest recordRequest
);

@Operation(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.dnd.dndtravel.map.controller.swagger;

import java.lang.reflect.Type;

import org.springframework.http.MediaType;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
* 스웨거에서 Multipart 요청시 발생하는 "Content-Type 'application/octet-stream' is not supported" 문제를 해결하기위한 클래스
* Postman같은 프로그램으로 보낼시 사진과 json객체에 대한 타입을 별도로 지정할 수 있지만, 스웨거는 파라미터별로 별도 타입을 지정할수 없었던것이 원인
*/
@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {

public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}

@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}

@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}

@Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.dnd.dndtravel.map.exception;

public class MemberAttractionNotFoundException extends RuntimeException {
private static final String MESSAGE = "존재하지 않는 방문기록 [memberAttractionId=%s]";
private static final String MESSAGE = "존재하지 않는 방문기록 혹은 멤버 [memberAttractionId=%s] [memberId=%s]";

public MemberAttractionNotFoundException(long memberAttractionId) {
super(String.format(MESSAGE, memberAttractionId));
public MemberAttractionNotFoundException(long memberAttractionId, long memberId) {
super(String.format(MESSAGE, memberAttractionId, memberId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface MemberAttractionRepository extends JpaRepository<MemberAttracti

List<MemberAttraction> findByMemberId(long memberId);

Optional<MemberAttraction> findByIdAndMemberId(long memberId, long memberAttractionId);
Optional<MemberAttraction> findByIdAndMemberId(long memberAttractionId, long memberId);
}

66 changes: 39 additions & 27 deletions src/main/java/com/dnd/dndtravel/map/service/MapService.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,59 +116,71 @@ public AttractionRecordsResponse allRecords(long memberId, long cursorNo, int di
}

// 방문기록 수정
//todo DB 컬럼을 매번 지웠다가 insert하는게 조금 부자연스럽다고 느낌, 추후 개선포인트 고려해보자
@Transactional
public void updateVisitRecord(RecordDto dto, long memberId, long memberAttractionId) {
//validation
MemberAttraction memberAttraction = memberAttractionRepository.findByIdAndMemberId(memberAttractionId, memberId).orElseThrow(() -> new MemberAttractionNotFoundException(memberAttractionId));
MemberAttraction memberAttraction = memberAttractionRepository.findByIdAndMemberId(memberAttractionId, memberId).orElseThrow(() -> new MemberAttractionNotFoundException(memberId, memberAttractionId));

//update
memberAttraction.updateVisitRecord(dto.region(), dto.dateTime(), dto.memo());
Attraction attraction = attractionRepository.findById(memberAttraction.getAttraction().getId()).orElseThrow(() -> new RuntimeException("유효하지 않은 명소이름"));
attraction.updateAttractionName(dto.attractionName());

//사진 업데이트
List<Photo> photos = photoRepository.findByMemberAttractionId(memberAttraction.getId());
List<String> existingUrls = photos.stream()
updatePhotos(memberAttraction, dto.photos());
}

/**
* 기록에 저장된 사진이 없는경우, 수정요청엔 사진이 있는경우 => s3에 업로드, DB에 새로 사진추가
* 기록에 저장된 사진이 없는경우, 수정요청엔 사진이 없는경우 => 아무작업도 안해도 됨
* 기록에 저장된 사진이 있는경우, 수정요청엔 사진이 있는경우 => s3에 있던 사진 전부 삭제후 재 업로드, DB에 있던 사진 전부 삭제 후 새로운 사진 추가
* 기록에 저장된 사진이 있는경우, 수정요청엔 사진이 없는경우 => s3에 있던 사진 전부삭제, DB에 있던 사진 전부 삭제
*/
private void updatePhotos(MemberAttraction memberAttraction, List<MultipartFile> newPhotos) {
// 방문기록에 저장된 사진 조회
List<Photo> existingPhotos = photoRepository.findByMemberAttractionId(memberAttraction.getId());
List<String> existingUrls = existingPhotos.stream()
.map(Photo::getUrl)
.toList();
List<String> newPhotoUrls = updatePhotoToS3(dto, existingUrls);
//todo DB 컬럼을 매번 지웠다가 insert하는게 조금 부자연스럽다고 느낌, 추후 개선포인트 고려해보자
updatePhotoToDatabase(photos, newPhotoUrls, memberAttraction);

// 방문기록에 저장된 사진이 없고, 수정요청에도 사진이 없는경우
if (existingPhotos.isEmpty() && (newPhotos == null || newPhotos.isEmpty())) {
return;
}

// 기존의 사진이 존재하는 경우
if (!existingPhotos.isEmpty()) {
photoService.deleteS3Photo(existingUrls);
photoRepository.deleteAll(existingPhotos);
}

// 새로운 사진 수정요청이 들어오는경우, S3에 업로드 후 DB에 추가
if (newPhotos != null && !newPhotos.isEmpty()) {
List<String> newPhotoUrls = newPhotos.stream()
.map(photoService::upload)
.toList();

List<Photo> newPhotoEntities = newPhotoUrls.stream()
.map(url -> Photo.of(memberAttraction, url))
.toList();
photoRepository.saveAll(newPhotoEntities);
}
}

// 방문기록 삭제
@Transactional
public void deleteRecord(long memberId, long memberAttractionId) {
//validation
MemberAttraction memberAttraction = memberAttractionRepository.findByIdAndMemberId(memberAttractionId, memberId)
.orElseThrow(() -> new MemberAttractionNotFoundException(memberAttractionId));
.orElseThrow(() -> new MemberAttractionNotFoundException(memberAttractionId, memberId));

List<Photo> photos = photoRepository.findByMemberAttractionId(memberAttraction.getId());
photoRepository.deleteAll(photos);
memberAttractionRepository.delete(memberAttraction);
attractionRepository.deleteById(memberAttraction.getAttraction().getId());
}

private List<String> updatePhotoToS3(RecordDto dto, List<String> existingUrls) {
// s3의 기존 사진 전부 삭제
photoService.deleteBeforePhoto(existingUrls);

// s3에 새로운 사진 전부 업로드
return dto.photos().stream()
.map(photoService::upload)
.toList();
}

private void updatePhotoToDatabase(List<Photo> photos, List<String> newPhotoUrls, MemberAttraction memberAttraction) {
photoRepository.deleteAll(photos);
List<Photo> newPhotos = newPhotoUrls.stream()
.map(url -> Photo.of(memberAttraction, url))
.toList();

// 새로운 사진 저장
photoRepository.saveAll(newPhotos);
}

private void setPhotoUrlsWithJoin(List<RecordProjection> attractionRecords) {
List<AttractionPhotoProjection> attractionPhotos = photoRepository.findByRecordDtos(
attractionRecords);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public String upload(MultipartFile image) {
return uploadImage(image);
}

public void deleteBeforePhoto(List<String> existingUrls) {
public void deleteS3Photo(List<String> existingUrls) {
for (String existingPhotoUrl : existingUrls) {
// 기존 이미지 URL에서 파일 이름 추출
String existingFileName = existingPhotoUrl.substring(existingPhotoUrl.lastIndexOf('/') + 1);;
Expand Down

0 comments on commit 67b84d6

Please sign in to comment.