-
Notifications
You must be signed in to change notification settings - Fork 97
[그리디] 김하은 SpringCore 7~9단계 제출합니다. #273
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: haeun92e0
Are you sure you want to change the base?
Changes from 85 commits
37ab4da
636c329
aa182a6
684129b
444e69f
e709d8b
7e42eac
da54f46
2745e21
b3887e3
851bbb2
0c3ad92
e598d30
dbaca0e
9ab6dd4
69c254f
dcac4d5
8ac2b26
c8637cb
0fb712b
003edd0
c867706
742e87c
2b8cc3e
8f542e3
e0fddd8
8b8425e
e1ed30c
2acc84a
677f89c
2718e57
1358c45
23d64ec
f35bcce
d1f60ed
b16169c
67f2b5d
9dee51b
6fe77db
4b66a8a
83027f1
a41d855
b8ec630
6f933e3
a0739e4
0de5f6f
50cf9f1
8cacf2b
84b8803
bcce22a
4d29436
4b65edf
e983b1f
201e1c8
fb5bc19
0429594
c3a64fc
b127cc2
01af716
20d17b0
0fc47d8
9b3d82e
cfcb3e8
bfc4174
ddbe201
3faa466
e8358f3
cc529cb
e9f37b1
1200212
01fcd88
d2f7a45
5fd4511
019bdd4
f02356f
08b0015
6205791
5b295d1
a7ef5b0
88cdd15
722a5ea
920088e
d6a99a4
be70672
77f7d71
000896a
1ef73f4
bf0aea5
209a9ce
dd4b8c2
f95aa63
501779d
985e5c1
2e146eb
4b46f91
f8521e1
df8025f
1d863b8
5773213
bbaa9ba
58740bf
f43cbba
5d09da9
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,29 @@ | ||
| #!/bin/bash | ||
|
|
||
| # 1. 최신 코드 불러오기 | ||
| echo ">>> Git Pull 실행" | ||
| git pull origin main | ||
|
|
||
| # 2. 프로젝트 빌드 | ||
| echo ">>> 프로젝트 빌드 시작" | ||
| ./gradlew build -x test | ||
|
|
||
| # 3. 기존 실행 중인 프로세스 종료 | ||
| echo ">>> 기존 애플리케이션 PID 확인" | ||
| CURRENT_PID=$(pgrep -f roomescape-0.0.1-SNAPSHOT.jar) | ||
|
|
||
| if [ -z "$CURRENT_PID" ]; then | ||
| echo ">>> 실행 중인 애플리케이션이 없습니다." | ||
| else | ||
| echo ">>> 기존 애플리케이션 종료 (PID: $CURRENT_PID)" | ||
| kill -15 $CURRENT_PID | ||
| sleep 5 | ||
| fi | ||
|
|
||
| # 4. 새 애플리케이션 실행 | ||
| echo ">>> 새 애플리케이션 배포 및 실행" | ||
| JAR_NAME=$(ls -tr build/libs/*.jar | tail -n 1) | ||
|
|
||
| nohup java -jar $JAR_NAME > app.log 2>&1 & | ||
|
|
||
| echo ">>> 배포 완료!" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package roomescape; | ||
|
|
||
|
|
||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.context.annotation.Profile; | ||
| import org.springframework.stereotype.Component; | ||
| import roomescape.member.Member; | ||
| import roomescape.member.MemberRepository; | ||
| import roomescape.theme.Theme; | ||
| import roomescape.theme.ThemeRepository; | ||
| import roomescape.time.Time; | ||
| import roomescape.time.TimeRepository; | ||
|
|
||
| @Profile("!test") //테스트 환경이 아닐때 실행되게 하는 기능 | ||
| @Component | ||
| public class DataLoader implements CommandLineRunner { | ||
|
|
||
| private final MemberRepository memberRepository; | ||
| private final ThemeRepository themeRepository; | ||
| private final TimeRepository timeRepository; | ||
|
|
||
| public DataLoader(MemberRepository memberRepository, ThemeRepository themeRepository, TimeRepository timeRepository) { | ||
| this.memberRepository = memberRepository; | ||
| this.themeRepository = themeRepository; | ||
| this.timeRepository = timeRepository; | ||
| } | ||
|
|
||
| @Override | ||
| public void run(String... args) throws Exception { | ||
| // 1. 회원 저장 (ID: 1, 2) | ||
| memberRepository.save(new Member("어드민", "admin@email.com", "password", "ADMIN")); | ||
| memberRepository.save(new Member("브라운", "brown@email.com", "password", "USER")); | ||
|
|
||
| // 2. 테마 저장 | ||
| themeRepository.save(new Theme("테마1", "테마1입니다.")); | ||
| themeRepository.save(new Theme("테마2", "테마2입니다.")); | ||
| themeRepository.save(new Theme("테마3", "테마3입니다.")); | ||
|
|
||
| // 3. 시간 저장 | ||
| timeRepository.save(new Time("10:00")); | ||
| timeRepository.save(new Time("12:00")); | ||
| timeRepository.save(new Time("14:00")); | ||
| timeRepository.save(new Time("16:00")); | ||
| timeRepository.save(new Time("18:00")); | ||
| timeRepository.save(new Time("20:00")); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package roomescape; | ||
|
|
||
|
|
||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.context.annotation.Profile; | ||
| 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; | ||
|
|
||
| @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 | ||
| public void run(String... args) throws Exception { | ||
| // 1. 회원 저장 (1L: 어드민, 2L: 브라운) | ||
| Member admin = memberRepository.save(new Member("어드민", "admin@email.com", "password", "ADMIN")); | ||
| Member brown = memberRepository.save(new Member("브라운", "brown@email.com", "password", "USER")); | ||
|
|
||
| // 2. 테마 저장 | ||
| Theme theme1 = themeRepository.save(new Theme("테마1", "테마1입니다.")); | ||
| Theme theme2 = themeRepository.save(new Theme("테마2", "테마2입니다.")); | ||
| Theme theme3 = themeRepository.save(new Theme("테마3", "테마3입니다.")); | ||
|
|
||
| // 3. 시간 저장 | ||
| Time time1 = timeRepository.save(new Time("10:00")); | ||
| Time time2 = timeRepository.save(new Time("12:00")); | ||
| Time time3 = timeRepository.save(new Time("14:00")); | ||
|
|
||
| // 4. 5단계, 6단계 테스트에서 요구하는 예약 데이터 저장 | ||
| reservationRepository.save(new Reservation("어드민", "2024-03-01", time1, theme1, admin)); | ||
| reservationRepository.save(new Reservation("어드민", "2024-03-01", time1, theme2, admin)); | ||
| reservationRepository.save(new Reservation("어드민", "2024-03-01", time3, theme3, admin)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package roomescape.auth; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| @Configuration | ||
| public class AuthConfig { | ||
|
|
||
| @Value("${roomescape.auth.jwt.secret}") | ||
| private String secretKey; | ||
|
|
||
| @Bean | ||
| public JwtUtils jwtUtils() { | ||
| // 1시간(3600000ms) 만료 기준 | ||
| return new JwtUtils(secretKey, 3600000L); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package roomescape.auth; | ||
|
|
||
| import io.jsonwebtoken.Claims; | ||
| import io.jsonwebtoken.Jwts; | ||
| import io.jsonwebtoken.security.Keys; | ||
|
|
||
| import java.nio.charset.StandardCharsets; | ||
| import java.security.Key; | ||
| import java.util.Date; | ||
|
|
||
| public class JwtUtils { | ||
|
|
||
| private final String secretKey; | ||
| private final long validityInMilliseconds; | ||
|
|
||
| public JwtUtils(String secretKey, long validityInMilliseconds) { | ||
| this.secretKey = secretKey; | ||
| this.validityInMilliseconds = validityInMilliseconds; | ||
| } | ||
|
|
||
| private Key getSigningKey() { | ||
| return Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); | ||
| } | ||
|
|
||
| public String createToken(String id, String role) { | ||
| Claims claims = Jwts.claims().setSubject(id); | ||
| claims.put("role", role); | ||
|
|
||
| Date now = new Date(); | ||
| Date validity = new Date(now.getTime() + validityInMilliseconds); | ||
|
|
||
| return Jwts.builder() | ||
| .setClaims(claims) | ||
| .setIssuedAt(now) | ||
| .setExpiration(validity) | ||
| .signWith(getSigningKey()) | ||
| .compact(); | ||
| } | ||
|
|
||
| public Claims parseToken(String token) { | ||
| return Jwts.parserBuilder() | ||
| .setSigningKey(getSigningKey()) | ||
| .build() | ||
| .parseClaimsJws(token) | ||
| .getBody(); | ||
| } | ||
| } |
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,19 +6,20 @@ | |
| import jakarta.servlet.http.Cookie; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import org.springframework.core.MethodParameter; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.web.bind.support.WebDataBinderFactory; | ||
| import org.springframework.web.context.request.NativeWebRequest; | ||
| import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
| import org.springframework.web.method.support.ModelAndViewContainer; | ||
| import roomescape.auth.JwtUtils; | ||
|
|
||
| //컨트롤러의 매개변수를 자동으로 만들어주는 클래스 | ||
| @Component | ||
| public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { | ||
| private final JwtTokenProvider jwtTokenProvider; | ||
| private final MemberRepository memberRepository; | ||
| private final JwtUtils jwtUtils; | ||
|
|
||
| public LoginMemberArgumentResolver(JwtTokenProvider jwtTokenProvider,MemberRepository memberRepository){ | ||
| this.jwtTokenProvider = jwtTokenProvider; | ||
| this.memberRepository = memberRepository; | ||
| public LoginMemberArgumentResolver(JwtUtils jwtUtils){ | ||
| this.jwtUtils = jwtUtils; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -30,30 +31,28 @@ public boolean supportsParameter(MethodParameter parameter) { | |
| public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, | ||
| NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { | ||
| HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); //현재 HTTP 요청 가져오기 | ||
| Cookie[] cookies = request.getCookies(); //쿠키 가져오기 | ||
| String token = extractToken(request); | ||
|
|
||
| if (cookies == null) { | ||
| throw new IllegalArgumentException("토큰 쿠키가 존재하지 않습니다."); | ||
| if (token == null) { | ||
| throw new IllegalArgumentException("토큰이 존재하지 않습니다."); | ||
| } | ||
|
|
||
| String token = ""; | ||
| for (Cookie cookie : cookies) { | ||
| if ("token".equals(cookie.getName())) {//이름이 token인 쿠키 찾기 | ||
| token = cookie.getValue(); //JWT 문자열 저장 | ||
| } | ||
| } | ||
|
|
||
| if(token.isBlank()){ | ||
| throw new IllegalArgumentException("토큰 값이 비어있습니다."); | ||
| } | ||
|
|
||
| // 토큰 파싱하여 회원 정보 추출 | ||
| Claims claims = jwtTokenProvider.parseToken(token); | ||
| //정보 꺼내기 | ||
| Claims claims = jwtUtils.parseToken(token); | ||
| Long id = Long.parseLong(claims.getSubject()); | ||
| String role = claims.get("role", String.class); | ||
| return new Member(id, role); // 필요한 id와 role만 가진 객체 반환 | ||
|
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. 현재 로그인한 회원도 예약 생성이 되지 않습니다. 왜일까요?
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. 앗... new Member(id, role) 객체를 직접 생성했더니, name이나 email이 null 상태가 되어 예약 생성 시 에러가 발생한 것 같습니다. |
||
| } | ||
|
|
||
| return memberRepository.findById(id) | ||
| .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다.")); | ||
| private String extractToken(HttpServletRequest request) { | ||
| Cookie[] cookies = request.getCookies(); | ||
| if (cookies != null) { | ||
| for (Cookie cookie : cookies) { | ||
| if ("token".equals(cookie.getName())) { | ||
| return cookie.getValue(); | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
| //브라우저가 보낸 JWT 쿠키를 읽어서 그 안에 저장된 회원 정보를 Member 객체로 복원한 뒤, 컨트롤러의 Member loginMember 매개변수에 자동으로 | ||
|
|
||
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.
@Component로 관리되고 있는 LoginMemberArgumentResolver를 new로 새로 생성할 필요가 있을까요?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.
오마이갓 수정했습니다!! 감사합니다!!