jungrok5 / picturespot

SFlash 서비스 진행중

Home Page:https://www.sflash.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SFlash - 지도 SNS 서비스 📸✨

bg-3.png


💡 프로젝트 소개

사람들은 알고 나만 모르는 스팟들…… 대체 거기가 어디야? 블로그, 인스타 검색 이제 그만!! SFlash(Spot + Flash)는 전국의 명소들을 사진과 지도로 한눈에 볼수 있도록 기획한 서비스 입니다.

👨‍👨‍👦‍👦 팀원

  • Frontend : 허민규, 김다영, 김형민 React
  • Backend : 장현준[이력서], 김승욱, 이세정 SpringBoot
  • Designer : 송은정, 임아현

📅 진행 기간

  • 21.04.23(금) - 21.05.28(금)

✍ 기획 배경

  • 원하는 장소를 찾기 위해 인스타그램, 블로그 검색 후 해당 장소의 정확한 위치를 찾기 위해 지도로 검색을 해야하는 번거로움 발생
  • 사용자들이 원하는 스팟 정보를 지도와 사진으로 한 눈에 볼 수 있도록 기획

🙋🏻‍ 담당한 부분

  • 프로젝트 조장
  • 게시물 CRUD
  • 댓글 CRUD
  • 좋아요, 좋아요 취소
  • 게시물 이미지 등록, 수정, 삭제
  • 무중단 CI/CD

💡 개발 환경

  • Java 8
  • JDK 1.8.0
  • IDE : IntelliJ
  • Framework : SpringBoot
  • Build Tools : Gradle
  • Server : Amazon EC2 Ubuntu
  • Database : Amazon RDS MariaDB
  • File Storage: AWS S3 Bucket
  • CI/CD : Travis, codedeploy,s3

💡 전체 구조

💡 주요 기능

로그인/회원가입 이메일/비밀번호 찾기 소셜 로그인 게시글 CRUD 다중 이미지 업로드
2021-05-31-4-54-56.png 2021-05-31-4-56-35.png 2021-05-31-4-54-56.png 2021-05-31-4-58-55.png 2021-05-31-5-00-07.png
댓글CRUD 좋아요 프로필 편집 문의하기 CRUD 문의하기 답변 CRUD
2021-05-31-5-01-11.png 2021-05-31-5-02-05.png 2021-05-31-5-02-55.png 2021-05-31-5-03-42.png 2021-05-31-5-04-38.png




문제발생 및 해결

/map(GetMapping), /board(GetMapping) API호출 할 때 시간 최적화 하기 위한 노력

  • /map, /board를 호출시 Board,User,Heart,BoardImgUrl에 대한 정보를 한번에 보내주어야한다. 처음 프로젝트를 설계를 하였을 때는 반복문으로 DB를 조회를 하였지만 N + 1문제가 발생하였고, 데이터가 많아 질 수록 조회시간도 더욱 느리게 되었다. 그래서 한번 조회를 할 때 User,Heart,ImgUrl를 다 조회하는 페치조인을 사용하였다. 그 결과 아래 사진과 같이 시간을 축소 시켰습니다. 2021-05-31-8-31-59.png

무중단 CI/CD

  • FileZila를 사용하면서 배포 시간비용이 오래 걸렸고, 배포를 하는 과정에서 서비스가 멈춰야하는 불상사가 나버리는 치명적인 단점이 있었다. 그래서 깃헙에서 무료제공중인 travis와 스크립트를 활용하여 무중단 배포를 구현하였습니다.

  • 이번 무중단 배포에서의 핵심은 2가지로 생각합니다. intelij에서 깃허브로 push를 했을 때 travis에 연동되어있는 Repository가 자동으로 빌드를 하여 검사를 하는 포인트와 빌드를 다 진행하고 *.jar파일을 s3와 CodeDepoly에서 받고 쉘 스크립트를 이용하여 포트기반으로 배포하는 과정이 포인트 입니다.

  • 무중단 CI/CD를 한 결과 배포과정에서의 시간비용을 최소화할 수 있었고 배포가 되더라도 서비스는 멈추지않고 사용자들에게 제공할 수 있었습니다.

    2021-05-31-8-36-50.png

데이터베이스 하나의 컬럼에 여러 데이터 문제

