몬그로이

팀프로젝트 17일차, 18일차 본문

Dev입성기

팀프로젝트 17일차, 18일차

Mon Groy 2024. 8. 5. 06:37

할 일

 

- 리팩토링 / 잘못된 메서드 찾기 -> 반 정도 진행

- 기능 추가 구현 -> 취소 및 완료

- S3 삭제 기능 구현 -> 완료

- 기술면접 답변 조사 (30일~) -> 이틀치 완료


생각해볼 것

0. 기술 선정 이유를 설명할 수 있나?
1. 프로젝트 구성 방법 및 관련된 시스템 아키텍쳐 설계 방법이 적절한가?
2. 개발에 활용한 서비스/프레임워크를 정확하게 이해하고 적절히 사용하였는가?
3. 작성한 어플리케이션 코드의 가독성이 좋고 의도가 명확한가?
4. 코드관리툴(깃)을 잘 활용하고 있는가? (commit, PR, 리뷰, 브랜치 관리정책 등)
5. 어플리케이션은 다량의 트래픽에도 무리가 없도록 효율적으로 작성되었는가?
6. 작성한 테스트 코드는 적절한 범위의 테스트를 수행하고 있는가? (예. 유닛/통합 테스트 등)
7. 트러블 슈팅의 접근과 해결 과정을 명확히 설명할 수 있는가?
8. 기술멘토님의 질문에 CS지식을 가미하여 답변 하고 있는가?

테스트 하다가 발견

 

아티스트를 아무나 데려가서 아티스트그룹을 만들 수 있는 로직이 짜여져 있어서 
뭔가 조건이 필요한 듯 하다
유닛활동도 가능하기때문에 여러 그룹에서 데려갈 수 있긴한데,
더 현실적으로 만들기 위해서라면 아티스트가 허가를 받아주는 방식으로 하는게 나을까?

현재 로직으로는
그렇게 여러곳에서 가져다가 그룹을 생성하는 것 까지는 좋은데아티스트가 하나인데 그룹이 두개가 됨

그런데!
아티스트 테이블에는 두 개 다 등록이 되는게 아니라하나만 등록이 되고, 가장 최신에 등록한 곳만 남아있음

뭔가 문제인듯 문제아닌 그런 문제..
너무 깊게 생각한 것 같으니 말 안해도 되겠지?

 


도커 강의를 조금 들었는데

내 컴퓨터는 도커를 구동할 수 없는 컴퓨터라는 것을 알았다

H로 시작하는 무언가가 없기 때문이다


아티스트 

 

아티스트 개인 페이지 를 맡았다

정확하게는 그 아티스트에 대한 간단한 소개내용이 담기는 것이다


고려할 것

 

이것을 만지는 사람은 아티스트 본인일까, 소속사일까?

이 부분에 따라서 package 위치가 달라져야 한다

일단 소속사로 생각하고는 있는데, 확인해야 할 듯

 

+ 그런데 프로필이 팝업으로 뜨고 소개가 뜬다고 하는 것으로 보아

아티스트 기본정보에 있는 정보를 로드해 오는 것이 맞다

그렇다면 아티스트 본인이 설정하는 정보로

SNS 에서 프로필 사진을 눌렀을때 뜨는 페이지 정도가 될 것이다

이럴 경우 package 는 아티스트가 될 것이다

 

-> ...

 

기능 구현을 어느 패키지에 담을지 둘러보다보니 문득 든 의문

 

아티스트 (프로필) 단건조회와 뭐가 다른지 모르겠음

아티스트 단건조회의 경우

비가입자 가능에다 아티스트에 대한 정보가 다 들어있음

 

아티스트 본인이 프로필을 수정하기 전에

마이페이지>아티스트정보보기 를 눌렀을 때 뜨는 페이지

그러니까, 수정하기 버튼을 누르기 전의 아티스트 정보 페이지를 위한 메서드가 필요한 것 같음

 

근데 결국 이것도 단건조회와 담기는 내용은 같을 것인데,

그렇다면 Url을 단건조회로 보내되, UI만 다르게 구성하면 되는 것 아닌가?

하고 생각을 하게됨

 

아무래도 UI를 잘 모르니까 혼란이 온 것 같다

 

-> 팀장님께 말씀드리고, 팀원분들과 상의하니

