-
Notifications
You must be signed in to change notification settings - Fork 97
[그리디] 이채현 SpringCore 7~9단계 제출합니다. #272
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: chaehyunl
Are you sure you want to change the base?
Changes from all commits
d0eac68
53bba1c
24ee8ee
54aee6d
0365054
143eb7d
ecc8025
80053ba
ab18aef
66728ba
74f36bd
f0ce4c0
44ad820
c5ae254
05a06d3
7e0c71b
95f915d
165b552
40aff17
578d9a3
af5ff58
b0692c5
d87a302
4836e92
d808ed6
4c1ffe7
f77ce23
0de02ba
2e26756
4730128
0eae6c3
653e960
8bb5385
488f861
aa2b5fa
8895666
4184b79
3bd4251
ec8004e
8957601
20a948c
f948434
93465ad
2fba555
49b6d7f
13b8925
715960c
a272863
cee6ff6
9fda054
767742f
a3eebbe
262a651
c5cc7a3
6fff1f3
4518389
b9cc04b
31d685e
9c9ae75
e3f65ef
35ebc38
0f3d928
77abb17
cae9a52
dd40b5a
07c4f55
1ff8645
1373c71
3db99b7
80797fa
cd1a819
74c0595
313e5ee
fd3e903
12e9014
7bb3fe5
72b8311
63b2eb1
13f3d39
5405303
6c6a2e9
e52407f
cb1863e
2fb95bf
afcde38
a6013d1
7be91b0
235214c
8fca327
a610636
f188d27
aabe511
b930ef6
10eb09f
129ab0d
bcc5974
9e41a00
315b5ae
1c74bc1
0b719fd
4d167b5
6c2cee4
e152c74
7477b48
d6e9530
1cc41fb
418bb7c
415b116
ce208a9
343886c
95b0f3d
e338ce7
1d08094
c153761
0b1be93
787759e
2a8661e
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 |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| git pull code JPA4 | ||
| ./gradlew clean build | ||
| PID=$(cat application.pid 2>/dev/null) | ||
|
|
||
| if [ -n "$PID" ]; then | ||
| kill -15 "$PID" | ||
| sleep 5 | ||
| fi | ||
|
|
||
| JAR=$(find build/libs -name "*.jar" | head -n 1) | ||
|
|
||
| nohup java -jar "$JAR" > application.log 2>&1 & | ||
|
|
||
| echo $! > application.pid | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,27 +3,28 @@ | |
| 안녕하세요. 세종대학교 그리디 백엔드 4기 이채현입니다. | ||
|
|
||
|
|
||
| --- | ||
| ## Spring MVC 미션 3단계 - 관리자 기능 | ||
|
|
||
| 어드민 페이지 진입은 admin 권한이 있는 사람만 할 수 있도록 제한한다. | ||
| 만약 진입 권한이 없다면 401 코드를 응답하도록 한다. | ||
|
|
||
| --- | ||
| ### 고민한 내용 🤔 | ||
| ## Spring JPA Spring Core 배포 | ||
|
|
||
| - HandlerInterceptor에서 기본적으로 preHandle/postHandle/afterCompletion으로 나뉘어져있던데, | ||
| 이번의 경우에는 admin페이지 접속만을 확인하면 되는거라서 preHandle만을 사용했습니다. | ||
| 이경우에는 postHandle과 afterCompletion을 어떻게 구성하면 좋을지..? 알고 싶네요. | ||
| ### 🚀 7단계 - @Configuration | ||
| JWT 관련 로직을 roomescape와 같은 계층의 auth 패키지의 클래스로 분리하고, | ||
| 불필요한 DB 접근을 최소화하기. | ||
|
|
||
|
|
||
| - WebConfig 같은 경우에는, admin 페이지를 접속할때의 role만을 확인해주면 되므로 /admin/***을 사용해주었습니다. | ||
| ### 🚀 8단계 - Profile과 Resource | ||
|
|
||
|
Comment on lines
+15
to
16
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. Profile과 Resource는 각각 어떤 의미인가요? profile은 어떤거고 언제 사용하나요~?
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. Profile의 경우, 실행 환경에 따라 다른 설정을 사용하기 위한 기능이고, Profile은 어디에서 사용하냐면요, 애플리케이션을 실행하는 환경을 구분해야할때 사용합니다. |
||
| - token 만료시간도 있어야할 것 같아서 expire_time을 이용해서,만료시간을 구현해보았습니다. 만료시간을 구현할 더 좋은 | ||
| 방법이 있을지?? 궁금합니다. | ||
| schema.sql 대신 데이터베이스를 초기화 해주기 위해 실행하는 클래스를 생성. | ||
| 스프링이 실행될 때 동작해야 함. | ||
| token 생성에 필요한 비밀키값을 외부 파일로 분리하기. | ||
|
|
||
| - token을 accessToken과 refreshToken으로 나눠서 구현해주었는데, 구현하다보니 너무 어려워서 제대로 구현된건지 잘 | ||
| 모르겠습니다. | ||
| ### 🚀 9단계 - 배포 스크립트 | ||
|
|
||
| ec2나 서버에서 배포를 할 수 있게 배포 스크립트를 작성하기. | ||
|
|
||
| --- | ||
| ### 고민한 내용 🤔 | ||
| 1. JwtProvider를 auth package를 생성해서,JwtConfig와 JwtUtils로 분리해줬는데, 이렇게 구성하면 장점이 궁금합니다. | ||
|
|
||
| 배포스크립트와 초기 설정의 시나리오가 어떻게 사용되는지 잘 모르겠습니다... | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package auth; | ||
|
|
||
| import io.jsonwebtoken.security.Keys; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| import java.nio.charset.StandardCharsets; | ||
| import java.security.Key; | ||
|
|
||
| @Configuration | ||
| public class JwtConfig { | ||
| @Bean | ||
| public JwtUtils jwtUtils(@Value("${roomescape.auth.jwt.secret}")String secret){ | ||
| Key key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); | ||
| return new JwtUtils(key); | ||
| } | ||
|
Comment on lines
+13
to
+17
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. config에서 하고 있는 것은 무엇일까요? 그럼 그것을 할때 이점은 없을까요?
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. config의 역할 소프트웨어 설정 저장/ 시스템 및 네트워크 구성 관리/ 보안 및 접근 제어 입니다. 비밀키의 변경이 용이하게 config를 통해 가능하게 됩니다 |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package auth; | ||
|
|
||
| import io.jsonwebtoken.Claims; | ||
| import io.jsonwebtoken.Jwts; | ||
| import roomescape.member.Member; | ||
|
|
||
| import java.security.Key; | ||
| import java.util.Date; | ||
|
|
||
|
|
||
| public class JwtUtils { | ||
| private final Key secretKey; | ||
| private final long expireAccessTime = 30L * 60 * 1000; | ||
| private final long expireRefreshTime = 14L * 24 * 60 * 60 * 1000; | ||
|
|
||
| public JwtUtils(Key secretKey) { | ||
| this.secretKey = secretKey; | ||
| } | ||
|
|
||
| public String createAccessToken(Member member) { | ||
| return createToken(member.getId(),expireAccessTime); | ||
| } | ||
|
|
||
| public String createRefreshToken(Member member) { | ||
| return createToken(member.getId(),expireRefreshTime); | ||
| } | ||
| private String createToken(Long memberId, long expireTime){ | ||
| Date now= new Date(); | ||
|
|
||
| return Jwts.builder() | ||
| .setSubject(memberId.toString()) | ||
| .setIssuedAt(now) | ||
| .setExpiration(new Date(now.getTime()+expireTime)) | ||
| .signWith(secretKey) | ||
| .compact(); | ||
| } | ||
|
|
||
| public Long getMemberId(String token) { | ||
| Claims claims = parseClaims(token); | ||
| return Long.parseLong(claims.getSubject()); | ||
| } | ||
|
|
||
| private Claims parseClaims(String token) { | ||
| try { | ||
| return Jwts.parserBuilder() | ||
| .setSigningKey(secretKey) | ||
| .build() | ||
| .parseClaimsJws(token) | ||
| .getBody(); | ||
| } catch (Exception e) { | ||
| throw new IllegalArgumentException("유효하지 않거나 만료된 토큰입니다.", e); | ||
| } | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package roomescape.dataLoader; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.stereotype.Component; | ||
| import roomescape.member.Member; | ||
| import roomescape.member.MemberRepository; | ||
|
|
||
|
|
||
| @Component | ||
| public class DataLoader implements CommandLineRunner { | ||
|
|
||
| @Autowired | ||
| private MemberRepository memberRepository; | ||
|
|
||
| public DataLoader(MemberRepository memberRepository) { | ||
| this.memberRepository = memberRepository; | ||
| } | ||
|
|
||
| @Override | ||
| public void run(String ...args){ | ||
| if(memberRepository.count()>0){ | ||
| return; | ||
| } | ||
|
|
||
| Member admin= Member.builder() | ||
| .name("어드민") | ||
| .email("admin@email.com") | ||
| .password("password") | ||
| .role("ADMIN").build(); | ||
|
|
||
| Member brown= Member.builder() | ||
| .name("브라운") | ||
| .email("brown@email.com") | ||
| .password("password") | ||
| .role("USER").build(); | ||
|
|
||
| memberRepository.save(admin); | ||
| memberRepository.save(brown); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| package roomescape.dataLoader; | ||
|
|
||
|
|
||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.stereotype.Component; | ||
| 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; | ||
|
|
||
| @Component | ||
| public class TestDataLoader implements CommandLineRunner { | ||
|
Comment on lines
+16
to
+17
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. 현재 이 TestDataLoader는 어떤 역할을 하고 있나요?
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. 테스트용 데이터를 대신 생성해주고 있습니다 |
||
|
|
||
| @Autowired | ||
| private final ThemeRepository themeRepository; | ||
| private final TimeRepository timeRepository; | ||
| private final ReservationRepository reservationRepository; | ||
| private final MemberRepository memberRepository; | ||
|
|
||
| public TestDataLoader(ThemeRepository themeRepository, TimeRepository timeRepository, | ||
| ReservationRepository reservationRepository, MemberRepository memberRepository) { | ||
| this.themeRepository = themeRepository; | ||
| this.timeRepository = timeRepository; | ||
| this.reservationRepository = reservationRepository; | ||
| this.memberRepository = memberRepository; | ||
| } | ||
|
|
||
| @Override | ||
| public void run(String... args) { | ||
| Member admin = memberRepository.findByName("ADMIN") | ||
| .orElseThrow(); | ||
| Member brown = memberRepository.findByName("브라운") | ||
| .orElseThrow(); | ||
| if (themeRepository.count() > 0) { | ||
| return; | ||
| } | ||
| Theme theme1 = Theme.builder() | ||
| .name("테마1") | ||
| .description("테마1입니다.") | ||
| .build(); | ||
| Theme theme2 = Theme.builder() | ||
| .name("테마2") | ||
| .description("테마2입니다.") | ||
| .build(); | ||
| Theme theme3 = Theme.builder() | ||
| .name("테마3") | ||
| .description("테마3입니다.") | ||
| .build(); | ||
|
|
||
| themeRepository.save(theme1); | ||
| themeRepository.save(theme2); | ||
| themeRepository.save(theme3); | ||
|
|
||
| if (timeRepository.count() > 0) { | ||
| return; | ||
| } | ||
| Time time1 = Time.builder() | ||
| .value("10:00") | ||
| .build(); | ||
| Time time2 = Time.builder() | ||
| .value("12:00") | ||
| .build(); | ||
| Time time3 = Time.builder() | ||
| .value("14:00") | ||
| .build(); | ||
| Time time4 = Time.builder() | ||
| .value("16:00") | ||
| .build(); | ||
| Time time5 = Time.builder() | ||
| .value("18:00") | ||
| .build(); | ||
| Time time6 = Time.builder() | ||
| .value("20:00") | ||
| .build(); | ||
| timeRepository.save(time1); | ||
| timeRepository.save(time2); | ||
| timeRepository.save(time3); | ||
| timeRepository.save(time4); | ||
| timeRepository.save(time5); | ||
| timeRepository.save(time6); | ||
|
|
||
| reservationRepository.save( | ||
| Reservation.builder() | ||
| .member(admin) | ||
| .date("2024-03-01") | ||
| .time(time1) | ||
| .theme(theme1) | ||
| .build()); | ||
| reservationRepository.save( | ||
| Reservation.builder() | ||
| .member(admin) | ||
| .date("2024-03-01") | ||
| .time(time2) | ||
| .theme(theme2) | ||
| .build()); | ||
| reservationRepository.save( | ||
| Reservation.builder() | ||
| .member(brown) | ||
| .date("2024-03-01") | ||
| .time(time3) | ||
| .theme(theme3) | ||
| .build()); | ||
| } | ||
| } | ||
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.
이 과정이 어떤 과정인지 옆에 주석으로 달아주셔도 좋을 것 같아요!
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.
이 부분을 ai 도움을 많이 받은 것 같습니다.
아직 script 파일이 어떻게 작성되어야 하고 어떻게 쓰여야 하는지 잘 감이 안 잡힙니다.
제가 봤을때는 docs README 파일과 차이를 잘 모르겠다는 느낌이 드는 것 같아요
주석은 달았습니다 ~~!!.