제1정규형 위배

  • 배포하기 전 까지만해도 메모리 DB인 H2를 사용하였다. DB 설계 및 API설계 할 때도 게시물이미지 테이블을 따로 만들지 않고 게시물테이블에다가 이미지 컬럼을 만들었다. 여기서 잘못 생각했던게 게시물에 대한 이미지가 1개 이상인데 그걸 간과했다. 그래서 하나의 컬럼에 이미지 url이 1개 이상이씩 들어가는 현상이 생겼다. 하지만 H2 DB에서는 에러를 발생시키지 않고 진행되었다. 그래서 눈치를 채지못하였고 MariaDB로 교체를 할 때 에러를 내뱉었다. 아... 제1정규형을 위배를 한 것을 눈치채었고 게시물이미지 테이블을 따로 만들고 연관관계도 다시 맺어주었다.

게시물이미지 테이블

@NoArgsConstructor
@Getter
@Entity
public class BoardImgUrls {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "BOARDIMGURLS_ID")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;

    private String imgUrl;

    @Builder
    public BoardImgUrls(String imgUrl, Board board) {
        this.imgUrl = imgUrl;
        this.board = board;
    }

    public static Set<BoardImgCommonRequestDto> toDtoList(Set<BoardImgUrls> dtos) {
        Set<BoardImgCommonRequestDto> imgCommonRequestDtos = new HashSet<>();
        for (BoardImgUrls boardImgUrl : dtos) {
            imgCommonRequestDtos.add(new BoardImgCommonRequestDto(boardImgUrl));
        }
        return imgCommonRequestDtos;
    }
}

S3 게시글 작성 이미지 업로드 에러

  • 1차배포, Http일 때는 이상이 없었다. -> 2차배포, Https 적용하고 나서 게시글 작성시 이미지를 s3에 저장할 때 Permission Error가 발생.

  • 블로그와 문서를 찾아보니 S3는 Https를 지원을 안할 수 도 있다? 라는 의견을 보게되었다. 그래서 1차 해결책으로 AWS CLoudFront로 s3를 배포하기로 해보았다. 하지만 실패를 하였고, 스택오버플로우와 블로그, 문서를 찾아보다가 나와 비슷한 문제를 가진 사람의 블로그를 찾을 수 있었다.

    private Optional<File[]> convert(List<MultipartFile> file) throws IOException {
            multiparts = new MultipartFile[file.size()];
            File[] convertFiles = new File[file.size()];
            for (int i=0; i<file.size(); i++) {
                multiparts[i] = file.get(i);
                convertFiles[i] = new File((file.get(i).getOriginalFilename()));
               if (!convertFiles[i].exists()) {
                  log.info("파일이 존재하는지? : " + convertFiles[i].exists()+" ,"+convertFiles[i]);
                    convertFiles[i].mkdirs();
                    Runtime.getRuntime().exec("chmod 777 " + file.get(i).getOriginalFilename());
                    convertFiles[i].setExecutable(true, false);
                    convertFiles[i].setReadable(true, false);
                    convertFiles[i].setWritable(true, false);
                   if (!convertFiles[i].createNewFile()) {
                       log.debug("===========Optional.emty 가 나옴!!===========");
                        return Optional.empty();
                    }else {
                        try(FileOutputStream fos = new FileOutputStream(convertFiles[i])) {
                            fos.write(file.get(i).getBytes());
                        }
                    }
                }
            }
            return Optional.of(convertFiles);
        }

    위와 같은 코드였다. 배포를 Linux환경에서 Multipart를 File로 변환을 하려면 권한이 있어야 한다는 점을 깨달았다! 그래서 권한을 주면서 File을 만들어 보았지만 부분적으로 해결은 했지만 결론적인 해결 x

    • 2차 해결방안 : 블로그를 보다보니 굳이 Multipart -> File로 안하고 바로 Multipart를 사용해도 된다는 것이다!!... 분명히.. MultipartFile은 File로 변환하고 사용을 해야한다고 블로그에서 봤었는데... 내가 잘못 이해하고 있었다. 그래서 다음과 같이 코드를 수정하였다.

      public List<String> boardUpload(List<MultipartFile> multipartFile, String dirName) throws IOException {
              String[] result = changeUploadFileName(multipartFile, dirName);
              return Arrays.asList(result);
          }

      MultipartFile을 File로 convert하지 않고 바로 Multipart파일을 사용해서 s3에 저장을 하는 로직으로 수정하였다.

About

SFlash 서비스 진행중

https://www.sflash.net


Languages

Language:Java 97.6%Language:Shell 2.4%