이미 만들어 놓은 기능이 이번에 맡은 기능과 같은 것 같다고 귀결되었다

-> 할 일이 줄어서(그래도 할일 많음..) 리팩토링을 우선 해놓기로 정했다

-> 끝나고나서 피드좋아요 기능중 하나인 좋아요 누른 유저 추출하는 기능을 구현하는 중

좋아요를 누른 유저의 닉네임을 리스트로 뽑으려니 List를 몇 번이나 돌려야 했다

처음 FeedId로 좋아요를 누른 유저Id를 List로 뽑아야 했고

그 Id를 가지고 유저의 닉네임을 뽑아야 하는데,

그 사이에 Optional로 쌓인 것을 처리해야했다

따라서 isPresent 와 get 을 연달아 사용했다

-> 메서드 방향 변경

이후를 잘 못만들겠어서 다른 방식으로 짰다


실행을 했는데 aws 가 연결이 안 되는 것 같다

다시 켤 때마다 재연결을 해줘야 하는 건가..?

아직 어렵다

 

aws Credential 이 import 안 되길래

찾아보니 gradle 을 리로드 해보래서 그렇게 하니 이번엔 다른 에러가 생겼다

Could not resolve placeholder 'ADMIN_TOKEN' in value "${ADMIN_TOKEN}"

 

아니 잘 적혀있는 ADMIN 토큰이 왜..?

일단 환경변수에 잘 넣어주고

다시 구동시켰더니 이번엔 

Ambiguous mapping

이라는 오류 발생

 

하루정도 전에 발생했던 에러라서 바로 원인을 알 수 있었다

같은 api 주소가 사용됐을 때 생긴 오류인 것

 

새로 만든 좋아요 누른 유저 목록 보기 기능과

기존 피드 조회 기능의 url이 같았던 것

뒤에 주소를 추가해주니 잘 돌아갔다!


업로드 이미지 S3에서 삭제하는 기능

 

url 과 key는 비슷하지만 다르다

url = key + a 인 것

지금 테이블에 저장된 것이 url인 것

key를 추출해야하는데, 그 방법으로는

 

1. substring 으로 잘라낼 만큼의 주소의 글자수를 세서 잘라내거나

2. replace로 문자열 대체를 하거나

3. split을이용하여 마지막 요소만 사용한다 (파일이름이 만들어질 때 / 는 사용이 불가능하므로 사용해도 괜찮음)

-> 3번 선택

-> 추후 변경(아래 이유 나옴)


디코딩이 필수라는 것을 알았다

S3에 저장된 상태를 보면, 이름이 한글로된 파일이 저장될 때 인코딩이 일어나있기 때문이다

-> 처음부터 인코딩을 해서 저장하도록 로직을 구성한 사람이라면 무조건 디코딩을 해야겠다고 생각했을테지만,

나의 경우에는 인코딩을 필수요소로 생각하지 않았었기 때문에 디코딩을 하지 않아 삭제가 제대로 되지 않고 있던 것


 'decode(java.lang.String)' is deprecated 

 

-> java.net.URLDecoder 으로 사용함. 대신 예외처리 해야함

 

또, "UTF-8" 로 사용했더니 안내로 ntelliJ가 아래의 코드로 적용하라고 추천함

그대로 변경했더니 예외처리할 필요가 없어짐

StandardCharsets.UTF_8

 

위 코드로 사용하면 예외를 던지지 않기 때문이라고 함


테스트를 하려고 보니까

User 테이블에 entertainment_id 가 모두 null인 것을 발견함

큰 문제는 없는 것 같기는한데.. 그럼 이 컬럼이 과연 필요한 것인가? 하는 의문이 들었다

 

1. 컬럼을 없애거나

2. 컬럼 채워넣는다

 

ARTIST 유저의 경우

엔터테인먼트가 아티스트를 아티스트그룹에 넣는 순간 엔터테인먼트id가 등록된다거나

아티스트 계정을 생성할 때, 엔터테인먼트id 가 등록이 되어야하지 않을까?

-> 그런데 ARTIST 엔티티와 USER 엔티티는 별개라 따로 설정을 해줘야한다

 

ENTERTAINMENT 유저의 경우

생성된 후 entertainment를 가지는 User 엔티티의 entertainment를 갱신하면 될 것 같다

 

아티스트를 생성시 넣는 코드를 직접짜보며

