From e50beb35e39ae23eaaa2c9c78ea1d94b7eb893df Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Wed, 5 Jun 2024 21:00:38 +0900 Subject: [PATCH 01/22] =?UTF-8?q?=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/main/java/roomescape/member/MemberController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 881ae5e0..576f7e8d 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -24,6 +24,8 @@ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { MemberResponse member = memberService.createMember(memberRequest); return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member); } + @PostMapping("/login") + @PostMapping("/logout") public ResponseEntity logout(HttpServletResponse response) { From d4d28de42edfcfc945380b2162d8a1ea8cb1571d Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Mon, 24 Jun 2024 21:28:38 +0900 Subject: [PATCH 02/22] step 1 --- .../roomescape/member/MemberController.java | 13 ++++++++++++ .../java/roomescape/member/MemberService.java | 12 +++++++++++ .../roomescape/provider/TokenProvider.java | 21 +++++++++++++++++++ src/main/resources/application.properties | 3 ++- 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/main/java/roomescape/provider/TokenProvider.java diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 576f7e8d..d07148d1 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -25,6 +25,19 @@ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member); } @PostMapping("/login") + public ResponseEntity login(@RequestBody MemberRequest memberRequest, HttpServletResponse response) { + MemberResponse member = memberService.findMemberByEmailAndPassword(memberRequest.getEmail(), memberRequest.getPassword()); + if (member == null) { + return ResponseEntity.badRequest().build(); + } + String token = memberService.createToken(member); + Cookie cookie = new Cookie("token", token); + cookie.setHttpOnly(true); + cookie.setPath("/"); + response.addCookie(cookie); + return ResponseEntity.ok().build(); + + } @PostMapping("/logout") diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index ccaa8cba..a95701e6 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -1,6 +1,8 @@ package roomescape.member; +import kotlin.reflect.jvm.internal.impl.descriptors.Visibilities; import org.springframework.stereotype.Service; +import roomescape.provider.TokenProvider; @Service public class MemberService { @@ -14,4 +16,14 @@ public MemberResponse createMember(MemberRequest memberRequest) { Member member = memberDao.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER")); return new MemberResponse(member.getId(), member.getName(), member.getEmail()); } + + public MemberResponse findMemberByEmailAndPassword(String email, String password) { + Member member = memberDao.findByEmailAndPassword(email, password); + return new MemberResponse(member.getId(), member.getName(), member.getEmail()); + } + public String createToken(MemberResponse member) { + String accessToken = TokenProvider.createToken(member); + return accessToken; + } + } diff --git a/src/main/java/roomescape/provider/TokenProvider.java b/src/main/java/roomescape/provider/TokenProvider.java new file mode 100644 index 00000000..6244a08c --- /dev/null +++ b/src/main/java/roomescape/provider/TokenProvider.java @@ -0,0 +1,21 @@ +package roomescape.provider; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import org.springframework.stereotype.Component; +import roomescape.member.MemberResponse; + +@Component +public class TokenProvider { + public static String createToken(MemberResponse member) { + String secretKey = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E="; + String accessToken = Jwts.builder() + .setSubject(member.getId().toString()) + .claim("name", member.getName()) + .claim("email", member.getEmail()) + .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) + .compact(); + return accessToken; + + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a0f33bba..f3ffc6f2 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= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= + From 64b176218ba14a86d9b304f4d73bda47334872c9 Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Mon, 24 Jun 2024 22:06:05 +0900 Subject: [PATCH 03/22] =?UTF-8?q?step=201=20-=20check=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/member/MemberController.java | 12 +++++++++++ .../java/roomescape/member/MemberDao.java | 12 +++++++++++ .../java/roomescape/member/MemberService.java | 21 +++++++++++++++++++ .../reservation/ReservationService.java | 1 + 4 files changed, 46 insertions(+) diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index d07148d1..c66df682 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -1,5 +1,7 @@ package roomescape.member; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -38,6 +40,16 @@ public ResponseEntity login(@RequestBody MemberRequest memberRequest, HttpServle return ResponseEntity.ok().build(); } + @GetMapping("/login/check") + public ResponseEntity checkLogin(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + return ResponseEntity.badRequest().build(); + } + String token = memberService.extractTokenFromCookie(cookies); + MemberResponse member = memberService.findByToken(token); + return ResponseEntity.ok(member); + } @PostMapping("/logout") diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java index 81f77f4c..aa977a29 100644 --- a/src/main/java/roomescape/member/MemberDao.java +++ b/src/main/java/roomescape/member/MemberDao.java @@ -52,4 +52,16 @@ public Member findByName(String name) { name ); } + public Member findById(Long id) { + return jdbcTemplate.queryForObject( + "SELECT id, name, email, role FROM member WHERE id = ?", + (rs, rowNum) -> new Member( + rs.getLong("id"), + rs.getString("name"), + rs.getString("email"), + rs.getString("role") + ), + id + ); + } } diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index a95701e6..145e65bd 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -1,5 +1,8 @@ package roomescape.member; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.Cookie; import kotlin.reflect.jvm.internal.impl.descriptors.Visibilities; import org.springframework.stereotype.Service; import roomescape.provider.TokenProvider; @@ -25,5 +28,23 @@ public String createToken(MemberResponse member) { String accessToken = TokenProvider.createToken(member); return accessToken; } + String extractTokenFromCookie(Cookie[] cookies) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("token")) { + return cookie.getValue(); + } + } + return ""; + } + + public MemberResponse findByToken(String token) { + Long memberId = Long.valueOf(Jwts.parserBuilder() + .setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes())) + .build() + .parseClaimsJws(token) + .getBody().getSubject()); + Member member = memberDao.findById(memberId); + return new MemberResponse(member.getId(), member.getName(), member.getEmail()); + } } diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index bd331332..69e44405 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -27,4 +27,5 @@ public List findAll() { .map(it -> new ReservationResponse(it.getId(), it.getName(), it.getTheme().getName(), it.getDate(), it.getTime().getValue())) .toList(); } + } From b0bad9dcb2ff35c79f297e747f81eef8331884e9 Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Mon, 24 Jun 2024 22:08:14 +0900 Subject: [PATCH 04/22] =?UTF-8?q?step=202=20-=20test=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/MissionStepTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 6add784b..9cafc7bb 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; @@ -35,4 +36,38 @@ public class MissionStepTest { assertThat(token).isNotBlank(); } + + @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("브라운"); + } } \ No newline at end of file From b13970c3b76bc1e176eae80c004700ee7aa43bd1 Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Tue, 25 Jun 2024 00:08:40 +0900 Subject: [PATCH 05/22] step 2 --- build.gradle | 1 + .../auth/LoginMemberArgumentResolver.java | 34 +++++++++++++++++++ .../java/roomescape/auth/LoginResolver.java | 11 ++++++ src/main/java/roomescape/auth/WebConfig.java | 20 +++++++++++ .../java/roomescape/member/LoginMember.java | 20 +++++++++++ .../roomescape/member/MemberController.java | 7 ++-- .../java/roomescape/member/MemberService.java | 13 ++++--- .../roomescape/provider/TokenProvider.java | 4 ++- .../reservation/ReservationController.java | 9 +++-- .../reservation/ReservationRequest.java | 4 +++ .../reservation/ReservationResponse.java | 3 ++ src/main/resources/application.properties | 1 - src/test/java/roomescape/MissionStepTest.java | 16 +++++++++ 13 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 src/main/java/roomescape/auth/LoginMemberArgumentResolver.java create mode 100644 src/main/java/roomescape/auth/LoginResolver.java create mode 100644 src/main/java/roomescape/auth/WebConfig.java create mode 100644 src/main/java/roomescape/member/LoginMember.java diff --git a/build.gradle b/build.gradle index 8d52aebc..b820ecb4 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.11.2' implementation 'io.jsonwebtoken:jjwt-impl:0.11.2' implementation 'io.jsonwebtoken:jjwt-gson:0.11.2' + implementation 'org.projectlombok:lombok:1.18.22' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' diff --git a/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java b/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java new file mode 100644 index 00000000..ba491c87 --- /dev/null +++ b/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java @@ -0,0 +1,34 @@ +package roomescape.auth; + +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.member.LoginMember; +import roomescape.member.Member; +import roomescape.member.MemberService; + +@Component +public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { + private MemberService memberService; + + public LoginMemberArgumentResolver(MemberService memberService) { + this.memberService = memberService; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.getParameterType().equals(LoginMember.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + String token = memberService.extractTokenFromCookie(request.getCookies()); + Member member = memberService.findByToken(token); + return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getRole()); + } +} diff --git a/src/main/java/roomescape/auth/LoginResolver.java b/src/main/java/roomescape/auth/LoginResolver.java new file mode 100644 index 00000000..2c2fe329 --- /dev/null +++ b/src/main/java/roomescape/auth/LoginResolver.java @@ -0,0 +1,11 @@ +package roomescape.auth; + +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) +public @interface LoginResolver { +} diff --git a/src/main/java/roomescape/auth/WebConfig.java b/src/main/java/roomescape/auth/WebConfig.java new file mode 100644 index 00000000..c60605e3 --- /dev/null +++ b/src/main/java/roomescape/auth/WebConfig.java @@ -0,0 +1,20 @@ +package roomescape.auth; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Autowired + private LoginMemberArgumentResolver loginMemberArgumentResolver; + + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(loginMemberArgumentResolver); + } +} diff --git a/src/main/java/roomescape/member/LoginMember.java b/src/main/java/roomescape/member/LoginMember.java new file mode 100644 index 00000000..59a49458 --- /dev/null +++ b/src/main/java/roomescape/member/LoginMember.java @@ -0,0 +1,20 @@ +package roomescape.member; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LoginMember { + private Long id; + private String name; + private String email; + private String role; + + public LoginMember(Long id, String name, String email, String role) { + this.id = id; + this.name = name; + this.email = email; + this.role = role; + } +} diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index c66df682..59cd74ae 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -28,7 +28,7 @@ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { } @PostMapping("/login") public ResponseEntity login(@RequestBody MemberRequest memberRequest, HttpServletResponse response) { - MemberResponse member = memberService.findMemberByEmailAndPassword(memberRequest.getEmail(), memberRequest.getPassword()); + Member member = memberService.findMemberByEmailAndPassword(memberRequest.getEmail(), memberRequest.getPassword()); if (member == null) { return ResponseEntity.badRequest().build(); } @@ -47,8 +47,9 @@ public ResponseEntity checkLogin(HttpServletRequest request) { return ResponseEntity.badRequest().build(); } String token = memberService.extractTokenFromCookie(cookies); - MemberResponse member = memberService.findByToken(token); - return ResponseEntity.ok(member); + Member member = memberService.findByToken(token); + MemberResponse memberResponse = new MemberResponse(member.getId(), member.getName(), member.getEmail()); + return ResponseEntity.ok(memberResponse); } diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 145e65bd..7905a249 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -3,7 +3,6 @@ import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import jakarta.servlet.http.Cookie; -import kotlin.reflect.jvm.internal.impl.descriptors.Visibilities; import org.springframework.stereotype.Service; import roomescape.provider.TokenProvider; @@ -20,15 +19,15 @@ public MemberResponse createMember(MemberRequest memberRequest) { return new MemberResponse(member.getId(), member.getName(), member.getEmail()); } - public MemberResponse findMemberByEmailAndPassword(String email, String password) { + public Member findMemberByEmailAndPassword(String email, String password) { Member member = memberDao.findByEmailAndPassword(email, password); - return new MemberResponse(member.getId(), member.getName(), member.getEmail()); + return member; } - public String createToken(MemberResponse member) { + public String createToken(Member member) { String accessToken = TokenProvider.createToken(member); return accessToken; } - String extractTokenFromCookie(Cookie[] cookies) { + public String extractTokenFromCookie(Cookie[] cookies) { for (Cookie cookie : cookies) { if (cookie.getName().equals("token")) { return cookie.getValue(); @@ -38,13 +37,13 @@ String extractTokenFromCookie(Cookie[] cookies) { return ""; } - public MemberResponse findByToken(String token) { + public Member findByToken(String token) { Long memberId = Long.valueOf(Jwts.parserBuilder() .setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes())) .build() .parseClaimsJws(token) .getBody().getSubject()); Member member = memberDao.findById(memberId); - return new MemberResponse(member.getId(), member.getName(), member.getEmail()); + return member; } } diff --git a/src/main/java/roomescape/provider/TokenProvider.java b/src/main/java/roomescape/provider/TokenProvider.java index 6244a08c..52249745 100644 --- a/src/main/java/roomescape/provider/TokenProvider.java +++ b/src/main/java/roomescape/provider/TokenProvider.java @@ -3,16 +3,18 @@ import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.stereotype.Component; +import roomescape.member.Member; import roomescape.member.MemberResponse; @Component public class TokenProvider { - public static String createToken(MemberResponse member) { + public static String createToken(Member member) { String secretKey = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E="; String accessToken = Jwts.builder() .setSubject(member.getId().toString()) .claim("name", member.getName()) .claim("email", member.getEmail()) + .claim("role", member.getRole()) .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) .compact(); return accessToken; diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index b3bef399..5255f8e5 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.member.LoginMember; import java.net.URI; import java.util.List; @@ -26,9 +27,11 @@ public List list() { } @PostMapping("/reservations") - public ResponseEntity create(@RequestBody ReservationRequest reservationRequest) { - if (reservationRequest.getName() == null - || reservationRequest.getDate() == null + public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, LoginMember member) { + if(reservationRequest.getName() == null && member != null){ + reservationRequest.setName(member.getName()); + } + if ( reservationRequest.getDate() == null || reservationRequest.getTheme() == null || reservationRequest.getTime() == null) { return ResponseEntity.badRequest().build(); 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; + } } diff --git a/src/main/java/roomescape/reservation/ReservationResponse.java b/src/main/java/roomescape/reservation/ReservationResponse.java index 41360a36..9035143b 100644 --- a/src/main/java/roomescape/reservation/ReservationResponse.java +++ b/src/main/java/roomescape/reservation/ReservationResponse.java @@ -15,6 +15,9 @@ public ReservationResponse(Long id, String name, String theme, String date, Stri this.time = time; } + public ReservationResponse() { + } + public Long getId() { return id; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f3ffc6f2..83a5e5f8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,4 +9,3 @@ spring.datasource.url=jdbc:h2:mem:database #spring.jpa.defer-datasource-initialization=true #roomescape.auth.jwt.secret= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= - diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 9cafc7bb..b13a37a4 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -37,6 +37,22 @@ public class MissionStepTest { assertThat(token).isNotBlank(); } + private String createToken(String email, String password) { + Map params = new HashMap<>(); + params.put("email", email); + params.put("password", password); + + ExtractableResponse response = RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(params) + .when().post("/login") + .then().log().all() + .statusCode(200) + .extract(); + + return response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; + } + @Test void 이단계() { String token = createToken("admin@email.com", "password"); // 일단계에서 토큰을 추출하는 로직을 메서드로 따로 만들어서 활용하세요. From 8e375adfd7025078483b840dcfea8298e77b362f Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Tue, 25 Jun 2024 00:24:31 +0900 Subject: [PATCH 06/22] step 3 --- .../roomescape/auth/AdminInterceptor.java | 35 +++++++++++++++++++ src/main/java/roomescape/auth/WebConfig.java | 8 +++++ src/test/java/roomescape/MissionStepTest.java | 18 ++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/main/java/roomescape/auth/AdminInterceptor.java diff --git a/src/main/java/roomescape/auth/AdminInterceptor.java b/src/main/java/roomescape/auth/AdminInterceptor.java new file mode 100644 index 00000000..d2695971 --- /dev/null +++ b/src/main/java/roomescape/auth/AdminInterceptor.java @@ -0,0 +1,35 @@ +package roomescape.auth; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import roomescape.member.Member; +import roomescape.member.MemberResponse; +import roomescape.member.MemberService; + +@Component +public class AdminInterceptor implements HandlerInterceptor { + private final MemberService memberService; + + public AdminInterceptor(MemberService memberService) { + this.memberService = memberService; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + Cookie[] cookies = request.getCookies(); + String token = memberService.extractTokenFromCookie(cookies); + + Member member = memberService.findByToken(token); + + if (member == null || !member.getRole().equals("ADMIN")) { + response.setStatus(401); + return false; + } + + return true; + } +} diff --git a/src/main/java/roomescape/auth/WebConfig.java b/src/main/java/roomescape/auth/WebConfig.java index c60605e3..46722b4c 100644 --- a/src/main/java/roomescape/auth/WebConfig.java +++ b/src/main/java/roomescape/auth/WebConfig.java @@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; 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; @@ -12,9 +13,16 @@ public class WebConfig implements WebMvcConfigurer { @Autowired private LoginMemberArgumentResolver loginMemberArgumentResolver; + @Autowired + private AdminInterceptor adminInterceptor; @Override public void addArgumentResolvers(List argumentResolvers) { argumentResolvers.add(loginMemberArgumentResolver); } + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor) + .addPathPatterns("/admin/**"); + } } diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index b13a37a4..bb735721 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -86,4 +86,22 @@ private String createToken(String email, String password) { 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 f550f15b1ae5736754756a73bd7f2a4f67e8b76d Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Tue, 25 Jun 2024 00:37:23 +0900 Subject: [PATCH 07/22] =?UTF-8?q?=EA=B0=9C=ED=96=89=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 | 1 + src/test/java/roomescape/MissionStepTest.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 83a5e5f8..f3ffc6f2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,3 +9,4 @@ spring.datasource.url=jdbc:h2:mem:database #spring.jpa.defer-datasource-initialization=true #roomescape.auth.jwt.secret= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= + diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index bb735721..0b8b898e 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -104,4 +104,4 @@ private String createToken(String email, String password) { .then().log().all() .statusCode(200); } -} \ No newline at end of file +} From dd15dda71e3aa585d84410a7874e31b5b4cf4af2 Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Mon, 1 Jul 2024 00:20:21 +0900 Subject: [PATCH 08/22] =?UTF-8?q?step4=20-=20test=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/JpaTest.java | 30 +++++++++++++++++++ src/test/java/roomescape/MissionStepTest.java | 1 + 2 files changed, 31 insertions(+) create mode 100644 src/test/java/roomescape/JpaTest.java diff --git a/src/test/java/roomescape/JpaTest.java b/src/test/java/roomescape/JpaTest.java new file mode 100644 index 00000000..81bbae76 --- /dev/null +++ b/src/test/java/roomescape/JpaTest.java @@ -0,0 +1,30 @@ +package roomescape; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import roomescape.time.Time; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +public class JpaTest { + @Autowired + private TestEntityManager entityManager; + + @Autowired + private TimeRepository timeRepository; + + @Test + void 사단계() { + Time time = new Time("10:00"); + entityManager.persist(time); + entityManager.flush(); + + Time persistTime = timeRepository.findById(time.getId()).orElse(null); + + assertThat(persistTime.getTime()).isEqualTo(time.getTime()); + } +} + diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 0b8b898e..8f9b6e24 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -105,3 +105,4 @@ private String createToken(String email, String password) { .statusCode(200); } } + From 1469f1e597ebd441bd5dffe05a103de889a15da3 Mon Sep 17 00:00:00 2001 From: Kyuwon-Choi Date: Mon, 1 Jul 2024 02:07:36 +0900 Subject: [PATCH 09/22] =?UTF-8?q?step4=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- src/main/java/roomescape/member/Member.java | 14 +- .../java/roomescape/member/MemberDao.java | 67 --------- .../roomescape/member/MemberRepository.java | 7 + .../java/roomescape/member/MemberService.java | 12 +- .../roomescape/reservation/Reservation.java | 6 + .../reservation/ReservationDao.java | 127 ------------------ .../reservation/ReservationRepository.java | 10 ++ .../reservation/ReservationService.java | 26 ++-- src/main/java/roomescape/theme/Theme.java | 8 ++ .../roomescape/theme/ThemeController.java | 12 +- src/main/java/roomescape/theme/ThemeDao.java | 41 ------ .../roomescape/theme/ThemeRepository.java | 6 + src/main/java/roomescape/time/Time.java | 11 ++ src/main/java/roomescape/time/TimeDao.java | 41 ------ .../java/roomescape/time/TimeRepository.java | 6 + .../java/roomescape/time/TimeService.java | 22 +-- src/main/resources/application.properties | 8 +- src/main/resources/schema.sql | 60 --------- src/test/java/roomescape/JpaTest.java | 1 + 20 files changed, 110 insertions(+), 377 deletions(-) delete mode 100644 src/main/java/roomescape/member/MemberDao.java create mode 100644 src/main/java/roomescape/member/MemberRepository.java delete mode 100644 src/main/java/roomescape/reservation/ReservationDao.java create mode 100644 src/main/java/roomescape/reservation/ReservationRepository.java delete mode 100644 src/main/java/roomescape/theme/ThemeDao.java create mode 100644 src/main/java/roomescape/theme/ThemeRepository.java delete mode 100644 src/main/java/roomescape/time/TimeDao.java create mode 100644 src/main/java/roomescape/time/TimeRepository.java delete mode 100644 src/main/resources/schema.sql diff --git a/build.gradle b/build.gradle index b820ecb4..5d06a0e7 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 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.0.0' diff --git a/src/main/java/roomescape/member/Member.java b/src/main/java/roomescape/member/Member.java index 903aaa9b..1114f6b4 100644 --- a/src/main/java/roomescape/member/Member.java +++ b/src/main/java/roomescape/member/Member.java @@ -1,17 +1,21 @@ package roomescape.member; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity public class Member { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; private String password; private String role; - public Member(Long id, String name, String email, String role) { - this.id = id; - this.name = name; - this.email = email; - this.role = role; + public Member() { } public Member(String name, String email, String password, String role) { diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java deleted file mode 100644 index aa977a29..00000000 --- a/src/main/java/roomescape/member/MemberDao.java +++ /dev/null @@ -1,67 +0,0 @@ -package roomescape.member; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -@Repository -public class MemberDao { - private JdbcTemplate jdbcTemplate; - - public MemberDao(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public Member save(Member member) { - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(connection -> { - var ps = connection.prepareStatement("INSERT INTO member(name, email, password, role) VALUES (?, ?, ?, ?)", new String[]{"id"}); - ps.setString(1, member.getName()); - ps.setString(2, member.getEmail()); - ps.setString(3, member.getPassword()); - ps.setString(4, member.getRole()); - return ps; - }, keyHolder); - - return new Member(keyHolder.getKey().longValue(), member.getName(), member.getEmail(), "USER"); - } - - public Member findByEmailAndPassword(String email, String password) { - return jdbcTemplate.queryForObject( - "SELECT id, name, email, role FROM member WHERE email = ? AND password = ?", - (rs, rowNum) -> new Member( - rs.getLong("id"), - rs.getString("name"), - rs.getString("email"), - rs.getString("role") - ), - email, password - ); - } - - public Member findByName(String name) { - return jdbcTemplate.queryForObject( - "SELECT id, name, email, role FROM member WHERE name = ?", - (rs, rowNum) -> new Member( - rs.getLong("id"), - rs.getString("name"), - rs.getString("email"), - rs.getString("role") - ), - name - ); - } - public Member findById(Long id) { - return jdbcTemplate.queryForObject( - "SELECT id, name, email, role FROM member WHERE id = ?", - (rs, rowNum) -> new Member( - rs.getLong("id"), - rs.getString("name"), - rs.getString("email"), - rs.getString("role") - ), - id - ); - } -} diff --git a/src/main/java/roomescape/member/MemberRepository.java b/src/main/java/roomescape/member/MemberRepository.java new file mode 100644 index 00000000..1a061142 --- /dev/null +++ b/src/main/java/roomescape/member/MemberRepository.java @@ -0,0 +1,7 @@ +package roomescape.member; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { + Member findByEmailAndPassword(String email, String password); +} diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 7905a249..b564259b 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -8,19 +8,19 @@ @Service public class MemberService { - private MemberDao memberDao; + private MemberRepository memberRepository; - public MemberService(MemberDao memberDao) { - this.memberDao = memberDao; + public MemberService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; } public MemberResponse createMember(MemberRequest memberRequest) { - Member member = memberDao.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER")); + Member member = memberRepository.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER")); return new MemberResponse(member.getId(), member.getName(), member.getEmail()); } public Member findMemberByEmailAndPassword(String email, String password) { - Member member = memberDao.findByEmailAndPassword(email, password); + Member member = memberRepository.findByEmailAndPassword(email, password); return member; } public String createToken(Member member) { @@ -43,7 +43,7 @@ public Member findByToken(String token) { .build() .parseClaimsJws(token) .getBody().getSubject()); - Member member = memberDao.findById(memberId); + Member member = memberRepository.findById(memberId).orElseThrow(); return member; } } diff --git a/src/main/java/roomescape/reservation/Reservation.java b/src/main/java/roomescape/reservation/Reservation.java index 83a7edf1..49c29e7b 100644 --- a/src/main/java/roomescape/reservation/Reservation.java +++ b/src/main/java/roomescape/reservation/Reservation.java @@ -1,13 +1,19 @@ package roomescape.reservation; +import jakarta.persistence.*; import roomescape.theme.Theme; import roomescape.time.Time; +@Entity public class Reservation { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String date; + @ManyToOne private Time time; + @ManyToOne private Theme theme; public Reservation(Long id, String name, String date, Time time, Theme theme) { diff --git a/src/main/java/roomescape/reservation/ReservationDao.java b/src/main/java/roomescape/reservation/ReservationDao.java deleted file mode 100644 index a4972430..00000000 --- a/src/main/java/roomescape/reservation/ReservationDao.java +++ /dev/null @@ -1,127 +0,0 @@ -package roomescape.reservation; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; -import roomescape.theme.Theme; -import roomescape.time.Time; - -import java.sql.PreparedStatement; -import java.util.List; - -@Repository -public class ReservationDao { - - private final JdbcTemplate jdbcTemplate; - - public ReservationDao(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public List findAll() { - return jdbcTemplate.query( - "SELECT r.id AS reservation_id, r.name as reservation_name, r.date as reservation_date, " + - "t.id AS theme_id, t.name AS theme_name, t.description AS theme_description, " + - "ti.id AS time_id, ti.time_value AS time_value " + - "FROM reservation r " + - "JOIN theme t ON r.theme_id = t.id " + - "JOIN time ti ON r.time_id = ti.id", - - (rs, rowNum) -> new Reservation( - rs.getLong("reservation_id"), - rs.getString("reservation_name"), - rs.getString("reservation_date"), - new Time( - rs.getLong("time_id"), - rs.getString("time_value") - ), - new Theme( - rs.getLong("theme_id"), - rs.getString("theme_name"), - rs.getString("theme_description") - ))); - } - - public Reservation save(ReservationRequest reservationRequest) { - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(connection -> { - PreparedStatement ps = connection.prepareStatement("INSERT INTO reservation(date, name, theme_id, time_id) VALUES (?, ?, ?, ?)", new String[]{"id"}); - ps.setString(1, reservationRequest.getDate()); - ps.setString(2, reservationRequest.getName()); - ps.setLong(3, reservationRequest.getTheme()); - ps.setLong(4, reservationRequest.getTime()); - return ps; - }, keyHolder); - - Time time = jdbcTemplate.queryForObject("SELECT * FROM time WHERE id = ?", - (rs, rowNum) -> new Time(rs.getLong("id"), rs.getString("time_value")), - reservationRequest.getTime()); - - Theme theme = jdbcTemplate.queryForObject("SELECT * FROM theme WHERE id = ?", - (rs, rowNum) -> new Theme(rs.getLong("id"), rs.getString("name"), rs.getString("description")), - reservationRequest.getTheme()); - - return new Reservation( - keyHolder.getKey().longValue(), - reservationRequest.getName(), - reservationRequest.getDate(), - time, - theme - ); - } - - public void deleteById(Long id) { - jdbcTemplate.update("DELETE FROM reservation WHERE id = ?", id); - } - - public List findReservationsByDateAndTheme(String date, Long themeId) { - return jdbcTemplate.query( - "SELECT r.id AS reservation_id, r.name as reservation_name, r.date as reservation_date, " + - "t.id AS theme_id, t.name AS theme_name, t.description AS theme_description, " + - "ti.id AS time_id, ti.time_value AS time_value " + - "FROM reservation r " + - "JOIN theme t ON r.theme_id = t.id " + - "JOIN time ti ON r.time_id = ti.id" + - "WHERE r.date = ? AND r.theme_id = ?", - new Object[]{date, themeId}, - (rs, rowNum) -> new Reservation( - rs.getLong("reservation_id"), - rs.getString("reservation_name"), - rs.getString("reservation_date"), - new Time( - rs.getLong("time_id"), - rs.getString("time_value") - ), - new Theme( - rs.getLong("theme_id"), - rs.getString("theme_name"), - rs.getString("theme_description") - ))); - } - - public List findByDateAndThemeId(String date, Long themeId) { - return jdbcTemplate.query( - "SELECT r.id AS reservation_id, r.name as reservation_name, r.date as reservation_date, " + - "t.id AS theme_id, t.name AS theme_name, t.description AS theme_description, " + - "ti.id AS time_id, ti.time_value AS time_value " + - "FROM reservation r " + - "JOIN theme t ON r.theme_id = t.id " + - "JOIN time ti ON r.time_id = ti.id " + - "WHERE r.date = ? AND r.theme_id = ?", - new Object[]{date, themeId}, - (rs, rowNum) -> new Reservation( - rs.getLong("reservation_id"), - rs.getString("reservation_name"), - rs.getString("reservation_date"), - new Time( - rs.getLong("time_id"), - rs.getString("time_value") - ), - new Theme( - rs.getLong("theme_id"), - rs.getString("theme_name"), - rs.getString("theme_description") - ))); - } -} diff --git a/src/main/java/roomescape/reservation/ReservationRepository.java b/src/main/java/roomescape/reservation/ReservationRepository.java new file mode 100644 index 00000000..7cd40286 --- /dev/null +++ b/src/main/java/roomescape/reservation/ReservationRepository.java @@ -0,0 +1,10 @@ +package roomescape.reservation; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface ReservationRepository extends JpaRepository { + List findByDateAndThemeId(String date, Long themeId); + +} diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index 69e44405..3408fa56 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -1,29 +1,39 @@ package roomescape.reservation; import org.springframework.stereotype.Service; +import roomescape.theme.Theme; +import roomescape.theme.ThemeRepository; +import roomescape.time.Time; +import roomescape.time.TimeRepository; import java.util.List; @Service public class ReservationService { - private ReservationDao reservationDao; + private ReservationRepository reservationRepository; + private TimeRepository timeRepository; + private ThemeRepository themeRepository; - public ReservationService(ReservationDao reservationDao) { - this.reservationDao = reservationDao; + + public ReservationService(ReservationRepository reservationRepository, TimeRepository timeRepository, ThemeRepository themeRepository) { + this.reservationRepository = reservationRepository; + this.timeRepository = timeRepository; + this.themeRepository = themeRepository; } public ReservationResponse save(ReservationRequest reservationRequest) { - Reservation reservation = reservationDao.save(reservationRequest); - - return new ReservationResponse(reservation.getId(), reservationRequest.getName(), reservation.getTheme().getName(), reservation.getDate(), reservation.getTime().getValue()); + Time time = timeRepository.findById(reservationRequest.getTime()).orElseThrow(); + Theme theme = themeRepository.findById(reservationRequest.getTheme()).orElseThrow(); + Reservation reservation = reservationRepository.save(new Reservation(reservationRequest.getName(), reservationRequest.getDate(), time, theme)); + return new ReservationResponse(reservation.getId(), reservation.getName(), reservation.getTheme().getName(), reservation.getDate(), reservation.getTime().getValue()); } public void deleteById(Long id) { - reservationDao.deleteById(id); + reservationRepository.deleteById(id); } public List findAll() { - return reservationDao.findAll().stream() + return reservationRepository.findAll().stream() .map(it -> new ReservationResponse(it.getId(), it.getName(), it.getTheme().getName(), it.getDate(), it.getTime().getValue())) .toList(); } diff --git a/src/main/java/roomescape/theme/Theme.java b/src/main/java/roomescape/theme/Theme.java index 430a6239..1063c86d 100644 --- a/src/main/java/roomescape/theme/Theme.java +++ b/src/main/java/roomescape/theme/Theme.java @@ -1,6 +1,14 @@ package roomescape.theme; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity public class Theme { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String description; diff --git a/src/main/java/roomescape/theme/ThemeController.java b/src/main/java/roomescape/theme/ThemeController.java index 03bca41a..f336ffe8 100644 --- a/src/main/java/roomescape/theme/ThemeController.java +++ b/src/main/java/roomescape/theme/ThemeController.java @@ -13,26 +13,26 @@ @RestController public class ThemeController { - private ThemeDao themeDao; + private ThemeRepository themeRepository; - public ThemeController(ThemeDao themeDao) { - this.themeDao = themeDao; + public ThemeController(ThemeRepository themeRepository) { + this.themeRepository = themeRepository; } @PostMapping("/themes") public ResponseEntity createTheme(@RequestBody Theme theme) { - Theme newTheme = themeDao.save(theme); + Theme newTheme = themeRepository.save(theme); return ResponseEntity.created(URI.create("/themes/" + newTheme.getId())).body(newTheme); } @GetMapping("/themes") public ResponseEntity> list() { - return ResponseEntity.ok(themeDao.findAll()); + return ResponseEntity.ok(themeRepository.findAll()); } @DeleteMapping("/themes/{id}") public ResponseEntity deleteTheme(@PathVariable Long id) { - themeDao.deleteById(id); + themeRepository.deleteById(id); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/roomescape/theme/ThemeDao.java b/src/main/java/roomescape/theme/ThemeDao.java deleted file mode 100644 index 945341d8..00000000 --- a/src/main/java/roomescape/theme/ThemeDao.java +++ /dev/null @@ -1,41 +0,0 @@ -package roomescape.theme; - -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.util.List; - -@Repository -public class ThemeDao { - private JdbcTemplate jdbcTemplate; - - public ThemeDao(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - public List findAll() { - return jdbcTemplate.query("SELECT * FROM theme where deleted = false", (rs, rowNum) -> new Theme( - rs.getLong("id"), - rs.getString("name"), - rs.getString("description") - )); - } - - public Theme save(Theme theme) { - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(connection -> { - var ps = connection.prepareStatement("INSERT INTO theme(name, description) VALUES (?, ?)", new String[]{"id"}); - ps.setString(1, theme.getName()); - ps.setString(2, theme.getDescription()); - return ps; - }, keyHolder); - - return new Theme(keyHolder.getKey().longValue(), theme.getName(), theme.getDescription()); - } - - public void deleteById(Long id) { - jdbcTemplate.update("UPDATE theme SET deleted = true WHERE id = ?", id); - } -} diff --git a/src/main/java/roomescape/theme/ThemeRepository.java b/src/main/java/roomescape/theme/ThemeRepository.java new file mode 100644 index 00000000..cbdb21a3 --- /dev/null +++ b/src/main/java/roomescape/theme/ThemeRepository.java @@ -0,0 +1,6 @@ +package roomescape.theme; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ThemeRepository extends JpaRepository { +} diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java index 008ed93c..15efd74c 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.*; +import lombok.Getter; + +@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) { @@ -24,4 +31,8 @@ public Long getId() { public String getValue() { return value; } + + public String getTime() { + return value; + } } 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