From 5913de1c9b8c526826ad7f5a56829b0a788b0a6e Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:01:44 +0900 Subject: [PATCH 01/49] =?UTF-8?q?=20gradle=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index 8d52aebc..d5f9249b 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-validation' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' implementation 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.0.0' From 67da61712a7cf9a359fab80da10dd0887afbb752 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:14:33 +0900 Subject: [PATCH 02/49] =?UTF-8?q?=20=ED=86=A0=ED=81=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=20=EC=9D=B8=EC=A6=9D=20=EB=B0=A9=EC=8B=9D=20jwt=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/jwt/JwtProvider.java | 31 +++++++++ src/main/java/roomescape/jwt/JwtResponse.java | 6 ++ src/main/java/roomescape/jwt/JwtUtils.java | 65 +++++++++++++++++++ src/main/resources/application.properties | 3 +- 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/main/java/roomescape/jwt/JwtProvider.java create mode 100644 src/main/java/roomescape/jwt/JwtResponse.java create mode 100644 src/main/java/roomescape/jwt/JwtUtils.java diff --git a/src/main/java/roomescape/jwt/JwtProvider.java b/src/main/java/roomescape/jwt/JwtProvider.java new file mode 100644 index 00000000..8a4c5a56 --- /dev/null +++ b/src/main/java/roomescape/jwt/JwtProvider.java @@ -0,0 +1,31 @@ +package roomescape.jwt; + +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import roomescape.exception.JwtProviderException; +import roomescape.member.Member; + +@Component +public class JwtProvider { + + @Value("${roomescape.auth.jwt.secret}") + private String secretKey; + + public JwtResponse createAccessToken(Member member) { + try { + String accessToken = Jwts.builder() + .setSubject(member.getId().toString()) + .claim("name", member.getName()) + .claim("role", member.getRole()) + .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) + .compact(); + + return new JwtResponse(accessToken); + } catch (JwtException e) { + throw new JwtProviderException("JWT 생성에 실패하였습니다."); + } + } +} diff --git a/src/main/java/roomescape/jwt/JwtResponse.java b/src/main/java/roomescape/jwt/JwtResponse.java new file mode 100644 index 00000000..8d9ae9d9 --- /dev/null +++ b/src/main/java/roomescape/jwt/JwtResponse.java @@ -0,0 +1,6 @@ +package roomescape.jwt; + +public record JwtResponse( + String accessToken +) { +} diff --git a/src/main/java/roomescape/jwt/JwtUtils.java b/src/main/java/roomescape/jwt/JwtUtils.java new file mode 100644 index 00000000..1c0c5a18 --- /dev/null +++ b/src/main/java/roomescape/jwt/JwtUtils.java @@ -0,0 +1,65 @@ +package roomescape.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.Cookie; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import roomescape.authentication.MemberAuthInfo; +import roomescape.exception.JwtValidationException; + +import java.util.Arrays; + +@Component +@RequiredArgsConstructor +public class JwtUtils { + + private static String secretKey; + + @Value("${roomescape.auth.jwt.secret}") + public void setSecretKey(String secretKey) { + JwtUtils.secretKey = secretKey; + } + + public static MemberAuthInfo extractMemberAuthInfoFromToken(String token) { + if (token == null || token.isEmpty()) { + throw new JwtValidationException("토큰이 존재하지 않습니다."); + } + + try { + Claims claims = Jwts.parserBuilder() + .setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes())) + .build() + .parseClaimsJws(token) + .getBody(); + + String name = claims.get("name", String.class); + String role = claims.get("role", String.class); + + return new MemberAuthInfo(name, role); + } catch (JwtException e) { + throw new JwtValidationException("유효하지 않은 JWT 토큰입니다."); + } + } + + public static JwtResponse extractTokenFromCookie(Cookie[] cookies) { + if (cookies == null) { + throw new JwtValidationException("쿠키가 존재하지 않습니다."); + } + + try { + String accessToken = Arrays.stream(cookies) + .filter(cookie -> cookie.getName().equals("token")) + .map(Cookie::getValue) + .findFirst() + .orElseThrow(() -> new JwtValidationException("토큰이 존재하지 않습니다.")); + + return new JwtResponse(accessToken); + } catch (Exception e) { + throw new JwtValidationException("쿠키에서 토큰 추출 중 오류가 발생했습니다."); + } + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a0f33bba..5cfe2f4f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -8,4 +8,5 @@ spring.datasource.url=jdbc:h2:mem:database #spring.jpa.ddl-auto=create-drop #spring.jpa.defer-datasource-initialization=true -#roomescape.auth.jwt.secret= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= \ No newline at end of file +roomescape.auth.jwt.secret=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5Eaadfasdfsadfsafdsa2df= +server.connection-timeout=60s From 53828d83dd0774e6235d390097d16ecf90317060 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:19:36 +0900 Subject: [PATCH 03/49] =?UTF-8?q?=20MemberRequest=20DTO=EB=A5=BC=20re?= =?UTF-8?q?cord=20=ED=98=95=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/member/MemberRequest.java | 21 +++++-------------- .../java/roomescape/member/MemberService.java | 2 +- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/main/java/roomescape/member/MemberRequest.java b/src/main/java/roomescape/member/MemberRequest.java index cafb79f1..d3258382 100644 --- a/src/main/java/roomescape/member/MemberRequest.java +++ b/src/main/java/roomescape/member/MemberRequest.java @@ -1,19 +1,8 @@ package roomescape.member; -public class MemberRequest { - private String name; - private String email; - private String password; - - public String getName() { - return name; - } - - public String getEmail() { - return email; - } - - public String getPassword() { - return password; - } +public record MemberRequest( + String name, + String email, + String password +) { } diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index ccaa8cba..bec76725 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -11,7 +11,7 @@ public MemberService(MemberDao memberDao) { } public MemberResponse createMember(MemberRequest memberRequest) { - Member member = memberDao.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER")); + Member member = memberDao.save(new Member(memberRequest.name(), memberRequest.email(), memberRequest.password(), "USER")); return new MemberResponse(member.getId(), member.getName(), member.getEmail()); } } From 0ec518608d52eb7760c5173ab48a38ac6169faff Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:22:17 +0900 Subject: [PATCH 04/49] =?UTF-8?q?=20jwt=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B0=8F=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/login/LoginCheckResponse.java | 4 ++ .../roomescape/login/LoginController.java | 54 +++++++++++++++++++ .../java/roomescape/login/LoginRequest.java | 15 ++++++ .../java/roomescape/login/LoginService.java | 39 ++++++++++++++ .../roomescape/member/MemberController.java | 14 ----- 5 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 src/main/java/roomescape/login/LoginCheckResponse.java create mode 100644 src/main/java/roomescape/login/LoginController.java create mode 100644 src/main/java/roomescape/login/LoginRequest.java create mode 100644 src/main/java/roomescape/login/LoginService.java diff --git a/src/main/java/roomescape/login/LoginCheckResponse.java b/src/main/java/roomescape/login/LoginCheckResponse.java new file mode 100644 index 00000000..c113663f --- /dev/null +++ b/src/main/java/roomescape/login/LoginCheckResponse.java @@ -0,0 +1,4 @@ +package roomescape.login; + +public record LoginCheckResponse(String name) { +} diff --git a/src/main/java/roomescape/login/LoginController.java b/src/main/java/roomescape/login/LoginController.java new file mode 100644 index 00000000..7d4ae7f2 --- /dev/null +++ b/src/main/java/roomescape/login/LoginController.java @@ -0,0 +1,54 @@ +package roomescape.login; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import roomescape.authentication.MemberAuthInfo; +import roomescape.jwt.JwtResponse; +import roomescape.jwt.JwtUtils; + +@RestController +@RequiredArgsConstructor +public class LoginController { + + private final LoginService loginService; + + @PostMapping("/login") + public ResponseEntity login(@Valid @RequestBody LoginRequest loginRequest, HttpServletResponse response) { + JwtResponse jwtResponse = loginService.login(loginRequest); + + Cookie cookie = new Cookie("token", jwtResponse.accessToken()); + cookie.setHttpOnly(true); + cookie.setPath("/"); + response.addCookie(cookie); + + return ResponseEntity.ok().build(); + } + + @GetMapping("/login/check") + public ResponseEntity checkLogin(HttpServletRequest request) { + JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); + MemberAuthInfo memberAuthInfo = JwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); + LoginCheckResponse loginCheckResponse = loginService.checkLogin(memberAuthInfo); + + return ResponseEntity.ok(loginCheckResponse); + } + + @PostMapping("/logout") + public ResponseEntity logout(HttpServletResponse response) { + Cookie cookie = new Cookie("token", ""); + cookie.setHttpOnly(true); + cookie.setPath("/"); + cookie.setMaxAge(0); + response.addCookie(cookie); + + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/roomescape/login/LoginRequest.java b/src/main/java/roomescape/login/LoginRequest.java new file mode 100644 index 00000000..525f6286 --- /dev/null +++ b/src/main/java/roomescape/login/LoginRequest.java @@ -0,0 +1,15 @@ +package roomescape.login; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +@Data +public class LoginRequest { + + @NotEmpty + private String email; + + @NotEmpty + private String password; + +} diff --git a/src/main/java/roomescape/login/LoginService.java b/src/main/java/roomescape/login/LoginService.java new file mode 100644 index 00000000..680130fa --- /dev/null +++ b/src/main/java/roomescape/login/LoginService.java @@ -0,0 +1,39 @@ +package roomescape.login; + +import lombok.RequiredArgsConstructor; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.stereotype.Service; +import roomescape.authentication.MemberAuthInfo; +import roomescape.jwt.JwtProvider; +import roomescape.jwt.JwtResponse; +import roomescape.member.Member; +import roomescape.member.MemberDao; +import roomescape.exception.MemberNotFoundException; + +@Service +@RequiredArgsConstructor +public class LoginService { + + private final MemberDao memberDao; + private final JwtProvider jwtProvider; + + public JwtResponse login(LoginRequest loginRequest) { + + try { + Member member = memberDao.findByEmailAndPassword(loginRequest.getEmail(), loginRequest.getPassword()); + return jwtProvider.createAccessToken(member); + } catch (EmptyResultDataAccessException e) { + throw new MemberNotFoundException("이메일 혹은 비밀번호가 맞지 않습니다."); + } + } + + public LoginCheckResponse checkLogin(MemberAuthInfo memberAuthInfo) { + + try { + Member member = memberDao.findByName(memberAuthInfo.name()); + return new LoginCheckResponse(member.getName()); + } catch (EmptyResultDataAccessException e) { + throw new MemberNotFoundException("로그인이 되지 않은 상태입니다."); + } + } +} diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 881ae5e0..43c1dcd6 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -1,10 +1,6 @@ package roomescape.member; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -24,14 +20,4 @@ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { MemberResponse member = memberService.createMember(memberRequest); return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member); } - - @PostMapping("/logout") - public ResponseEntity logout(HttpServletResponse response) { - Cookie cookie = new Cookie("token", ""); - cookie.setHttpOnly(true); - cookie.setPath("/"); - cookie.setMaxAge(0); - response.addCookie(cookie); - return ResponseEntity.ok().build(); - } } From ebf6407488b34fb4358289b7c087bf8a976d6348 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:43:12 +0900 Subject: [PATCH 05/49] =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=EC=9D=B8=20Mem?= =?UTF-8?q?berAuthInfo=EB=A5=BC=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20H?= =?UTF-8?q?andlerMethodArgumentResolver=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LoginMemberArgumentResolver.java | 38 +++++++++++++++++++ .../authentication/MemberAuthInfo.java | 6 +++ 2 files changed, 44 insertions(+) create mode 100644 src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java create mode 100644 src/main/java/roomescape/authentication/MemberAuthInfo.java diff --git a/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java b/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java new file mode 100644 index 00000000..d4f7b301 --- /dev/null +++ b/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java @@ -0,0 +1,38 @@ +package roomescape.authentication; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +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.context.request.ServletWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import roomescape.jwt.JwtProvider; +import roomescape.jwt.JwtResponse; +import roomescape.jwt.JwtUtils; + +@Component +@RequiredArgsConstructor +public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { + + private final JwtProvider jwtProvider; + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.getParameterType().equals(MemberAuthInfo.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest request = ((ServletWebRequest) webRequest).getRequest(); + + JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); + if (jwtResponse.accessToken() == null) { + return null; + } + + return JwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); + } +} diff --git a/src/main/java/roomescape/authentication/MemberAuthInfo.java b/src/main/java/roomescape/authentication/MemberAuthInfo.java new file mode 100644 index 00000000..d2d2027f --- /dev/null +++ b/src/main/java/roomescape/authentication/MemberAuthInfo.java @@ -0,0 +1,6 @@ +package roomescape.authentication; + +public record MemberAuthInfo( + String name, + String role) { +} From 22f9e301f76b3be0309b181049f513866266aa92 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:45:19 +0900 Subject: [PATCH 06/49] =?UTF-8?q?=20HandlerMethodArgumentResolver=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=20API=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/reservation/ReservationController.java | 10 ++++++++-- .../roomescape/reservation/ReservationRequest.java | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index b3bef399..0ef4bae8 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import roomescape.authentication.MemberAuthInfo; import java.net.URI; import java.util.List; @@ -26,13 +27,18 @@ public List list() { } @PostMapping("/reservations") - public ResponseEntity create(@RequestBody ReservationRequest reservationRequest) { - if (reservationRequest.getName() == null + public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, MemberAuthInfo memberAuthInfo) { + if ( memberAuthInfo == null || reservationRequest.getDate() == null || reservationRequest.getTheme() == null || reservationRequest.getTime() == null) { return ResponseEntity.badRequest().build(); } + + if (reservationRequest.getName() == null) { + reservationRequest.setName(memberAuthInfo.name()); + } + ReservationResponse reservation = reservationService.save(reservationRequest); return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())).body(reservation); diff --git a/src/main/java/roomescape/reservation/ReservationRequest.java b/src/main/java/roomescape/reservation/ReservationRequest.java index 19f44124..a07a8483 100644 --- a/src/main/java/roomescape/reservation/ReservationRequest.java +++ b/src/main/java/roomescape/reservation/ReservationRequest.java @@ -21,4 +21,8 @@ public Long getTheme() { public Long getTime() { return time; } + + public void setName(String name) { + this.name = name; + } } From 347d0c7a8539a6ccfd4945550078d650d45304c0 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:48:15 +0900 Subject: [PATCH 07/49] =?UTF-8?q?=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthAdminRoleInterceptor.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java diff --git a/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java b/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java new file mode 100644 index 00000000..61ea6d5c --- /dev/null +++ b/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java @@ -0,0 +1,33 @@ +package roomescape.authentication; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import roomescape.jwt.JwtProvider; +import roomescape.jwt.JwtResponse; +import roomescape.jwt.JwtUtils; + +@Component +@RequiredArgsConstructor +public class AuthAdminRoleInterceptor implements HandlerInterceptor { + + private final JwtProvider jwtProvider; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); + if (jwtResponse.accessToken() == null || !isAdmin(jwtResponse.accessToken())) { + response.setStatus(401); + return false; + } + + return true; + } + + private boolean isAdmin(String token) { + MemberAuthInfo memberAuthInfo = JwtUtils.extractMemberAuthInfoFromToken(token); + return "ADMIN".equals(memberAuthInfo.role()); + } +} From 2a96836353946561d89c24b767258271150a2b1e Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:50:54 +0900 Subject: [PATCH 08/49] =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EC=9D=98=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20ArgumentResolver=EC=99=80=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EC=9E=90=EB=A7=8C=20=ED=95=B4=EB=8B=B9=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EC=97=90=20=EC=A0=91=EA=B7=BC=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=ED=95=98=EB=8A=94=20Interceptor?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authentication/AuthenticationConfig.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/roomescape/authentication/AuthenticationConfig.java diff --git a/src/main/java/roomescape/authentication/AuthenticationConfig.java b/src/main/java/roomescape/authentication/AuthenticationConfig.java new file mode 100644 index 00000000..afd0bc58 --- /dev/null +++ b/src/main/java/roomescape/authentication/AuthenticationConfig.java @@ -0,0 +1,28 @@ +package roomescape.authentication; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +@RequiredArgsConstructor +public class AuthenticationConfig implements WebMvcConfigurer { + + private final LoginMemberArgumentResolver loginMemberArgumentResolver; + private final AuthAdminRoleInterceptor authAdminRoleInterceptor; + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(loginMemberArgumentResolver); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(authAdminRoleInterceptor) + .addPathPatterns("/admin/**"); + } +} From 91bf7bf5228fa966b7841f814c622ae4e675b786 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:52:28 +0900 Subject: [PATCH 09/49] =?UTF-8?q?=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/ExceptionController.java | 14 --------- .../exception/GeneralExceptionHandler.java | 31 +++++++++++++++++++ .../exception/JwtProviderException.java | 7 +++++ .../exception/JwtValidationException.java | 7 +++++ .../exception/MemberNotFoundException.java | 7 +++++ .../exception/PageExceptionHandler.java | 16 ++++++++++ 6 files changed, 68 insertions(+), 14 deletions(-) delete mode 100644 src/main/java/roomescape/ExceptionController.java create mode 100644 src/main/java/roomescape/exception/GeneralExceptionHandler.java create mode 100644 src/main/java/roomescape/exception/JwtProviderException.java create mode 100644 src/main/java/roomescape/exception/JwtValidationException.java create mode 100644 src/main/java/roomescape/exception/MemberNotFoundException.java create mode 100644 src/main/java/roomescape/exception/PageExceptionHandler.java diff --git a/src/main/java/roomescape/ExceptionController.java b/src/main/java/roomescape/ExceptionController.java deleted file mode 100644 index 4e2450f9..00000000 --- a/src/main/java/roomescape/ExceptionController.java +++ /dev/null @@ -1,14 +0,0 @@ -package roomescape; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -@ControllerAdvice -public class ExceptionController { - @ExceptionHandler(Exception.class) - public ResponseEntity handleRuntimeException(Exception e) { - e.printStackTrace(); - return ResponseEntity.badRequest().build(); - } -} diff --git a/src/main/java/roomescape/exception/GeneralExceptionHandler.java b/src/main/java/roomescape/exception/GeneralExceptionHandler.java new file mode 100644 index 00000000..d14e8f5f --- /dev/null +++ b/src/main/java/roomescape/exception/GeneralExceptionHandler.java @@ -0,0 +1,31 @@ +package roomescape.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GeneralExceptionHandler { + + @ExceptionHandler(MemberNotFoundException.class) + public ResponseEntity handleMemberNotFound(MemberNotFoundException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); + } + + @ExceptionHandler(JwtValidationException.class) + public ResponseEntity handleJwtValidationException(JwtValidationException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); + } + + @ExceptionHandler(JwtProviderException.class) + public ResponseEntity handleJwtProviderException(JwtProviderException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGeneralException(Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); + } +} diff --git a/src/main/java/roomescape/exception/JwtProviderException.java b/src/main/java/roomescape/exception/JwtProviderException.java new file mode 100644 index 00000000..1ce101b0 --- /dev/null +++ b/src/main/java/roomescape/exception/JwtProviderException.java @@ -0,0 +1,7 @@ +package roomescape.exception; + +public class JwtProviderException extends RuntimeException { + public JwtProviderException(String message) { + super(message); + } +} diff --git a/src/main/java/roomescape/exception/JwtValidationException.java b/src/main/java/roomescape/exception/JwtValidationException.java new file mode 100644 index 00000000..1f5dae54 --- /dev/null +++ b/src/main/java/roomescape/exception/JwtValidationException.java @@ -0,0 +1,7 @@ +package roomescape.exception; + +public class JwtValidationException extends RuntimeException { + public JwtValidationException(String message) { + super(message); + } +} diff --git a/src/main/java/roomescape/exception/MemberNotFoundException.java b/src/main/java/roomescape/exception/MemberNotFoundException.java new file mode 100644 index 00000000..934da819 --- /dev/null +++ b/src/main/java/roomescape/exception/MemberNotFoundException.java @@ -0,0 +1,7 @@ +package roomescape.exception; + +public class MemberNotFoundException extends RuntimeException { + public MemberNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/roomescape/exception/PageExceptionHandler.java b/src/main/java/roomescape/exception/PageExceptionHandler.java new file mode 100644 index 00000000..f9964917 --- /dev/null +++ b/src/main/java/roomescape/exception/PageExceptionHandler.java @@ -0,0 +1,16 @@ +package roomescape.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import roomescape.PageController; + +@Slf4j +@ControllerAdvice(assignableTypes = PageController.class) +public class PageExceptionHandler { + @ExceptionHandler(Exception.class) + public String handleException(Exception e) { + log.error("error: " + e.getMessage()); + return "error/500"; //view 렌더링 페이지는 만들지 않음 + } +} From 16e217bb67967ac1199ad9fcf7dfa3b981e3ef89 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Thu, 26 Dec 2024 14:52:58 +0900 Subject: [PATCH 10/49] =?UTF-8?q?=201=20~=203=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/MissionStepTest.java | 81 +++++++++++++++++-- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 6add784b..d9f7e1f0 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; +import roomescape.reservation.ReservationResponse; import java.util.HashMap; import java.util.Map; @@ -17,11 +18,11 @@ @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class MissionStepTest { - @Test - void 일단계() { + private String createToken(String email, String password) { Map params = new HashMap<>(); - params.put("email", "admin@email.com"); - params.put("password", "password"); + + params.put("email", email); + params.put("password", password); ExtractableResponse response = RestAssured.given().log().all() .contentType(ContentType.JSON) @@ -31,8 +32,76 @@ public class MissionStepTest { .statusCode(200) .extract(); - String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; + return response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; + } + + @Test + void 일단계() { + String token = createToken("admin@email.com", "password"); assertThat(token).isNotBlank(); + + ExtractableResponse checkResponse = RestAssured.given().log().all() + .contentType(ContentType.JSON) + .cookie("token", token) + .when().get("/login/check") + .then().log().all() + .statusCode(200) + .extract(); + + assertThat(checkResponse.body().jsonPath().getString("name")).isEqualTo("어드민"); + } + + @Test + void 이단계() { + String token = createToken("admin@email.com", "password"); // 일단계에서 토큰을 추출하는 로직을 메서드로 따로 만들어서 활용하세요. + + Map params = new HashMap<>(); + params.put("date", "2024-03-01"); + params.put("time", "1"); + params.put("theme", "1"); + + ExtractableResponse response = RestAssured.given().log().all() + .body(params) + .cookie("token", token) + .contentType(ContentType.JSON) + .post("/reservations") + .then().log().all() + .extract(); + + assertThat(response.statusCode()).isEqualTo(201); + assertThat(response.as(ReservationResponse.class).getName()).isEqualTo("어드민"); + + params.put("name", "브라운"); + + ExtractableResponse adminResponse = RestAssured.given().log().all() + .body(params) + .cookie("token", token) + .contentType(ContentType.JSON) + .post("/reservations") + .then().log().all() + .extract(); + + assertThat(adminResponse.statusCode()).isEqualTo(201); + assertThat(adminResponse.as(ReservationResponse.class).getName()).isEqualTo("브라운"); + } + + @Test + void 삼단계() { + String brownToken = createToken("brown@email.com", "password"); + + RestAssured.given().log().all() + .cookie("token", brownToken) + .get("/admin") + .then().log().all() + .statusCode(401); + + String adminToken = createToken("admin@email.com", "password"); + + RestAssured.given().log().all() + .cookie("token", adminToken) + .get("/admin") + .then().log().all() + .statusCode(200); } -} \ No newline at end of file +} From 4a9ff8c98eea50b5de1f039136202513e8fbc1ad Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 01:33:20 +0900 Subject: [PATCH 11/49] =?UTF-8?q?=20DTO=20record=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/login/LoginRequest.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/roomescape/login/LoginRequest.java b/src/main/java/roomescape/login/LoginRequest.java index 525f6286..3062db84 100644 --- a/src/main/java/roomescape/login/LoginRequest.java +++ b/src/main/java/roomescape/login/LoginRequest.java @@ -1,15 +1,5 @@ package roomescape.login; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -@Data -public class LoginRequest { - - @NotEmpty - private String email; - - @NotEmpty - private String password; - +public record LoginRequest(String email, + String password) { } From a5e8d66b61101573896ad497175cc0ce24cc7c39 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 01:56:07 +0900 Subject: [PATCH 12/49] =?UTF-8?q?=20DTO=20record=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/login/LoginService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/roomescape/login/LoginService.java b/src/main/java/roomescape/login/LoginService.java index 680130fa..35804d7d 100644 --- a/src/main/java/roomescape/login/LoginService.java +++ b/src/main/java/roomescape/login/LoginService.java @@ -20,7 +20,7 @@ public class LoginService { public JwtResponse login(LoginRequest loginRequest) { try { - Member member = memberDao.findByEmailAndPassword(loginRequest.getEmail(), loginRequest.getPassword()); + Member member = memberDao.findByEmailAndPassword(loginRequest.email(), loginRequest.password()); return jwtProvider.createAccessToken(member); } catch (EmptyResultDataAccessException e) { throw new MemberNotFoundException("이메일 혹은 비밀번호가 맞지 않습니다."); From e027b31d3e86d0fea0c836b619d6dbb87f552364 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 02:13:44 +0900 Subject: [PATCH 13/49] =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20=EB=B0=94?= =?UTF-8?q?=EB=94=94=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/login/LoginController.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/roomescape/login/LoginController.java b/src/main/java/roomescape/login/LoginController.java index 7d4ae7f2..ace3b293 100644 --- a/src/main/java/roomescape/login/LoginController.java +++ b/src/main/java/roomescape/login/LoginController.java @@ -5,7 +5,6 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -21,34 +20,30 @@ public class LoginController { private final LoginService loginService; @PostMapping("/login") - public ResponseEntity login(@Valid @RequestBody LoginRequest loginRequest, HttpServletResponse response) { + public void login(@Valid @RequestBody LoginRequest loginRequest, HttpServletResponse response) { JwtResponse jwtResponse = loginService.login(loginRequest); Cookie cookie = new Cookie("token", jwtResponse.accessToken()); cookie.setHttpOnly(true); cookie.setPath("/"); response.addCookie(cookie); - - return ResponseEntity.ok().build(); } @GetMapping("/login/check") - public ResponseEntity checkLogin(HttpServletRequest request) { + public LoginCheckResponse checkLogin(HttpServletRequest request) { JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); MemberAuthInfo memberAuthInfo = JwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); LoginCheckResponse loginCheckResponse = loginService.checkLogin(memberAuthInfo); - return ResponseEntity.ok(loginCheckResponse); + return loginCheckResponse; } @PostMapping("/logout") - public ResponseEntity logout(HttpServletResponse response) { + public void logout(HttpServletResponse response) { Cookie cookie = new Cookie("token", ""); cookie.setHttpOnly(true); cookie.setPath("/"); cookie.setMaxAge(0); response.addCookie(cookie); - - return ResponseEntity.ok().build(); } } From c7a18750c307232f97d453e4511e1c311246043b Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 10:33:23 +0900 Subject: [PATCH 14/49] =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/authentication/AuthAdminRoleInterceptor.java | 6 +++--- .../authentication/LoginMemberArgumentResolver.java | 6 +++--- .../roomescape/{ => authentication}/jwt/JwtProvider.java | 2 +- .../roomescape/{ => authentication}/jwt/JwtResponse.java | 2 +- .../java/roomescape/{ => authentication}/jwt/JwtUtils.java | 2 +- src/main/java/roomescape/login/LoginController.java | 4 ++-- src/main/java/roomescape/login/LoginService.java | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) rename src/main/java/roomescape/{ => authentication}/jwt/JwtProvider.java (96%) rename src/main/java/roomescape/{ => authentication}/jwt/JwtResponse.java (61%) rename src/main/java/roomescape/{ => authentication}/jwt/JwtUtils.java (98%) diff --git a/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java b/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java index 61ea6d5c..c0bea7e0 100644 --- a/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java +++ b/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java @@ -5,9 +5,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; -import roomescape.jwt.JwtProvider; -import roomescape.jwt.JwtResponse; -import roomescape.jwt.JwtUtils; +import roomescape.authentication.jwt.JwtProvider; +import roomescape.authentication.jwt.JwtResponse; +import roomescape.authentication.jwt.JwtUtils; @Component @RequiredArgsConstructor diff --git a/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java b/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java index d4f7b301..fa88d75d 100644 --- a/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java +++ b/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java @@ -9,9 +9,9 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import roomescape.jwt.JwtProvider; -import roomescape.jwt.JwtResponse; -import roomescape.jwt.JwtUtils; +import roomescape.authentication.jwt.JwtProvider; +import roomescape.authentication.jwt.JwtResponse; +import roomescape.authentication.jwt.JwtUtils; @Component @RequiredArgsConstructor diff --git a/src/main/java/roomescape/jwt/JwtProvider.java b/src/main/java/roomescape/authentication/jwt/JwtProvider.java similarity index 96% rename from src/main/java/roomescape/jwt/JwtProvider.java rename to src/main/java/roomescape/authentication/jwt/JwtProvider.java index 8a4c5a56..d3a84844 100644 --- a/src/main/java/roomescape/jwt/JwtProvider.java +++ b/src/main/java/roomescape/authentication/jwt/JwtProvider.java @@ -1,4 +1,4 @@ -package roomescape.jwt; +package roomescape.authentication.jwt; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/roomescape/jwt/JwtResponse.java b/src/main/java/roomescape/authentication/jwt/JwtResponse.java similarity index 61% rename from src/main/java/roomescape/jwt/JwtResponse.java rename to src/main/java/roomescape/authentication/jwt/JwtResponse.java index 8d9ae9d9..4fe6be93 100644 --- a/src/main/java/roomescape/jwt/JwtResponse.java +++ b/src/main/java/roomescape/authentication/jwt/JwtResponse.java @@ -1,4 +1,4 @@ -package roomescape.jwt; +package roomescape.authentication.jwt; public record JwtResponse( String accessToken diff --git a/src/main/java/roomescape/jwt/JwtUtils.java b/src/main/java/roomescape/authentication/jwt/JwtUtils.java similarity index 98% rename from src/main/java/roomescape/jwt/JwtUtils.java rename to src/main/java/roomescape/authentication/jwt/JwtUtils.java index 1c0c5a18..f68c96aa 100644 --- a/src/main/java/roomescape/jwt/JwtUtils.java +++ b/src/main/java/roomescape/authentication/jwt/JwtUtils.java @@ -1,4 +1,4 @@ -package roomescape.jwt; +package roomescape.authentication.jwt; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtException; diff --git a/src/main/java/roomescape/login/LoginController.java b/src/main/java/roomescape/login/LoginController.java index ace3b293..4024d629 100644 --- a/src/main/java/roomescape/login/LoginController.java +++ b/src/main/java/roomescape/login/LoginController.java @@ -10,8 +10,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import roomescape.authentication.MemberAuthInfo; -import roomescape.jwt.JwtResponse; -import roomescape.jwt.JwtUtils; +import roomescape.authentication.jwt.JwtResponse; +import roomescape.authentication.jwt.JwtUtils; @RestController @RequiredArgsConstructor diff --git a/src/main/java/roomescape/login/LoginService.java b/src/main/java/roomescape/login/LoginService.java index 35804d7d..7ae33b16 100644 --- a/src/main/java/roomescape/login/LoginService.java +++ b/src/main/java/roomescape/login/LoginService.java @@ -4,8 +4,8 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.stereotype.Service; import roomescape.authentication.MemberAuthInfo; -import roomescape.jwt.JwtProvider; -import roomescape.jwt.JwtResponse; +import roomescape.authentication.jwt.JwtProvider; +import roomescape.authentication.jwt.JwtResponse; import roomescape.member.Member; import roomescape.member.MemberDao; import roomescape.exception.MemberNotFoundException; From 23585684eb4391b9cc0d0639301a61f23b2e75f3 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 11:57:19 +0900 Subject: [PATCH 15/49] =?UTF-8?q?=20JwtUtils=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(=EB=A9=A4=EB=B2=84=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=20=EB=B0=8F=20=EB=A9=94=EC=84=9C=EB=93=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthAdminRoleInterceptor.java | 7 ++--- .../LoginMemberArgumentResolver.java | 7 ++--- .../authentication/jwt/JwtProvider.java | 31 ------------------- .../authentication/jwt/JwtUtils.java | 25 +++++++++++---- .../roomescape/login/LoginController.java | 5 +-- .../java/roomescape/login/LoginService.java | 6 ++-- 6 files changed, 31 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/roomescape/authentication/jwt/JwtProvider.java diff --git a/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java b/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java index c0bea7e0..cefb6af8 100644 --- a/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java +++ b/src/main/java/roomescape/authentication/AuthAdminRoleInterceptor.java @@ -5,7 +5,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; -import roomescape.authentication.jwt.JwtProvider; import roomescape.authentication.jwt.JwtResponse; import roomescape.authentication.jwt.JwtUtils; @@ -13,11 +12,11 @@ @RequiredArgsConstructor public class AuthAdminRoleInterceptor implements HandlerInterceptor { - private final JwtProvider jwtProvider; + private final JwtUtils jwtUtils; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); + JwtResponse jwtResponse = jwtUtils.extractTokenFromCookie(request.getCookies()); if (jwtResponse.accessToken() == null || !isAdmin(jwtResponse.accessToken())) { response.setStatus(401); return false; @@ -27,7 +26,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } private boolean isAdmin(String token) { - MemberAuthInfo memberAuthInfo = JwtUtils.extractMemberAuthInfoFromToken(token); + MemberAuthInfo memberAuthInfo = jwtUtils.extractMemberAuthInfoFromToken(token); return "ADMIN".equals(memberAuthInfo.role()); } } diff --git a/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java b/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java index fa88d75d..807170ac 100644 --- a/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java +++ b/src/main/java/roomescape/authentication/LoginMemberArgumentResolver.java @@ -9,7 +9,6 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import roomescape.authentication.jwt.JwtProvider; import roomescape.authentication.jwt.JwtResponse; import roomescape.authentication.jwt.JwtUtils; @@ -17,7 +16,7 @@ @RequiredArgsConstructor public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { - private final JwtProvider jwtProvider; + private final JwtUtils jwtUtils; @Override public boolean supportsParameter(MethodParameter parameter) { @@ -28,11 +27,11 @@ public boolean supportsParameter(MethodParameter parameter) { public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = ((ServletWebRequest) webRequest).getRequest(); - JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); + JwtResponse jwtResponse = jwtUtils.extractTokenFromCookie(request.getCookies()); if (jwtResponse.accessToken() == null) { return null; } - return JwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); + return jwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); } } diff --git a/src/main/java/roomescape/authentication/jwt/JwtProvider.java b/src/main/java/roomescape/authentication/jwt/JwtProvider.java deleted file mode 100644 index d3a84844..00000000 --- a/src/main/java/roomescape/authentication/jwt/JwtProvider.java +++ /dev/null @@ -1,31 +0,0 @@ -package roomescape.authentication.jwt; - -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.security.Keys; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import roomescape.exception.JwtProviderException; -import roomescape.member.Member; - -@Component -public class JwtProvider { - - @Value("${roomescape.auth.jwt.secret}") - private String secretKey; - - public JwtResponse createAccessToken(Member member) { - try { - String accessToken = Jwts.builder() - .setSubject(member.getId().toString()) - .claim("name", member.getName()) - .claim("role", member.getRole()) - .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) - .compact(); - - return new JwtResponse(accessToken); - } catch (JwtException e) { - throw new JwtProviderException("JWT 생성에 실패하였습니다."); - } - } -} diff --git a/src/main/java/roomescape/authentication/jwt/JwtUtils.java b/src/main/java/roomescape/authentication/jwt/JwtUtils.java index f68c96aa..206480a6 100644 --- a/src/main/java/roomescape/authentication/jwt/JwtUtils.java +++ b/src/main/java/roomescape/authentication/jwt/JwtUtils.java @@ -9,7 +9,9 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import roomescape.authentication.MemberAuthInfo; +import roomescape.exception.JwtProviderException; import roomescape.exception.JwtValidationException; +import roomescape.member.Member; import java.util.Arrays; @@ -17,14 +19,25 @@ @RequiredArgsConstructor public class JwtUtils { - private static String secretKey; - @Value("${roomescape.auth.jwt.secret}") - public void setSecretKey(String secretKey) { - JwtUtils.secretKey = secretKey; + private String secretKey; + + public JwtResponse createAccessToken(Member member) { + try { + String accessToken = Jwts.builder() + .setSubject(member.getId().toString()) + .claim("name", member.getName()) + .claim("role", member.getRole()) + .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) + .compact(); + + return new JwtResponse(accessToken); + } catch (JwtException e) { + throw new JwtProviderException("JWT 생성에 실패하였습니다."); + } } - public static MemberAuthInfo extractMemberAuthInfoFromToken(String token) { + public MemberAuthInfo extractMemberAuthInfoFromToken(String token) { if (token == null || token.isEmpty()) { throw new JwtValidationException("토큰이 존재하지 않습니다."); } @@ -45,7 +58,7 @@ public static MemberAuthInfo extractMemberAuthInfoFromToken(String token) { } } - public static JwtResponse extractTokenFromCookie(Cookie[] cookies) { + public JwtResponse extractTokenFromCookie(Cookie[] cookies) { if (cookies == null) { throw new JwtValidationException("쿠키가 존재하지 않습니다."); } diff --git a/src/main/java/roomescape/login/LoginController.java b/src/main/java/roomescape/login/LoginController.java index 4024d629..f13dd838 100644 --- a/src/main/java/roomescape/login/LoginController.java +++ b/src/main/java/roomescape/login/LoginController.java @@ -18,6 +18,7 @@ public class LoginController { private final LoginService loginService; + private final JwtUtils jwtUtils; @PostMapping("/login") public void login(@Valid @RequestBody LoginRequest loginRequest, HttpServletResponse response) { @@ -31,8 +32,8 @@ public void login(@Valid @RequestBody LoginRequest loginRequest, HttpServletResp @GetMapping("/login/check") public LoginCheckResponse checkLogin(HttpServletRequest request) { - JwtResponse jwtResponse = JwtUtils.extractTokenFromCookie(request.getCookies()); - MemberAuthInfo memberAuthInfo = JwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); + JwtResponse jwtResponse = jwtUtils.extractTokenFromCookie(request.getCookies()); + MemberAuthInfo memberAuthInfo = jwtUtils.extractMemberAuthInfoFromToken(jwtResponse.accessToken()); LoginCheckResponse loginCheckResponse = loginService.checkLogin(memberAuthInfo); return loginCheckResponse; diff --git a/src/main/java/roomescape/login/LoginService.java b/src/main/java/roomescape/login/LoginService.java index 7ae33b16..86b1467b 100644 --- a/src/main/java/roomescape/login/LoginService.java +++ b/src/main/java/roomescape/login/LoginService.java @@ -4,8 +4,8 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.stereotype.Service; import roomescape.authentication.MemberAuthInfo; -import roomescape.authentication.jwt.JwtProvider; import roomescape.authentication.jwt.JwtResponse; +import roomescape.authentication.jwt.JwtUtils; import roomescape.member.Member; import roomescape.member.MemberDao; import roomescape.exception.MemberNotFoundException; @@ -15,13 +15,13 @@ public class LoginService { private final MemberDao memberDao; - private final JwtProvider jwtProvider; + private final JwtUtils jwtUtils; public JwtResponse login(LoginRequest loginRequest) { try { Member member = memberDao.findByEmailAndPassword(loginRequest.email(), loginRequest.password()); - return jwtProvider.createAccessToken(member); + return jwtUtils.createAccessToken(member); } catch (EmptyResultDataAccessException e) { throw new MemberNotFoundException("이메일 혹은 비밀번호가 맞지 않습니다."); } From b44dab1ff73f3887e6a173a004238caeb01dad6c Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 16:51:13 +0900 Subject: [PATCH 16/49] =?UTF-8?q?=20=EC=97=90=EB=9F=AC=20=EC=B6=94?= =?UTF-8?q?=EC=A0=81=20=EC=9A=A9=EC=9D=B4=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=8F=AC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/authentication/jwt/JwtUtils.java | 6 +++--- .../java/roomescape/exception/JwtProviderException.java | 4 ++-- .../java/roomescape/exception/JwtValidationException.java | 4 ++++ .../java/roomescape/exception/MemberNotFoundException.java | 4 ++-- src/main/java/roomescape/login/LoginService.java | 4 ++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/roomescape/authentication/jwt/JwtUtils.java b/src/main/java/roomescape/authentication/jwt/JwtUtils.java index 206480a6..3a3e3f7e 100644 --- a/src/main/java/roomescape/authentication/jwt/JwtUtils.java +++ b/src/main/java/roomescape/authentication/jwt/JwtUtils.java @@ -33,7 +33,7 @@ public JwtResponse createAccessToken(Member member) { return new JwtResponse(accessToken); } catch (JwtException e) { - throw new JwtProviderException("JWT 생성에 실패하였습니다."); + throw new JwtProviderException("JWT 생성에 실패하였습니다.", e); } } @@ -54,7 +54,7 @@ public MemberAuthInfo extractMemberAuthInfoFromToken(String token) { return new MemberAuthInfo(name, role); } catch (JwtException e) { - throw new JwtValidationException("유효하지 않은 JWT 토큰입니다."); + throw new JwtValidationException("유효하지 않은 JWT 토큰입니다.", e); } } @@ -72,7 +72,7 @@ public JwtResponse extractTokenFromCookie(Cookie[] cookies) { return new JwtResponse(accessToken); } catch (Exception e) { - throw new JwtValidationException("쿠키에서 토큰 추출 중 오류가 발생했습니다."); + throw new JwtValidationException("쿠키에서 토큰 추출 중 오류가 발생했습니다.", e); } } } diff --git a/src/main/java/roomescape/exception/JwtProviderException.java b/src/main/java/roomescape/exception/JwtProviderException.java index 1ce101b0..30310600 100644 --- a/src/main/java/roomescape/exception/JwtProviderException.java +++ b/src/main/java/roomescape/exception/JwtProviderException.java @@ -1,7 +1,7 @@ package roomescape.exception; public class JwtProviderException extends RuntimeException { - public JwtProviderException(String message) { - super(message); + public JwtProviderException(String message, Throwable cause) { + super(message, cause); } } diff --git a/src/main/java/roomescape/exception/JwtValidationException.java b/src/main/java/roomescape/exception/JwtValidationException.java index 1f5dae54..2b897d92 100644 --- a/src/main/java/roomescape/exception/JwtValidationException.java +++ b/src/main/java/roomescape/exception/JwtValidationException.java @@ -4,4 +4,8 @@ public class JwtValidationException extends RuntimeException { public JwtValidationException(String message) { super(message); } + + public JwtValidationException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/main/java/roomescape/exception/MemberNotFoundException.java b/src/main/java/roomescape/exception/MemberNotFoundException.java index 934da819..b8a7db7a 100644 --- a/src/main/java/roomescape/exception/MemberNotFoundException.java +++ b/src/main/java/roomescape/exception/MemberNotFoundException.java @@ -1,7 +1,7 @@ package roomescape.exception; public class MemberNotFoundException extends RuntimeException { - public MemberNotFoundException(String message) { - super(message); + public MemberNotFoundException(String message, Throwable cause) { + super(message, cause); } } diff --git a/src/main/java/roomescape/login/LoginService.java b/src/main/java/roomescape/login/LoginService.java index 86b1467b..d95b083f 100644 --- a/src/main/java/roomescape/login/LoginService.java +++ b/src/main/java/roomescape/login/LoginService.java @@ -23,7 +23,7 @@ public JwtResponse login(LoginRequest loginRequest) { Member member = memberDao.findByEmailAndPassword(loginRequest.email(), loginRequest.password()); return jwtUtils.createAccessToken(member); } catch (EmptyResultDataAccessException e) { - throw new MemberNotFoundException("이메일 혹은 비밀번호가 맞지 않습니다."); + throw new MemberNotFoundException("이메일 혹은 비밀번호가 맞지 않습니다.", e); } } @@ -33,7 +33,7 @@ public LoginCheckResponse checkLogin(MemberAuthInfo memberAuthInfo) { Member member = memberDao.findByName(memberAuthInfo.name()); return new LoginCheckResponse(member.getName()); } catch (EmptyResultDataAccessException e) { - throw new MemberNotFoundException("로그인이 되지 않은 상태입니다."); + throw new MemberNotFoundException("로그인이 되지 않은 상태입니다.", e); } } } From 330b40ceebd03789c2a82b1c237a4df95437aa11 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 22:45:18 +0900 Subject: [PATCH 17/49] =?UTF-8?q?=20gradle=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20jdbc=20->=20jpa=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d5f9249b..fcf72cb6 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' From 7a7ed5549412cc8a7ab2767b55718e0758bf5423 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 22:48:40 +0900 Subject: [PATCH 18/49] =?UTF-8?q?=20JPA=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5cfe2f4f..59b61121 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,10 +3,10 @@ spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.datasource.url=jdbc:h2:mem:database -#spring.jpa.show-sql=true -#spring.jpa.properties.hibernate.format_sql=true -#spring.jpa.ddl-auto=create-drop -#spring.jpa.defer-datasource-initialization=true +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.ddl-auto=create-drop +spring.jpa.defer-datasource-initialization=true roomescape.auth.jwt.secret=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5Eaadfasdfsadfsafdsa2df= server.connection-timeout=60s From c5f4f9735b68a204638f84db72d4a135685f621b Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 22:50:03 +0900 Subject: [PATCH 19/49] =?UTF-8?q?=20=EC=B4=88=EA=B8=B0=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4=EC=8A=A4=20seed=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/data.sql | 21 ++++++++++++ src/main/resources/schema.sql | 60 ----------------------------------- 2 files changed, 21 insertions(+), 60 deletions(-) create mode 100644 src/main/resources/data.sql delete mode 100644 src/main/resources/schema.sql diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 00000000..45d0d21c --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,21 @@ +INSERT INTO member (name, email, password, role) +VALUES ('어드민', 'admin@email.com', 'password', 'ADMIN'), + ('브라운', 'brown@email.com', 'password', 'USER'); + +INSERT INTO theme (name, description) +VALUES ('테마1', '테마1입니다.'), + ('테마2', '테마2입니다.'), + ('테마3', '테마3입니다.'); + +INSERT INTO time (time_value) +VALUES ('10:00'), + ('12:00'), + ('14:00'), + ('16:00'), + ('18:00'), + ('20:00'); + +INSERT INTO reservation (name, date, time_id, theme_id) +VALUES ('어드민', '2024-03-01', 1, 1), + ('어드민', '2024-03-01', 2, 2), + ('어드민', '2024-03-01', 3, 3); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql deleted file mode 100644 index 75c947a5..00000000 --- a/src/main/resources/schema.sql +++ /dev/null @@ -1,60 +0,0 @@ -CREATE TABLE time -( - id BIGINT NOT NULL AUTO_INCREMENT, - time_value VARCHAR(20) NOT NULL, - deleted BOOLEAN NOT NULL DEFAULT FALSE, - PRIMARY KEY (id) -); - -CREATE TABLE theme -( - id BIGINT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - description VARCHAR(255) NOT NULL, - deleted BOOLEAN NOT NULL DEFAULT FALSE, - PRIMARY KEY (id) -); - -CREATE TABLE member -( - id BIGINT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - email VARCHAR(255) UNIQUE NOT NULL, - password VARCHAR(255) NOT NULL, - role VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE reservation -( - id BIGINT NOT NULL AUTO_INCREMENT, - date VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - time_id BIGINT, - theme_id BIGINT, - PRIMARY KEY (id), - FOREIGN KEY (time_id) REFERENCES time (id), - FOREIGN KEY (theme_id) REFERENCES theme (id) -); - -INSERT INTO member (name, email, password, role) -VALUES ('어드민', 'admin@email.com', 'password', 'ADMIN'), - ('브라운', 'brown@email.com', 'password', 'USER'); - -INSERT INTO theme (name, description) -VALUES ('테마1', '테마1입니다.'), - ('테마2', '테마2입니다.'), - ('테마3', '테마3입니다.'); - -INSERT INTO time (time_value) -VALUES ('10:00'), - ('12:00'), - ('14:00'), - ('16:00'), - ('18:00'), - ('20:00'); - -INSERT INTO reservation (name, date, time_id, theme_id) -VALUES ('어드민', '2024-03-01', 1, 1), - ('어드민', '2024-03-01', 2, 2), - ('어드민', '2024-03-01', 3, 3); \ No newline at end of file From 580c6ab131da0b02b81506cf68af118804d6e875 Mon Sep 17 00:00:00 2001 From: goldm0ng Date: Wed, 8 Jan 2025 23:09:46 +0900 Subject: [PATCH 20/49] =?UTF-8?q?=20Time=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?=EB=B0=8F=20JPA=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/time/Time.java | 8 +++- src/main/java/roomescape/time/TimeDao.java | 41 ------------------- .../java/roomescape/time/TimeRepository.java | 6 +++ .../java/roomescape/time/TimeService.java | 22 +++++----- 4 files changed, 23 insertions(+), 54 deletions(-) delete mode 100644 src/main/java/roomescape/time/TimeDao.java create mode 100644 src/main/java/roomescape/time/TimeRepository.java diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java index 008ed93c..f54691bb 100644 --- a/src/main/java/roomescape/time/Time.java +++ b/src/main/java/roomescape/time/Time.java @@ -1,7 +1,14 @@ package roomescape.time; +import jakarta.persistence.*; + +@Entity public class Time { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + + @Column(name = "time_value") private String value; public Time(Long id, String value) { @@ -14,7 +21,6 @@ public Time(String value) { } public Time() { - } public Long getId() { diff --git a/src/main/java/roomescape/time/TimeDao.java b/src/main/java/roomescape/time/TimeDao.java deleted file mode 100644 index f39a9a32..00000000 --- a/src/main/java/roomescape/time/TimeDao.java +++ /dev/null @@ -1,41 +0,0 @@ -package roomescape.time; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import java.sql.PreparedStatement; -import java.util.List; - -@Repository -public class TimeDao { - private final JdbcTemplate jdbcTemplate; - - public TimeDao(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public List