아티스트를 생성시 User 테이블의 entertainment 값을 넣으려고 봤더니,

entertainment가 생성된 후에나 넣을 수 있다

가수가 먼저 있는게 맞는걸까, 엔터가 먼저 있는게 맞는 걸까?

 

현실적으로 생각해봐도,

아티스트의 경우 오디션을 보고나서 소속사가 생기고

아니면 엔터에서 영업해서 아티스트를 데리고온다

그렇다면 입력주체는 엔터가 맞는 것 같다

 

그렇기때문에

artistGroup을 entertainment에서 만들때 (어차피 모든 가수는 artistGroup을 가지므로)

최종 정리하는 느낌으로 artist를 가지는User 엔티티의 entertainment 정보를 업데이트하는게 낫지 않을까?

 

-> 주말이지만 접속해있는 팀원에게 물어봤더니

처음부터 ERD를 짤때 되어있었기 때문에 엔터 생성시 컬럼값에 넣으려고 했으나

setter 적용하지 않고 다른 방법을 하려니까 오류가 나서 일단 그냥 둔 상태였다고 한다

 


이메일인증할 때 id 글자수/글자타입 제한 없으나
아티스트 계정 생성할 때 글자수 제한이 있음
-> 다시 아이디 설정해서 인증받아야함..


삭제기능을 만들때 필수로 적용해야 하는 것

- 문자열 자르기

- 디코딩하기

- 업데이트 기능에 S3에 저장된 파일 삭제 로직 추가하기



했는데, 내가 만든 폴더명 여러 단계로 타고 들어가다보니까 /가 여러겹이라 제대로 처리가 안 되었다

그래서 2번으로 방법 바꿈

private final 로 삭제할 만큼의 문자열을 선언해 놓고 사용했다

Feed 삭제 테스트 성공! (2시 40분 정도)

 

이미지 삭제가 필요한 메서드에 모두 넣어주고 테스트 해야함

 

 

어떻게 되는 거지?

아티스트계정회원탈퇴 안 하고 유저에서만 탈퇴하는 경우 이미지 남아있을까?

연관관계 설정 되어있어서 괜찮을까?


수정할 때도 기존 이미지는 S3에서 삭제를 해야하기 때문에

삭제 메서드를 넣을 위치를 정해야 한다

 

새로운 이미지 url을 생성한 다음

S3에 그 url 을 저장하는 메서드가 발동되는 상태이다

 

url이 저장되어 버리고나면 객체에서 url을 가져와서 삭제하는 delete 메서드의 특성상

url을 저장하기 전에 삭제가 진행되어야 하고

새로운 이미지의 이름이 정해지기 전에 기존 url을 가져와 놓아야 한다

 

Feed 안에 속한 다건의 이미지를

통째로 삭제 후 새로운 이미지를 저장할 것인지

다건의 이미지를 하나씩 돌리면서 하나 삭제하고 하나 저장하는 식으로 할 것인지

.. 라고 생각했는데,

이미지 개수가 동일하다면 후자의 방법도 먹히겠지만

만약 이미지 개수가 다르다면?

남아도는 이미지가 기존저장된 거에 발생할지도 모른다

그렇다면 전자의 방법으로 하는게 맞다


이미지 수정 내용이 S3에도 적용이 되게끔 로직을 작성하는 중

 

String foundArtistProfileImageUrl = foundArtist.getArtistProfileImageUrl();
if (isFileExists(file)) { //기존 이미지 삭제
    s3FileUploader.deleteFileInBucket(foundArtistProfileImageUrl);

    try {
        foundArtistProfileImageUrl = s3FileUploader.saveProfileImage(file, foundArtist.getId(), UserRoleEnum.ARTIST);
    } catch (Exception e) {
        s3FileUploader.deleteFileInBucket(foundArtistProfileImageUrl);
        throw new S3Exception(UPLOAD_ERROR);
    }

    ImageUrlCarrier carrier = new ImageUrlCarrier(foundArtist.getId(), foundArtistProfileImageUrl);
    updateArtistImageUrl(carrier);
}

 

지금 상태로는 saveProfileImage 메서드가 발동하다가 예외가 발생했을 경우

profileUrl 에 들어있는 주소는 유지되고, S3에 담긴 파일은 삭제가 된 상태가 되어

테이블상 정보와 DB정보가 달라지게 된다

-> 가능한 선택지들

