Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop to Main 릴리즈 (#71) #72

Merged
merged 56 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
3dbda85
fix : 운영 CD 에 있는 배포과정 에서 오타 수정 (#52)
jinhoon227 Jan 18, 2024
6eb2131
feat : nginx 설정 (#52)
jinhoon227 Jan 18, 2024
b7d7a37
feat : nginx CD 설정 (#52)
jinhoon227 Jan 18, 2024
95b36ce
feat : 서브모듈 최신화 (#52)
jinhoon227 Jan 18, 2024
38977b7
feat : 테스트 트리거 추가 (#52)
jinhoon227 Jan 18, 2024
59bb0c9
feat : 서브모듈 커밋 최신화 (#52)
jinhoon227 Jan 18, 2024
0423807
feat : docker-compose-dev 수정 (#52)
jinhoon227 Jan 18, 2024
944794d
feat : 서브모듈 최신화 (#52)
jinhoon227 Jan 18, 2024
deebd45
feat : CD 파일 수정 (#52)
jinhoon227 Jan 18, 2024
2e7cf0d
feat : CD 파일 수정 (#52)
jinhoon227 Jan 18, 2024
13087a0
feat : CD 파일 수정 (#52)
jinhoon227 Jan 18, 2024
1b5f11c
Merge branch 'develop' of https://github.com/Korea-Certified-Store/ba…
jinhoon227 Jan 18, 2024
0644740
feat : CD 파일 수정 (#52)
jinhoon227 Jan 18, 2024
7874142
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
5f652b1
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
6b0b830
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
0a8b0d4
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
02b4f50
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
ba295e5
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
8391495
fix : 잘못된 nginx 설정 수정 (#52)
jinhoon227 Jan 18, 2024
147ba7e
feat : ngnix 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
994d9d2
feat : nginx 설정방식 변 (#52)
jinhoon227 Jan 18, 2024
557b58e
Merge branch 'develop' of https://github.com/Korea-Certified-Store/ba…
jinhoon227 Jan 18, 2024
e859c6a
feat : nginx 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
317e6c6
feat : nginx 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
c77fbc7
feat : nginx 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
5b6ee2d
feat : nginx 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
985e69a
Merge branch 'main' of https://github.com/Korea-Certified-Store/backe…
jinhoon227 Jan 18, 2024
f613655
feat : nginx 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
7c14023
feat : nginx 설정방식 변경 (#52)
jinhoon227 Jan 18, 2024
1956225
feat : nginx 인증서 추가 (#52)
jinhoon227 Jan 18, 2024
e1c0310
fix : nginx 잘못된 upstream 수정 (#52)
jinhoon227 Jan 18, 2024
4f4f54d
fix : cloudflare ssl -> certbot, letsencrypt ssl 로 변경 (#52)
jinhoon227 Jan 19, 2024
3f1f7e5
fix : API, Service 단에 (경도, 위도) 좌표를 4개 받도록 변경 (#65)
sungjindev Jan 19, 2024
358b86e
fix : 4개의 (경도, 위도) 좌표받아 Polygon 영역 내 가게들 리턴하는 Query 및 테스트 코드 작성 (#65)
sungjindev Jan 19, 2024
6570136
fix : cloudflare ssl -> certbot, letsencrypt ssl 로 변경 (#52)
jinhoon227 Jan 19, 2024
8c7c529
feat : Google Cloud Storage API 명세를 위한 SwaggerConfig 구현 (#65)
sungjindev Jan 19, 2024
4c536ea
Merge pull request #66 from Korea-Certified-Store/feature/fix-mbr-to-…
sungjindev Jan 19, 2024
a9b3727
fix : conf 설정 수정 (#52)
jinhoon227 Jan 19, 2024
52c76d5
Merge branch 'develop' of https://github.com/Korea-Certified-Store/ba…
jinhoon227 Jan 19, 2024
1de0e4c
feat : 서브모듈 최신화 (#52)
jinhoon227 Jan 19, 2024
9a5e810
feat : 서버로 설정파일 전송 과정 개선 (#52)
jinhoon227 Jan 19, 2024
ce8ae00
feat : 서버로 설정파일 전송 과정 개선 (#52)
jinhoon227 Jan 19, 2024
f17bd60
feat : 불필요한 테스트 트리거 제거 (#52)
jinhoon227 Jan 19, 2024
1027241
Merge pull request #56 from Korea-Certified-Store/feature/set-https(#52)
jinhoon227 Jan 19, 2024
aac45dc
refactor : 개발 nginx 주석 수정 (#67)
jinhoon227 Jan 20, 2024
79c3c9b
feat : 운영 CD 업데이트 (#67)
jinhoon227 Jan 20, 2024
3c5bed8
feat : 운영 CD 업데이트 (#67)
jinhoon227 Jan 20, 2024
0db7060
fix : 운영 CD 에서 nginx.conf 파일 home 으로 복사 (#67)
jinhoon227 Jan 20, 2024
8d8495d
fix : 운영 CD 에서 테스트 트리거 삭제 (#67)
jinhoon227 Jan 20, 2024
8e7046a
Merge pull request #68 from Korea-Certified-Store/feature/set-prod-ht…
jinhoon227 Jan 20, 2024
c354406
refactor : 약 20초 병목이 걸리던 로직을 Hash 구조를 이용해서 0.5초로 개선 (#69)
sungjindev Jan 20, 2024
9650f3a
refactor : 반복될 필요가 없는 조회 로직을 Service단에 PostConstruct init으로 해결 (#69)
sungjindev Jan 20, 2024
2f3c308
Merge branch 'develop' of https://github.com/Korea-Certified-Store/ba…
sungjindev Jan 20, 2024
0785272
Merge pull request #70 from Korea-Certified-Store/refactor/refactor-s…
sungjindev Jan 20, 2024
f492cc7
Merge branch 'main' of https://github.com/Korea-Certified-Store/backe…
sungjindev Jan 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/action-develop-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ jobs:
chmod +x ./gradlew
./gradlew clean build -x test

# 도커 컴포즈 설정 파일 서버(EC2)로 전달
- name: Send docker-compose.yml
# 설정 파일 서버(EC2)로 전달
- name: Send docker-compose.yml and nginx.conf
uses: appleboy/scp-action@master
with:
username: ubuntu
host: ${{ secrets.KCS_HOST_DEV }}
key: ${{ secrets.KCS_KEY_DEV }}
source: "src/main/resources/backend-submodule/docker-compose-dev.yml"
source: "src/main/resources/backend-submodule/docker-compose-dev.yml,./nginx/nginx.conf"
target: "/home/ubuntu/"

# Docker hub 로그인
Expand All @@ -57,8 +57,8 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME}}
password: ${{ secrets.DOCKER_TOKEN}}

# Docker Hub 에 푸시
- name: Build and push
# Docker Hub 에 Springboot 푸시
- name: Build and push springboot
uses: docker/build-push-action@v4
with:
context: .
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/action-production-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ jobs:
chmod +x ./gradlew
./gradlew clean build -x test

# 도커 컴포즈 설정 파일 서버로 전달
- name: Send docker-compose.yml
# 설정 파일 서버로 전달
- name: Send docker-compose.yml and nginx
uses: appleboy/scp-action@master
with:
username: ${{ secrets.KCS_USERNAME_PROD }}
host: ${{ secrets.KCS_HOST_PROD }}
key: ${{ secrets.KCS_KEY_PROD }}
source: "src/main/resources/backend-submodule/docker-compose.yml"
source: "src/main/resources/backend-submodule/docker-compose.yml,src/main/resources/backend-submodule/nginx/nginx.conf"
target: "/home/g22203/"

# Docker hub 로그인
Expand Down Expand Up @@ -79,8 +79,9 @@ jobs:
script: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
sudo docker pull {{ secrets.DOCKER_REPOSITORY_PROD }}:latest
docker-compose -f docker-compose-dev.yml down
docker-compose -f docker-compose.yml down
docker rmi $(docker images -q)
cp -f ./src/main/resources/backend-submodule/docker-compose.yml .
cp -rf ./src/main/resources/backend-submodule/nginx .
rm -r src
docker-compose -f docker-compose.yml up -d
41 changes: 41 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
events {
worker_connections 1024;
}

http {

# -------------------- spring-boot-dev WAS --------------------
upstream backend {
server server:8080;
}

server {
listen 80;
server_name dev.nainga.store;

# certbot 이 소유자임을 확인하는 경로
location /.well-known/acme-challenge {
root /var/lib/letsencrypt/; # 사용자 인증을 위한 파일이 생성 되는곳
}

# Redirect all traffic to HTTPS
location / {
return 301 https://$host$request_uri;
}
}

server {
listen 443 ssl;
server_name dev.nainga.store;

ssl_certificate /etc/letsencrypt/live/dev.nainga.store/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dev.nainga.store/privkey.pem;

location / {
proxy_pass http://backend;
proxy_set_header Host $host; # 클라이언트가 요청한 호스트의 도메인
proxy_set_header X-Real-IP $remote_addr; # 클라이언트의 실제 IP 주소
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 원격 클라이언트의 실제 IP 주소와, 이전에 거친 프록시 서버의 IP 주소들이 쉼표로 구분되어 포함
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ public class StoreCertificationApi {
"certificationName: 가게의 인증제 목록<br>" +
"=> 각 인증제별 순서는 보장되지 않습니다.")
@GetMapping("api/v1/storecertification/byLocation")
public Result<List<StoreCertificationsByLocationResponse>> findStoreCertificationsByLocation(@RequestParam("nwLong") double nwLong, @RequestParam("nwLat") double nwLat, @RequestParam("seLong") double seLong, @RequestParam("seLat") double seLat) {
List<StoreCertification> storeCertificationsByLocation = storeCertificationService.findStoreCertificationsByLocation(new Location(nwLong, nwLat), new Location(seLong, seLat));
List<Long> storeIdsWithMultipleCertifications = storeCertificationService.findStoreIdsWithMultipleCertifications(); //여러 인증제를 가지고 있는 가게의 id 리스트
public Result<List<StoreCertificationsByLocationResponse>> findStoreCertificationsByLocation(@RequestParam("nwLong") double nwLong, @RequestParam("nwLat") double nwLat, @RequestParam("swLong") double swLong, @RequestParam("swLat") double swLat, @RequestParam("seLong") double seLong, @RequestParam("seLat") double seLat, @RequestParam("neLong") double neLong, @RequestParam("neLat") double neLat) {
List<StoreCertification> storeCertificationsByLocation = storeCertificationService.findStoreCertificationsByLocation(new Location(nwLong, nwLat), new Location(swLong, swLat), new Location(seLong, seLat), new Location(neLong, neLat));
List<Long> storeIdsWithMultipleCertifications = storeCertificationService.getDuplicatedStoreIds(); //여러 인증제를 가지고 있는 가게의 id 리스트
List<StoreCertificationsByLocationResponse> storeCertificationsByLocationResponses = new ArrayList<>(); //반환해줄 StoreCertificationsByLocationResponse들의 List
Map<Long, StoreCertificationsByLocationResponse> map = new HashMap<>(); //여러 인증제를 가지고 있는 가게들의 response를 임시로 저장하고 있을 map

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,49 @@
import com.nainga.nainga.domain.store.domain.Location;
import com.nainga.nainga.domain.storecertification.dao.StoreCertificationRepository;
import com.nainga.nainga.domain.storecertification.domain.StoreCertification;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class StoreCertificationService {
private final StoreCertificationRepository storeCertificationRepository;
public List<StoreCertification> findStoreCertificationsByLocation(Location northWestLocation, Location southEastLocation) {
return storeCertificationRepository.findStoreCertificationsByLocation(northWestLocation, southEastLocation);
private List<Long> duplicatedStoreIds; //여러 인증제를 가지는 중복된 storeId를 담고있는 리스트

@Autowired
public StoreCertificationService(StoreCertificationRepository storeCertificationRepository) {
this.storeCertificationRepository = storeCertificationRepository;
}

public List<Long> findStoreIdsWithMultipleCertifications() {
@PostConstruct
public void init() { //이 Service Bean이 생성된 이후에 한번만 중복된 storeId를 검사해서 Globally하게 저장
List<StoreCertification> allStoreCertifications = storeCertificationRepository.findAll(); //중복된 id를 검사하기 위함
List<Long> allStoreIds = new ArrayList<>();

HashSet<Long> uniqueStoreIds = new HashSet<>(); //조회 성능을 높이기 위해 HashSet으로 저장
HashSet<Long> duplicatedIds = new HashSet<>();

for (StoreCertification storeCertification : allStoreCertifications) {
allStoreIds.add(storeCertification.getStore().getId());
Long storeId = storeCertification.getStore().getId();
if (!uniqueStoreIds.add(storeId)) { //HashSet에 add를 했을 때 이미 존재하는 데이터면 false가 리턴되는 것을 활용
duplicatedIds.add(storeId);
}
}
duplicatedStoreIds = new ArrayList<>(duplicatedIds);
}

List<Long> duplicatedIds = allStoreIds.stream()
.filter(e -> allStoreIds.indexOf(e) != allStoreIds.lastIndexOf(e)) //중복된 StoreId가 있는 경우
.distinct() //해당 id를 모아서 1번씩만(중복 제거) 리스트에 담아 전달
.collect(Collectors.toList());
public List<StoreCertification> findStoreCertificationsByLocation(Location northWestLocation, Location southWestLocation, Location southEastLocation, Location northEastLocation) {
return storeCertificationRepository.findStoreCertificationsByLocation(northWestLocation, southWestLocation, southEastLocation, northEastLocation);
}

return duplicatedIds;
public List<Long> getDuplicatedStoreIds() {
return duplicatedStoreIds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ public Optional<StoreCertification> findByStoreIdCertificationId(Long storeId, L
return result.stream().findAny();
}

//북서쪽 좌표와 남동쪽 좌표를 받아 그 좌표로 만들어지는 최소 사각형 내에 위치하는 가게들 리턴
public List<StoreCertification> findStoreCertificationsByLocation(Location northWestLocation, Location southEastLocation) {
//북서쪽 좌표, 남서쪽 좌표, 남동쪽 좌표, 북동쪽 좌표를 받아 그 좌표로 만들어지는 사각형 영역 내에 위치하는 가게들 리턴
public List<StoreCertification> findStoreCertificationsByLocation(Location northWestLocation, Location southWestLocation, Location southEastLocation, Location northEastLocation) {
String pointFormat = String.format(
"'LINESTRING(%f %f, %f %f)'", //POINT는 (경도, 위도) 순이다. 즉, (Logitude, Latitude)순
northWestLocation.getLongitude(), northWestLocation.getLatitude(), southEastLocation.getLongitude(), southEastLocation.getLatitude()
"'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))'", //POINT는 (경도, 위도) 순이다. 즉, (Logitude, Latitude)순
northWestLocation.getLongitude(), northWestLocation.getLatitude(), southWestLocation.getLongitude(), southWestLocation.getLatitude(), southEastLocation.getLongitude(), southEastLocation.getLatitude(), northEastLocation.getLongitude(), northEastLocation.getLatitude(), northWestLocation.getLongitude(), northWestLocation.getLatitude()
);

Query query = em.createNativeQuery("SELECT sc.* " + "FROM store_certification AS sc " + "JOIN store AS s ON sc.store_id = s.store_id " + "JOIN certification AS c ON sc.certification_id = c.certification_id " + "WHERE MBRCONTAINS(ST_LINESTRINGFROMTEXT(" + pointFormat + "), s.location)", StoreCertification.class);
Query query = em.createNativeQuery("SELECT sc.* " + "FROM store_certification AS sc " + "JOIN store AS s ON sc.store_id = s.store_id " + "JOIN certification AS c ON sc.certification_id = c.certification_id " + "WHERE ST_CONTAINS(ST_POLYGONFROMTEXT(" + pointFormat + "), s.location)", StoreCertification.class);

return query.getResultList();
}
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/com/nainga/nainga/global/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.nainga.nainga.global.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.tags.Tag;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class SwaggerConfig {

@Bean
public OpenAPI customOpenAPI() {
//Google Cloud Storage API는 별도로 Swagger에 명세
return new OpenAPI()
.paths(new Paths().addPathItem("https://storage.googleapis.com/{BUCKET_NAME}/{IMAGE_NAME}",
new PathItem().get(new Operation().summary("저장된 가게 이미지 제공")
.description("저장된 가게 이미지를 제공하는 API입니다.<br>" +
"본 API는 Google Cloud Storage에서 제공하는 API로 URL이 위와 같으며 이 정보는 각 가게별 local_photos 필드에 저장되어 있습니다.<br>" +
"Dev 환경에서 BUCKET_NAME은 kcs-dev-bucket1이고 Prod 환경에서 BUCKET_NAME은 kcs-prod-bucket1입니다.<br>" +
"가게 이름은 UUID를 활용한 난수로 제공됩니다.<br>" +
"참고로 Swagger 상에서는 Base URL이 달라 테스트가 불가능합니다.<br>" +
"만약 테스트를 원하신다면 브라우저 상에서 직접 URL을 입력해주시면 됩니다.<br>" +
"예) https://storage.googleapis.com/kcs-dev-bucket1/ad06294c-d4ed-42bd-9839-82af8714bd1e")
.tags(List.of("가게 상세 정보"))
.responses(new ApiResponses().addApiResponse("200",
new ApiResponse().description("OK")
.content(new Content().addMediaType("image/jpeg", new MediaType()
.schema(new Schema<>().type("string")
.format("binary")))))))));
}
}

2 changes: 1 addition & 1 deletion src/main/resources/backend-submodule
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ void findStoreCertificationsByLocation() {
}

//when
Location location1 = new Location(minLongitude - 1.0, minLatitude - 1.0);
Location location2 = new Location(maxLongitude + 1.0, maxLatitude + 1.0);
List<StoreCertification> storeCertificationsByLocation = storeCertificationService.findStoreCertificationsByLocation(location1, location2);
Location location1 = new Location(minLongitude - 1.0, maxLatitude + 1.0);
Location location2 = new Location(minLongitude - 1.0, minLatitude - 1.0);
Location location3 = new Location(maxLongitude + 1.0, minLatitude - 1.0);
Location location4 = new Location(maxLongitude + 1.0, maxLatitude + 1.0);
List<StoreCertification> storeCertificationsByLocation = storeCertificationService.findStoreCertificationsByLocation(location1, location2, location3, location4);

//then
assertThat(storeCertificationsByLocation.size()).isEqualTo(stores.size());
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/backend-submodule
Loading