-
Notifications
You must be signed in to change notification settings - Fork 81
[그리디] 서현진 Spring Core 배포 7, 8, 9 단계 미션 제출합니다. #211
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
base: nonactress
Are you sure you want to change the base?
Changes from all commits
29a3411
76e20ba
6884888
b994a63
9234df4
103e6bb
ecd0c7f
334327e
eeb4f66
a75257b
f95bdc5
c1610e8
aa8870e
9f54ac5
a674fa5
f9f63d1
5ee3e74
cc28fde
b5cca3b
9deeb22
7742db7
0812bd7
8f084a7
4876179
0f3aadf
7a12ebf
b05b545
e83a263
916af1e
48a6984
659c17b
f4f58e9
4c51bea
db04811
1ca9fa1
494fffe
0f655d2
5ce1144
eecfe3a
bd4201c
d4fc462
fd5d1a5
7c953c7
ecf4071
c7303bc
1bfd9e3
3e72013
62a0229
6de128e
d488aff
8bd9234
c5bdf60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,3 +35,5 @@ out/ | |
|
|
||
| ### VS Code ### | ||
| .vscode/ | ||
|
|
||
| **/application-key.properties | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/bin/bash | ||
|
|
||
| echo "==========================================" | ||
| echo "배포 시작" | ||
| echo "==========================================" | ||
|
|
||
| echo ">>> Git Pull" | ||
| git pull origin main | ||
|
|
||
| if [ $? -ne 0 ]; then | ||
| echo "Git Pull 실패" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo ">>> 프로젝트 빌드 시작" | ||
| ./gradlew clean build | ||
|
|
||
| if [ $? -ne 0 ]; then | ||
| echo "빌드 실패" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo ">>> 실행 중인 애플리케이션 확인" | ||
| CURRENT_PID=$(pgrep -f roomescape) | ||
|
|
||
| if [ -z "$CURRENT_PID" ]; then | ||
| echo ">>> 실행 중인 애플리케이션이 없습니다." | ||
| else | ||
| echo ">>> 애플리케이션 종료 (PID: $CURRENT_PID)" | ||
| kill -15 $CURRENT_PID | ||
| sleep 5 | ||
| fi | ||
|
|
||
| echo ">>> 새 애플리케이션 실행" | ||
| nohup java -jar build/libs/roomescape-0.0.1-SNAPSHOT.jar > application.log 2>&1 & | ||
|
|
||
| sleep 3 | ||
|
|
||
| NEW_PID=$(pgrep -f roomescape) | ||
| echo ">>> 배포 완료 (PID: $NEW_PID)" | ||
|
|
||
| echo "==========================================" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| package auth; | ||
|
|
||
| import io.jsonwebtoken.Claims; | ||
| import io.jsonwebtoken.JwtException; | ||
| import io.jsonwebtoken.Jwts; | ||
| import io.jsonwebtoken.SignatureAlgorithm; | ||
|
|
||
| import java.util.Date; | ||
|
|
||
|
|
||
| public class JwtTokenProvider { | ||
| private final String secretKey; | ||
| private final long validityInMilliseconds; | ||
|
|
||
| public JwtTokenProvider(String secretKey, long validityInMilliseconds) { | ||
| this.secretKey = secretKey; | ||
| this.validityInMilliseconds = validityInMilliseconds; | ||
| } | ||
|
|
||
| public String createToken(String payload) { | ||
| Claims claims = Jwts.claims().setSubject(payload); | ||
| Date now = new Date(); | ||
| Date validity = new Date(now.getTime() + validityInMilliseconds); | ||
|
|
||
| return Jwts.builder() | ||
| .setClaims(claims) | ||
| .setIssuedAt(now) | ||
| .setExpiration(validity) | ||
| .signWith(SignatureAlgorithm.HS256, secretKey) | ||
| .compact(); | ||
| } | ||
|
|
||
| public String getPayload(String token) { | ||
| return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); | ||
| } | ||
|
|
||
| public boolean validateToken(String token) { | ||
| try { | ||
| Jwts.parser() | ||
| .setSigningKey(secretKey) | ||
| .parseClaimsJws(token); | ||
| return true; | ||
|
|
||
| } catch (JwtException | IllegalArgumentException e) { | ||
|
|
||
| return false; | ||
| } | ||
| } | ||
| } | ||
|
|
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package roomescape.Loader; | ||
|
|
||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
| import roomescape.member.Member; | ||
| import roomescape.member.MemberRepository; | ||
| import roomescape.reservation.ReservationRepository; | ||
| import roomescape.theme.Theme; | ||
| import roomescape.theme.ThemeRepository; | ||
| import roomescape.time.Time; | ||
| import roomescape.time.TimeRepository; | ||
|
|
||
| @Component | ||
| public class ProductionDataLoader implements CommandLineRunner { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. .sql 파일을 활용하는 대신 CommandLineRunner를 활용했을 때 어떤 차이가 있었나요? 장단점은 있을까요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sql장점 - 퀴리 문으로 작동해서 매우 빠르다 CommandLineRunner장점 - 자바 로직으로 데이터를 만들 수 있다, 복잡한 엔티티 연관관계 보다 쉽게 만들 수 있다! 차이는 속도적인 차이가 존재하고 sql 엔티티 연관관계 구조를 매번 적용 시켜줘야 한다는 단점이 있는 거 같습니다! |
||
|
|
||
| private final MemberRepository memberRepository; | ||
| private final ThemeRepository themeRepository; | ||
| private final TimeRepository timeRepository; | ||
| private final ReservationRepository reservationRepository; | ||
|
|
||
| public ProductionDataLoader( | ||
| MemberRepository memberRepository, | ||
| ThemeRepository themeRepository, | ||
| TimeRepository timeRepository, | ||
| ReservationRepository reservationRepository | ||
| ) { | ||
| this.memberRepository = memberRepository; | ||
| this.themeRepository = themeRepository; | ||
| this.timeRepository = timeRepository; | ||
| this.reservationRepository = reservationRepository; | ||
| } | ||
|
|
||
| @Override | ||
| @Transactional | ||
| public void run(String... args) throws Exception { | ||
| // 1. 관리자 계정 생성 | ||
| if (memberRepository.findByEmail("admin").isEmpty()) { | ||
| Member admin = new Member("admin", "admin", "admin", "ADMIN"); | ||
| memberRepository.save(admin); | ||
| System.out.println("관리자 계정이 생성되었습니다."); | ||
| } | ||
|
|
||
| // 2. 테마 데이터 생성 | ||
| if (themeRepository.count() == 0) { | ||
| Theme theme1 = new Theme("테마1", "테마1입니다."); | ||
| Theme theme2 = new Theme("테마2", "테마2입니다."); | ||
| Theme theme3 = new Theme("테마3", "테마3입니다."); | ||
|
|
||
| themeRepository.save(theme1); | ||
| themeRepository.save(theme2); | ||
| themeRepository.save(theme3); | ||
| System.out.println("테마 데이터가 생성되었습니다."); | ||
| } | ||
|
|
||
| // 3. 시간 데이터 생성 | ||
| if (timeRepository.count() == 0) { | ||
| Time time1 = new Time("10:00"); | ||
| Time time2 = new Time("12:00"); | ||
| Time time3 = new Time("14:00"); | ||
| Time time4 = new Time("16:00"); | ||
| Time time5 = new Time("18:00"); | ||
| Time time6 = new Time("20:00"); | ||
|
|
||
| timeRepository.save(time1); | ||
| timeRepository.save(time2); | ||
| timeRepository.save(time3); | ||
| timeRepository.save(time4); | ||
| timeRepository.save(time5); | ||
| timeRepository.save(time6); | ||
| System.out.println("시간 데이터가 생성되었습니다."); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| package roomescape.Loader; | ||
|
|
||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.context.annotation.Profile; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
| import roomescape.member.Member; | ||
| import roomescape.member.MemberRepository; | ||
| import roomescape.reservation.Reservation; | ||
| import roomescape.reservation.ReservationRepository; | ||
| import roomescape.theme.Theme; | ||
| import roomescape.theme.ThemeRepository; | ||
| import roomescape.time.Time; | ||
| import roomescape.time.TimeRepository; | ||
|
|
||
| @Profile("test") | ||
| @Component | ||
| public class TestDataLoader implements CommandLineRunner { | ||
|
|
||
| private final MemberRepository memberRepository; | ||
| private final ThemeRepository themeRepository; | ||
| private final TimeRepository timeRepository; | ||
| private final ReservationRepository reservationRepository; | ||
|
|
||
| public TestDataLoader( | ||
| MemberRepository memberRepository, | ||
| ThemeRepository themeRepository, | ||
| TimeRepository timeRepository, | ||
| ReservationRepository reservationRepository | ||
| ) { | ||
| this.memberRepository = memberRepository; | ||
| this.themeRepository = themeRepository; | ||
| this.timeRepository = timeRepository; | ||
| this.reservationRepository = reservationRepository; | ||
| } | ||
|
|
||
| @Override | ||
| @Transactional | ||
| public void run(String... args) throws Exception { | ||
| // 1. 관리자 계정 생성 | ||
| if (memberRepository.findByEmail("admin").isEmpty()) { | ||
| Member admin = new Member("admin", "admin", "admin", "ADMIN"); | ||
| memberRepository.save(admin); | ||
| System.out.println("관리자 계정이 생성되었습니다."); | ||
| } | ||
|
|
||
| // 2. 테마 데이터 생성 | ||
| if (themeRepository.count() == 0) { | ||
| Theme theme1 = new Theme("테마1", "테마1입니다."); | ||
| Theme theme2 = new Theme("테마2", "테마2입니다."); | ||
| Theme theme3 = new Theme("테마3", "테마3입니다."); | ||
|
|
||
| themeRepository.save(theme1); | ||
| themeRepository.save(theme2); | ||
| themeRepository.save(theme3); | ||
| System.out.println("테마 데이터가 생성되었습니다."); | ||
| } | ||
|
|
||
| // 3. 시간 데이터 생성 | ||
| if (timeRepository.count() == 0) { | ||
| Time time1 = new Time("10:00"); | ||
| Time time2 = new Time("12:00"); | ||
| Time time3 = new Time("14:00"); | ||
| Time time4 = new Time("16:00"); | ||
| Time time5 = new Time("18:00"); | ||
| Time time6 = new Time("20:00"); | ||
|
|
||
| timeRepository.save(time1); | ||
| timeRepository.save(time2); | ||
| timeRepository.save(time3); | ||
| timeRepository.save(time4); | ||
| timeRepository.save(time5); | ||
| timeRepository.save(time6); | ||
| System.out.println("시간 데이터가 생성되었습니다."); | ||
| } | ||
|
|
||
| if (reservationRepository.count() == 0) { | ||
| Member admin = memberRepository.findByEmail("admin") | ||
| .orElseThrow(() -> new RuntimeException("Admin not found")); | ||
|
|
||
| Time time1 = timeRepository.findById(1L).orElseThrow(); | ||
| Time time2 = timeRepository.findById(2L).orElseThrow(); | ||
| Time time3 = timeRepository.findById(3L).orElseThrow(); | ||
|
|
||
| Theme theme1 = themeRepository.findById(1L).orElseThrow(); | ||
| Theme theme2 = themeRepository.findById(2L).orElseThrow(); | ||
| Theme theme3 = themeRepository.findById(3L).orElseThrow(); | ||
|
|
||
| Reservation reservation1 = new Reservation("", "2024-03-01", time1, theme1, admin); | ||
| Reservation reservation2 = new Reservation("", "2024-03-01", time2, theme2, admin); | ||
| Reservation reservation3 = new Reservation("", "2024-03-01", time3, theme3, admin); | ||
|
|
||
| reservationRepository.save(reservation1); | ||
| reservationRepository.save(reservation2); | ||
| reservationRepository.save(reservation3); | ||
|
|
||
| Reservation reservation4 = new Reservation("브라운", "2024-03-01", time1, theme2); | ||
|
|
||
| reservationRepository.save(reservation4); | ||
| System.out.println("예약 데이터가 생성되었습니다."); | ||
| } | ||
|
|
||
| System.out.println("초기 데이터 로딩이 완료되었습니다."); | ||
| } | ||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package roomescape.exception; | ||
|
|
||
| public class AuthenticationException extends RuntimeException { | ||
|
|
||
| public AuthenticationException(String message) { | ||
| super(message); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package roomescape.exception; | ||
|
|
||
| public record ErrorResponse(String message) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package roomescape.exception; | ||
|
|
||
| import io.jsonwebtoken.ExpiredJwtException; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.ControllerAdvice; | ||
| import org.springframework.web.bind.annotation.ExceptionHandler; | ||
|
|
||
| @ControllerAdvice | ||
| public class GlobalExceptionHandler { | ||
|
|
||
| @ExceptionHandler(IllegalArgumentException.class) | ||
| public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) { | ||
| return ResponseEntity.badRequest() | ||
| .body(new ErrorResponse(e.getMessage())); | ||
| } | ||
|
|
||
| @ExceptionHandler(AuthenticationException.class) | ||
| public ResponseEntity<String> handleAuthenticationException(AuthenticationException e) { | ||
| return ResponseEntity.status(HttpStatus.UNAUTHORIZED) | ||
| .body(e.getMessage()); | ||
| } | ||
|
|
||
| @ExceptionHandler(Exception.class) | ||
| public ResponseEntity<ErrorResponse> handleException(Exception e) { | ||
| return ResponseEntity.internalServerError() | ||
| .body(new ErrorResponse("오류가 발생했습니다.")); | ||
| } | ||
|
|
||
| @ExceptionHandler(ExpiredJwtException.class) | ||
| public ResponseEntity<ErrorResponse> handleExpiredJwtException(ExpiredJwtException e) { | ||
| return ResponseEntity.status(HttpStatus.UNAUTHORIZED) | ||
| .body(new ErrorResponse("토큰 만료 시간 초과")); | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package roomescape.infrastructure; | ||
|
|
||
| import java.lang.annotation.ElementType; | ||
| import java.lang.annotation.Retention; | ||
| import java.lang.annotation.RetentionPolicy; | ||
| import java.lang.annotation.Target; | ||
|
|
||
| @Target(ElementType.PARAMETER) | ||
| @Retention(RetentionPolicy.RUNTIME) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| public @interface AuthMember { | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현진님이 작성해주신 배포스크립트를 활용하면 어떻게 배포할 수 있나요?
즉, 이 배포 스크립트 실행 전에 해야할 사전 작업이 있나요?