1. 예외를 받아 처리하는 부분에서 삭제를 해버리는 선택지

2. deleteFileInBucket을 호출하기 전에 기존 이미지Url을 먼저 삭제한는 선택지

 

또 다른 상황 예측

테이블에는 Url 정보가 기록되어 있는데, S3에는 파일 실체가 들어있지 않은 경우

-> 전달받은 파일 Url 정보로 deleteFileInBucket 메서드에서 파일이 있는지 없는지를 확인하여 삭제를 진행하고,

만약 있으면 그대로 진행하지만, 만약 실체가 없다면 예외를 호출한 곳으로 던져서 처리하도록 만들어준다

-> 그런데 그런식으로 처리를 하고나니 artist profile 이미지의 경우가 곤란해졌다

artist나 logo는 기본적으로 가입할 때 다 받도록 되어있는데, profile 이미지가 url도 없고 실체도 없는 상황이 발생할 수 있기 때문이다. 그래서 default 이미지를 넣어줘야한다고 생각했다

 

- S3 자체에 기본이미지를 넣어두고, 그 이미지가 들어가도록 만드는 것

   -> 이방법으로 할 경우는, 그 기본 이미지가 삭제되면 안 되므로 수정이나 삭제 메서드 작성시 주의해야 할 것

- 잘못된 url 은 삭제한 뒤, 이미지 등록 메서드를 다시 넣어주어서 이미지file 저장을 마저 진행하도록 만드는 것

이 두 가지 방법이 떠올랐다

 

그런데 애초에 메서드를 잘못짜고 있었다는 사실을 알게되었다

 

Url이 저장되어있지만 S3에는 이미지파일이 없는경우

url정보를 삭제하고 다음단계로 넘기면 되는 것이었던 것


자, 그다음 문제

아까도 말했지만 프로필 이미지의 경우는 가입하는 순간부터 무조건 등록해줘야한다

그런데 예외를 거치면서 이미지가 초기화되어 널값이 될 수 있는 상황이 발생할 수 있다

 

이를 개선하기위해서는 S3에 기본 이미지를 올려놓고

그 이미지 주소를 받아서 주입해둔 다음

오류가 발생한 경우 그 이미지로 초기화를한다

S3에 이미지 save 메서드를 날린다는 뜻이 아니라,

S3에는 이미 이미지가 등록되어있기 때문에, 그냥 그 주소만 받아서 url에 저장해 두는 것이다

 

이렇게 하려면 사전에 이미지 수정이나 등록하는 부분에서

현재 프로필사진에 등록된 이미지가 default 이미지인지 아닌지 확인을 한다음 등록을 진행해야 할 것이다

왜냐하면 S3에 있는 기본 이미지를 삭제해버리면 안되기 때문

 

결국 현재의 메서드에서 추가적 로직이 필요한 것이다

근데 이걸 어디에다 물어봐야할지 모르겠다

 

아무튼 지금까지의 로직으로 이미지 수정 S3에 적용하는 것도 성공!(8시쯤)

근데 위에 적은 내용 고민하느라 시간 다 간 듯

 


아티스트 사진을 수정하는데 에러 발생

이미지를 contentType 이 걸러내고 있었기 때문이다

보기에는 분명 이미지류인데 왜 걸러내는지 아무리 속성을 뒤져봐도 모르겠어서

일단은 주석처리를 한다음, 다시 실행시켰다

그런데 또 다른 에러가 발생했다

 

private void checkDuplicateName(String artistName) {
    boolean isExistName = artistRepository.existsByArtistName(artistName);
    if (isExistName) {
        throw new DuplicatedException(ENROLLED_ARTIST_NAME);
    }
}
private void checkDuplicateName(String artistName, Artist artist) {

    if (!artistName.equals(artist.getArtistName())) {
        boolean isExistName = artistRepository.existsByArtistName(artistName);

        if (isExistName) {
            throw new DuplicatedException(ENROLLED_ARTIST_NAME);
        }
    }
}

 

아티스트가 본인 정보 수정을 하는데, 위에있는 메서드를 이용해서

수정하고자하는 활동명이 이미 등록이 되어있는 활동명인지 검증을 거치도록 만들어 두었었다

그런데 문제는, 본인이 현재 사용하고 있는 활동명을 그대로 입력했을 때도 걸러져서 예외가 발생한다는 것이었다

 

그래서 본인의 활동명일 때는 검증절차를 밟지 않도록 아래의 메서드로 수정했다

하마터면 활동명 말고도 수정할때마다 활동명을 바꿔야만하는 불상사가 일어날 뻔 했다

 


시연영상 촬영을 했다

모든 기능이 들어있지 않고, 간략한 흐름만 보여주는 영상이었다

계속 틀리다가 8시간 정도 걸려서 겨우 3분 40초짜리 를 만들었는데,

이마저도 토큰넣는 시간을 제외하면 3분가량 될 것이다


https://velog.io/@songunnie/Gradle-%EA%B0%91%EC%9E%90%EA%B8%B0-Main-Application-%EA%B5%AC%EB%8F%99%EC%9D%B4-%EC%95%88%EB%90%9C%EB%8B%A4.-%ED%95%B4%EA%B2%B0

 

[Gradle] 갑자기 Main Application 구동이 안된다. (해결)

AWS S3를 연결한 후 갑자기 잘만 구동되던 main application이 구동이 안된다.맨 윗단 에러 메시지는 아래와 같았는데,처음엔 JDK 버전 or Java 버전 or Gradle 버전 or STS의 문제인가 하고 살펴봤는데전부 문

velog.io

 

 

https://devel-log.tistory.com/100

 

[JAVA] Spring boot @Value 사용법과 java.lang.IllegalArgumentException: Could not resolve placeholder '' in value "${}" 에

@Value 로 application.yml 의 값을 가져오는데 해당 에러가 발생했다. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applicationProperty': Injection of autowired dependencies failed; nested exception

devel-log.tistory.com

 

https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/DeletingObjects.html

 

Amazon S3 객체 삭제 - Amazon Simple Storage Service

Amazon S3 객체 삭제 Amazon S3 콘솔, AWS SDK, AWS Command Line Interface(AWS CLI) 또는 REST API를 사용하여 Amazon S3에서 직접 하나 이상의 객체를 삭제할 수 있습니다. S3 버킷에 있는 모든 객체에 스토리지 비용이

docs.aws.amazon.com

https://green-bin.tistory.com/28

 

Spring - Spring으로 AWS S3에 이미지 업로드하기2: Spring에서 기능 구현

이전 글 참고! AWS - Spring으로 AWS S3에 이미지 업로드하기1: S3 버킷과 IAM 생성 이번에 진행하는 프로젝트에서 AWS S3에 파일을 저장/수정/삭제할 수 있는 기능 구현을 담당하게 되었다. 버킷 생성부

green-bin.tistory.com

https://jinmook.tistory.com/24

 

AWS S3 이미지 저장 및 삭제와 DB로직 트랜잭션 분리

트랜잭션 분리 최근에 Real MySQL 이라는 책을 읽으면서 트랜잭션에 대한 내용을 읽었는데, 많은 지식들을 얻을 수 있었지만 그중 가장 크게 와닿았던 내용이 바로 트랜잭션의 범위를 최소로 해야

jinmook.tistory.com

https://green-bin.tistory.com/32

 

Spring - Thmbnail 이미지로 웹 성능 향상시키기

얼마 전 S3로 이미지를 저장하고 저장된 이미지의 URL을 반환하는 기능을 구현했다. 하지만 한 가지 문제가 있었는데, 고용량의 이미지가 그대로 올라간 것이다. Thumbnail 이미지를 생성하는 이유

green-bin.tistory.com

https://www.gunwi.net/gunwi/board.php?bo_table=sense&wr_id=79

 

이미지 확장자 jfif는 무엇이고 jpg로 다운받는 방법 > 컴퓨터상식 | 군위넷-군위 인터넷 신문

인터넷을 보다보면 필요한 이미지나 사진을 저장할 때 jpg 파일인데 받고 보면 jfif라는 확장자가 된 경우들이 있습니다. 감상용이나 재사용 등의 목적으로 받았는데 확장자가 다르다보니 파일...

www.gunwi.net

 

 

'Dev입성기' 카테고리의 다른 글

21일차,22일차, 23일차  (0) 2024.08.09
19일차(중간발표날)  (0) 2024.08.06
15일차  (0) 2024.08.02
팀프로젝트 13일차, 14일차  (0) 2024.08.01
오늘 고민은 여기까지  (0) 2024.07.28