From 8b4d56123f2d4b7f39a5832a3de777527b6573f7 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Sun, 23 Jun 2024 20:15:01 +0900 Subject: [PATCH 01/26] =?UTF-8?q?feat:=20[1=EB=8B=A8=EA=B3=84]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A0=81=EC=9A=A9=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/MissionStepTest.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 6add784b..64dfb547 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -32,7 +32,16 @@ public class MissionStepTest { .extract(); String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; - 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("어드민"); } -} \ No newline at end of file +} From b8323702f2c59056f5dbd47e96b6211be0ff3518 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Sun, 23 Jun 2024 22:05:51 +0900 Subject: [PATCH 02/26] =?UTF-8?q?feat:=20[1=EB=8B=A8=EA=B3=84]=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=9A=94=EC=B2=AD=EC=8B=9C=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EB=B0=9C=EA=B8=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/jwt/JwtProvider.java | 24 ++++++++ .../roomescape/member/MemberController.java | 60 +++++++++++-------- .../roomescape/member/MemberLoginRequest.java | 7 +++ .../java/roomescape/member/MemberService.java | 12 ++++ src/main/resources/application.properties | 4 +- 5 files changed, 78 insertions(+), 29 deletions(-) create mode 100644 src/main/java/roomescape/jwt/JwtProvider.java create mode 100644 src/main/java/roomescape/member/MemberLoginRequest.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..e6100679 --- /dev/null +++ b/src/main/java/roomescape/jwt/JwtProvider.java @@ -0,0 +1,24 @@ +package roomescape.jwt; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import roomescape.member.Member; + +@Component +public class JwtProvider { + + @Value("${roomescape.auth.jwt.secret}") + private String secretKey; + + public String createToken(Member member) { + return Jwts.builder() + .setSubject(member.getId().toString()) + .claim("name", member.getName()) + .claim("role", member.getRole()) + .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) + .compact(); + } +} diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 881ae5e0..e12f4684 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -1,37 +1,45 @@ package roomescape.member; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; +import java.net.URI; + 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 java.net.URI; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletResponse; @RestController public class MemberController { - private MemberService memberService; - - public MemberController(MemberService memberService) { - this.memberService = memberService; - } - - @PostMapping("/members") - 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(); - } + private MemberService memberService; + + public MemberController(MemberService memberService) { + this.memberService = memberService; + } + + @PostMapping("/members") + public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { + MemberResponse member = memberService.createMember(memberRequest); + return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member); + } + + @PostMapping("/login") + public void login(@RequestBody MemberLoginRequest request, HttpServletResponse response) { + String token = memberService.login(request); + Cookie cookie = new Cookie("token", token); + cookie.setHttpOnly(true); + cookie.setPath("/"); + response.addCookie(cookie); + } + + @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/member/MemberLoginRequest.java b/src/main/java/roomescape/member/MemberLoginRequest.java new file mode 100644 index 00000000..467f6d55 --- /dev/null +++ b/src/main/java/roomescape/member/MemberLoginRequest.java @@ -0,0 +1,7 @@ +package roomescape.member; + +public record MemberLoginRequest( + String password, + String email +) { +} diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index ccaa8cba..1c9034f9 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -2,12 +2,24 @@ import org.springframework.stereotype.Service; +import roomescape.jwt.JwtProvider; + @Service public class MemberService { private MemberDao memberDao; + private JwtProvider jwtProvider; public MemberService(MemberDao memberDao) { this.memberDao = memberDao; + this.jwtProvider = new JwtProvider(); + } + + public String login(MemberLoginRequest request) { + Member member = memberDao.findByEmailAndPassword(request.email(), request.password()); + if(member == null){ + throw new IllegalArgumentException("Invalid email or password"); + } + return jwtProvider.createToken(member); } public MemberResponse createMember(MemberRequest memberRequest) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a0f33bba..dc720f30 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,10 +2,8 @@ spring.sql.init.encoding=utf-8 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 - -#roomescape.auth.jwt.secret= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= \ No newline at end of file +roomescape.auth.jwt.secret=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= From 916b61e00091accb7df1e2e3d946b84f9232dd10 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Sun, 23 Jun 2024 22:27:30 +0900 Subject: [PATCH 03/26] =?UTF-8?q?feat:=20[1=EB=8B=A8=EA=B3=84]=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EA=B2=80=EC=A6=9D=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/jwt/JwtProvider.java | 4 +- src/main/java/roomescape/jwt/JwtUtil.java | 26 +++++ .../member/MemberCheckResponse.java | 6 + .../roomescape/member/MemberController.java | 10 ++ .../java/roomescape/member/MemberDao.java | 105 ++++++++++-------- .../java/roomescape/member/MemberService.java | 45 +++++--- 6 files changed, 131 insertions(+), 65 deletions(-) create mode 100644 src/main/java/roomescape/jwt/JwtUtil.java create mode 100644 src/main/java/roomescape/member/MemberCheckResponse.java diff --git a/src/main/java/roomescape/jwt/JwtProvider.java b/src/main/java/roomescape/jwt/JwtProvider.java index e6100679..e6efbff6 100644 --- a/src/main/java/roomescape/jwt/JwtProvider.java +++ b/src/main/java/roomescape/jwt/JwtProvider.java @@ -1,6 +1,5 @@ package roomescape.jwt; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import io.jsonwebtoken.Jwts; @@ -10,8 +9,7 @@ @Component public class JwtProvider { - @Value("${roomescape.auth.jwt.secret}") - private String secretKey; + private String secretKey = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E="; public String createToken(Member member) { return Jwts.builder() diff --git a/src/main/java/roomescape/jwt/JwtUtil.java b/src/main/java/roomescape/jwt/JwtUtil.java new file mode 100644 index 00000000..d524b172 --- /dev/null +++ b/src/main/java/roomescape/jwt/JwtUtil.java @@ -0,0 +1,26 @@ +package roomescape.jwt; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.Cookie; + +public class JwtUtil { + + public static String extractTokenFromCookie(Cookie[] cookies) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("token")) { + return cookie.getValue(); + } + } + return ""; + } + + public static Long decodeToken(String token) { + return Long.valueOf(Jwts.parserBuilder() + .setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes())) + .build() + .parseClaimsJws(token) + .getBody().getSubject()); + } + +} diff --git a/src/main/java/roomescape/member/MemberCheckResponse.java b/src/main/java/roomescape/member/MemberCheckResponse.java new file mode 100644 index 00000000..8c3cb1db --- /dev/null +++ b/src/main/java/roomescape/member/MemberCheckResponse.java @@ -0,0 +1,6 @@ +package roomescape.member; + +public record MemberCheckResponse( + String name +) { +} diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index e12f4684..4805547f 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -3,12 +3,15 @@ import java.net.URI; 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 jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import roomescape.jwt.JwtUtil; @RestController public class MemberController { @@ -33,6 +36,13 @@ public void login(@RequestBody MemberLoginRequest request, HttpServletResponse r response.addCookie(cookie); } + @GetMapping("/login/check") + public MemberCheckResponse checkLogin(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + String token = JwtUtil.extractTokenFromCookie(cookies); + return memberService.checkMember(token); + } + @PostMapping("/logout") public ResponseEntity logout(HttpServletResponse response) { Cookie cookie = new Cookie("token", ""); diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java index 81f77f4c..9840a429 100644 --- a/src/main/java/roomescape/member/MemberDao.java +++ b/src/main/java/roomescape/member/MemberDao.java @@ -7,49 +7,64 @@ @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 - ); - } + 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/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 1c9034f9..319ccb7b 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -3,27 +3,38 @@ import org.springframework.stereotype.Service; import roomescape.jwt.JwtProvider; +import roomescape.jwt.JwtUtil; @Service public class MemberService { - private MemberDao memberDao; - private JwtProvider jwtProvider; + private MemberDao memberDao; + private JwtProvider jwtProvider; - public MemberService(MemberDao memberDao) { - this.memberDao = memberDao; - this.jwtProvider = new JwtProvider(); - } + public MemberService(MemberDao memberDao) { + this.memberDao = memberDao; + this.jwtProvider = new JwtProvider(); + } - public String login(MemberLoginRequest request) { - Member member = memberDao.findByEmailAndPassword(request.email(), request.password()); - if(member == null){ - throw new IllegalArgumentException("Invalid email or password"); - } - return jwtProvider.createToken(member); - } + public String login(MemberLoginRequest request) { + Member member = memberDao.findByEmailAndPassword(request.email(), request.password()); + if (member == null) { + throw new IllegalArgumentException("Invalid email or password"); + } + return jwtProvider.createToken(member); + } - 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 MemberCheckResponse checkMember(String token) { + Long memberId = JwtUtil.decodeToken(token); + Member member = memberDao.findById(memberId); + if (member == null) { + throw new IllegalArgumentException("Invalid member"); + } + return new MemberCheckResponse(member.getName()); + } + + 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()); + } } From 814f97767de18604a7db4113caa1e34f4300cd35 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Sun, 23 Jun 2024 22:43:39 +0900 Subject: [PATCH 04/26] =?UTF-8?q?feat:=20[2=EB=8B=A8=EA=B3=84]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/MissionStepTest.java | 105 ++++++++++++------ 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 64dfb547..4c57cafa 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -1,47 +1,82 @@ package roomescape; -import io.restassured.RestAssured; -import io.restassured.http.ContentType; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; +import static org.assertj.core.api.Assertions.*; import java.util.HashMap; import java.util.Map; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import roomescape.reservation.ReservationResponse; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class MissionStepTest { - @Test - void 일단계() { - Map params = new HashMap<>(); - params.put("email", "admin@email.com"); - params.put("password", "password"); - - ExtractableResponse response = RestAssured.given().log().all() - .contentType(ContentType.JSON) - .body(params) - .when().post("/login") - .then().log().all() - .statusCode(200) - .extract(); - - String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; - 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 일단계() { + Map params = new HashMap<>(); + params.put("email", "admin@email.com"); + params.put("password", "password"); + + ExtractableResponse response = RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(params) + .when().post("/login") + .then().log().all() + .statusCode(200) + .extract(); + + String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; + 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("브라운"); + } } From 728c6dd28689e3a88899de5970f2aa95ccec62a8 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 24 Jun 2024 02:56:57 +0900 Subject: [PATCH 05/26] =?UTF-8?q?feat:=20[2=EB=8B=A8=EA=B3=84]=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=EC=9C=BC=EB=A1=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/LoginMemberArgumentResolver.java | 43 +++++++++++++++++++ src/main/java/roomescape/jwt/JwtProvider.java | 7 +++ .../java/roomescape/member/LoginMember.java | 15 +++++++ .../java/roomescape/member/MemberService.java | 5 +++ 4 files changed, 70 insertions(+) create mode 100644 src/main/java/roomescape/auth/LoginMemberArgumentResolver.java create mode 100644 src/main/java/roomescape/member/LoginMember.java diff --git a/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java b/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java new file mode 100644 index 00000000..584a8796 --- /dev/null +++ b/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java @@ -0,0 +1,43 @@ +package roomescape.auth; + +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 jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import roomescape.jwt.JwtUtil; +import roomescape.member.LoginMember; +import roomescape.member.Member; +import roomescape.member.MemberService; + +@Component +public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { + + private final 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 = webRequest.getNativeRequest(HttpServletRequest.class); + Cookie[] cookies = request.getCookies(); + String token = JwtUtil.extractTokenFromCookie(cookies); + if (token == null) { + return null; + } + Member member = memberService.getMemberFromToken(token); + return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getRole()); + } +} diff --git a/src/main/java/roomescape/jwt/JwtProvider.java b/src/main/java/roomescape/jwt/JwtProvider.java index e6efbff6..5aba804b 100644 --- a/src/main/java/roomescape/jwt/JwtProvider.java +++ b/src/main/java/roomescape/jwt/JwtProvider.java @@ -19,4 +19,11 @@ public String createToken(Member member) { .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) .compact(); } + + public String createToken(String email, String password) { + return Jwts.builder() + .claim("email", email) + .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) + .compact(); + } } diff --git a/src/main/java/roomescape/member/LoginMember.java b/src/main/java/roomescape/member/LoginMember.java new file mode 100644 index 00000000..a3e73fcc --- /dev/null +++ b/src/main/java/roomescape/member/LoginMember.java @@ -0,0 +1,15 @@ +package roomescape.member; + +public class LoginMember { + Long id; + String name; + String email; + String password; + + public LoginMember(Long id, String name, String email, String password) { + this.id = id; + this.name = name; + this.email = email; + this.password = password; + } +} diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 319ccb7b..96d31d1b 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -32,6 +32,11 @@ public MemberCheckResponse checkMember(String token) { return new MemberCheckResponse(member.getName()); } + public Member getMemberFromToken(String token) { + Long memberId = JwtUtil.decodeToken(token); + return memberDao.findById(memberId); + } + public MemberResponse createMember(MemberRequest memberRequest) { Member member = memberDao.save( new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER")); From 62dc58219fe20dc12bd03a35b9ccabd426ab05ae Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 24 Jun 2024 03:40:03 +0900 Subject: [PATCH 06/26] =?UTF-8?q?feat:=20[2=EB=8B=A8=EA=B3=84]=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=EC=9C=BC=EB=A1=9C=20=EC=98=88=EC=95=BD=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/config/WebConfig.java | 24 +++++++ src/main/java/roomescape/jwt/JwtProvider.java | 7 -- .../java/roomescape/member/LoginMember.java | 17 ++--- .../reservation/ReservationController.java | 64 ++++++++++--------- .../reservation/ReservationRequest.java | 39 ++++++----- .../reservation/ReservationService.java | 52 ++++++++------- src/test/java/roomescape/MissionStepTest.java | 16 +++-- 7 files changed, 126 insertions(+), 93 deletions(-) create mode 100644 src/main/java/roomescape/config/WebConfig.java diff --git a/src/main/java/roomescape/config/WebConfig.java b/src/main/java/roomescape/config/WebConfig.java new file mode 100644 index 00000000..9ca2da19 --- /dev/null +++ b/src/main/java/roomescape/config/WebConfig.java @@ -0,0 +1,24 @@ +package roomescape.config; + +import java.util.List; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import roomescape.auth.LoginMemberArgumentResolver; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + private final LoginMemberArgumentResolver loginMemberArgumentResolver; + + public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver) { + this.loginMemberArgumentResolver = loginMemberArgumentResolver; + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(loginMemberArgumentResolver); + } +} diff --git a/src/main/java/roomescape/jwt/JwtProvider.java b/src/main/java/roomescape/jwt/JwtProvider.java index 5aba804b..e6efbff6 100644 --- a/src/main/java/roomescape/jwt/JwtProvider.java +++ b/src/main/java/roomescape/jwt/JwtProvider.java @@ -19,11 +19,4 @@ public String createToken(Member member) { .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) .compact(); } - - public String createToken(String email, String password) { - return Jwts.builder() - .claim("email", email) - .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) - .compact(); - } } diff --git a/src/main/java/roomescape/member/LoginMember.java b/src/main/java/roomescape/member/LoginMember.java index a3e73fcc..7e8515b6 100644 --- a/src/main/java/roomescape/member/LoginMember.java +++ b/src/main/java/roomescape/member/LoginMember.java @@ -1,15 +1,8 @@ package roomescape.member; -public class LoginMember { - Long id; - String name; - String email; - String password; - - public LoginMember(Long id, String name, String email, String password) { - this.id = id; - this.name = name; - this.email = email; - this.password = password; - } +public record LoginMember( + Long id, + String name, + String email, + String password) { } diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index b3bef399..44cbf144 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -1,5 +1,8 @@ package roomescape.reservation; +import java.net.URI; +import java.util.List; + import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -8,39 +11,38 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.net.URI; -import java.util.List; +import roomescape.member.LoginMember; @RestController public class ReservationController { - private final ReservationService reservationService; - - public ReservationController(ReservationService reservationService) { - this.reservationService = reservationService; - } - - @GetMapping("/reservations") - public List list() { - return reservationService.findAll(); - } - - @PostMapping("/reservations") - public ResponseEntity create(@RequestBody ReservationRequest reservationRequest) { - if (reservationRequest.getName() == null - || reservationRequest.getDate() == null - || reservationRequest.getTheme() == null - || reservationRequest.getTime() == null) { - return ResponseEntity.badRequest().build(); - } - ReservationResponse reservation = reservationService.save(reservationRequest); - - return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())).body(reservation); - } - - @DeleteMapping("/reservations/{id}") - public ResponseEntity delete(@PathVariable Long id) { - reservationService.deleteById(id); - return ResponseEntity.noContent().build(); - } + private final ReservationService reservationService; + + public ReservationController(ReservationService reservationService) { + this.reservationService = reservationService; + } + + @GetMapping("/reservations") + public List list() { + return reservationService.findAll(); + } + + @PostMapping("/reservations") + public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, LoginMember member) { + if (reservationRequest.getDate() == null + || reservationRequest.getTheme() == null + || reservationRequest.getTime() == null) { + return ResponseEntity.badRequest().build(); + } + System.out.println(member.name()); + ReservationResponse reservation = reservationService.save(reservationRequest, member); + + return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())).body(reservation); + } + + @DeleteMapping("/reservations/{id}") + public ResponseEntity delete(@PathVariable Long id) { + reservationService.deleteById(id); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/roomescape/reservation/ReservationRequest.java b/src/main/java/roomescape/reservation/ReservationRequest.java index 19f44124..e5d85470 100644 --- a/src/main/java/roomescape/reservation/ReservationRequest.java +++ b/src/main/java/roomescape/reservation/ReservationRequest.java @@ -1,24 +1,31 @@ package roomescape.reservation; public class ReservationRequest { - private String name; - private String date; - private Long theme; - private Long time; + private String name; + private String date; + private Long theme; + private Long time; - public String getName() { - return name; - } + public ReservationRequest(String name, String date, Long theme, Long time) { + this.name = name; + this.date = date; + this.theme = theme; + this.time = time; + } - public String getDate() { - return date; - } + public String getName() { + return name; + } - public Long getTheme() { - return theme; - } + public String getDate() { + return date; + } - public Long getTime() { - return time; - } + public Long getTheme() { + return theme; + } + + public Long getTime() { + return time; + } } diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index bd331332..55f125b1 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -1,30 +1,38 @@ package roomescape.reservation; +import java.util.List; + import org.springframework.stereotype.Service; -import java.util.List; +import roomescape.member.LoginMember; @Service public class ReservationService { - private ReservationDao reservationDao; - - public ReservationService(ReservationDao reservationDao) { - this.reservationDao = reservationDao; - } - - 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()); - } - - public void deleteById(Long id) { - reservationDao.deleteById(id); - } - - public List findAll() { - return reservationDao.findAll().stream() - .map(it -> new ReservationResponse(it.getId(), it.getName(), it.getTheme().getName(), it.getDate(), it.getTime().getValue())) - .toList(); - } + private ReservationDao reservationDao; + + public ReservationService(ReservationDao reservationDao) { + this.reservationDao = reservationDao; + } + + public ReservationResponse save(ReservationRequest reservationRequest, LoginMember member) { + if (reservationRequest.getName() == null) { + reservationRequest = new ReservationRequest(member.name(), reservationRequest.getDate(), + reservationRequest.getTheme(), reservationRequest.getTime()); + } + Reservation reservation = reservationDao.save(reservationRequest); + + return new ReservationResponse(reservation.getId(), reservationRequest.getName(), + reservation.getTheme().getName(), reservation.getDate(), reservation.getTime().getValue()); + } + + public void deleteById(Long id) { + reservationDao.deleteById(id); + } + + public List findAll() { + return reservationDao.findAll().stream() + .map(it -> new ReservationResponse(it.getId(), it.getName(), it.getTheme().getName(), it.getDate(), + it.getTime().getValue())) + .toList(); + } } diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 4c57cafa..90df18b6 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -19,11 +19,11 @@ @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class MissionStepTest { - @Test - void 일단계() { + 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) @@ -33,7 +33,12 @@ 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() @@ -50,6 +55,7 @@ public class MissionStepTest { @Test void 이단계() { String token = createToken("admin@email.com", "password"); // 일단계에서 토큰을 추출하는 로직을 메서드로 따로 만들어서 활용하세요. + Map params = new HashMap<>(); params.put("date", "2024-03-01"); params.put("time", "1"); From 016927380d901272472db515ee51890f0fd6077c Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 24 Jun 2024 03:40:43 +0900 Subject: [PATCH 07/26] =?UTF-8?q?feat:=20[3=EB=8B=A8=EA=B3=84]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A0=81=EC=9A=A9=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/MissionStepTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 90df18b6..33e4c182 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -85,4 +85,23 @@ 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); + } } From 5db49d6b5151e594234ad38ee1936ec156af435b Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 24 Jun 2024 04:18:43 +0900 Subject: [PATCH 08/26] =?UTF-8?q?feat:=20[3=EB=8B=A8=EA=B3=84]=20admin=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9D=B8=ED=84=B0=EC=85=89?= =?UTF-8?q?=ED=84=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/auth/AdminInterceptor.java | 33 +++++++++++++++++++ .../java/roomescape/config/WebConfig.java | 14 +++++++- src/main/resources/application.properties | 2 +- src/test/java/roomescape/MissionStepTest.java | 2 ++ 4 files changed, 49 insertions(+), 2 deletions(-) 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..6e6fbcf2 --- /dev/null +++ b/src/main/java/roomescape/auth/AdminInterceptor.java @@ -0,0 +1,33 @@ +package roomescape.auth; + +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import roomescape.jwt.JwtUtil; +import roomescape.member.Member; +import roomescape.member.MemberService; + +@Component +public class AdminInterceptor implements HandlerInterceptor { + + private MemberService memberService; + + public AdminInterceptor(MemberService memberService) { + this.memberService = memberService; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws + Exception { + String token = JwtUtil.extractTokenFromCookie(request.getCookies()); + Member member = memberService.getMemberFromToken(token); + if (member == null || !member.getRole().equals("ADMIN")) { + response.setStatus(401); + return false; + } + return true; + } + +} diff --git a/src/main/java/roomescape/config/WebConfig.java b/src/main/java/roomescape/config/WebConfig.java index 9ca2da19..ac6f9908 100644 --- a/src/main/java/roomescape/config/WebConfig.java +++ b/src/main/java/roomescape/config/WebConfig.java @@ -2,23 +2,35 @@ import java.util.List; +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 roomescape.auth.AdminInterceptor; import roomescape.auth.LoginMemberArgumentResolver; @Configuration public class WebConfig implements WebMvcConfigurer { private final LoginMemberArgumentResolver loginMemberArgumentResolver; + private final AdminInterceptor adminInterceptor; - public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver) { + @Autowired + public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver, AdminInterceptor adminInterceptor) { this.loginMemberArgumentResolver = loginMemberArgumentResolver; + this.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/main/resources/application.properties b/src/main/resources/application.properties index dc720f30..f4c9d071 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,8 +2,8 @@ spring.sql.init.encoding=utf-8 spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.datasource.url=jdbc:h2:mem:database +roomescape.auth.jwt.secret=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= #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=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 33e4c182..9d253b5d 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; import io.restassured.RestAssured; import io.restassured.http.ContentType; @@ -17,6 +18,7 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@TestPropertySource(locations = "classpath:application.properties") public class MissionStepTest { String createToken(String email, String password) { From c978b3c85666f0466dba4800151a34d74ccc6119 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 24 Jun 2024 04:30:43 +0900 Subject: [PATCH 09/26] =?UTF-8?q?refactor:=20[3=EB=8B=A8=EA=B3=84]=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B0=8F=20=ED=95=A8=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/auth/AdminInterceptor.java | 1 - .../WebConfig.java => auth/AuthWebConfiguration.java} | 10 ++++------ .../java/roomescape/{member => auth}/LoginMember.java | 2 +- .../roomescape/auth/LoginMemberArgumentResolver.java | 1 - src/main/java/roomescape/jwt/JwtUtil.java | 3 +-- src/main/java/roomescape/member/MemberService.java | 4 ++-- .../roomescape/reservation/ReservationController.java | 2 +- .../roomescape/reservation/ReservationService.java | 2 +- src/test/java/roomescape/MissionStepTest.java | 2 +- 9 files changed, 11 insertions(+), 16 deletions(-) rename src/main/java/roomescape/{config/WebConfig.java => auth/AuthWebConfiguration.java} (77%) rename src/main/java/roomescape/{member => auth}/LoginMember.java (76%) diff --git a/src/main/java/roomescape/auth/AdminInterceptor.java b/src/main/java/roomescape/auth/AdminInterceptor.java index 6e6fbcf2..642e1131 100644 --- a/src/main/java/roomescape/auth/AdminInterceptor.java +++ b/src/main/java/roomescape/auth/AdminInterceptor.java @@ -29,5 +29,4 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } return true; } - } diff --git a/src/main/java/roomescape/config/WebConfig.java b/src/main/java/roomescape/auth/AuthWebConfiguration.java similarity index 77% rename from src/main/java/roomescape/config/WebConfig.java rename to src/main/java/roomescape/auth/AuthWebConfiguration.java index ac6f9908..13e1a22e 100644 --- a/src/main/java/roomescape/config/WebConfig.java +++ b/src/main/java/roomescape/auth/AuthWebConfiguration.java @@ -1,4 +1,4 @@ -package roomescape.config; +package roomescape.auth; import java.util.List; @@ -8,17 +8,15 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import roomescape.auth.AdminInterceptor; -import roomescape.auth.LoginMemberArgumentResolver; - @Configuration -public class WebConfig implements WebMvcConfigurer { +public class AuthWebConfiguration implements WebMvcConfigurer { private final LoginMemberArgumentResolver loginMemberArgumentResolver; private final AdminInterceptor adminInterceptor; @Autowired - public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver, AdminInterceptor adminInterceptor) { + public AuthWebConfiguration(LoginMemberArgumentResolver loginMemberArgumentResolver, + AdminInterceptor adminInterceptor) { this.loginMemberArgumentResolver = loginMemberArgumentResolver; this.adminInterceptor = adminInterceptor; } diff --git a/src/main/java/roomescape/member/LoginMember.java b/src/main/java/roomescape/auth/LoginMember.java similarity index 76% rename from src/main/java/roomescape/member/LoginMember.java rename to src/main/java/roomescape/auth/LoginMember.java index 7e8515b6..bdb01f97 100644 --- a/src/main/java/roomescape/member/LoginMember.java +++ b/src/main/java/roomescape/auth/LoginMember.java @@ -1,4 +1,4 @@ -package roomescape.member; +package roomescape.auth; public record LoginMember( Long id, diff --git a/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java b/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java index 584a8796..22b9ae26 100644 --- a/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java +++ b/src/main/java/roomescape/auth/LoginMemberArgumentResolver.java @@ -10,7 +10,6 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import roomescape.jwt.JwtUtil; -import roomescape.member.LoginMember; import roomescape.member.Member; import roomescape.member.MemberService; diff --git a/src/main/java/roomescape/jwt/JwtUtil.java b/src/main/java/roomescape/jwt/JwtUtil.java index d524b172..cfdbdf39 100644 --- a/src/main/java/roomescape/jwt/JwtUtil.java +++ b/src/main/java/roomescape/jwt/JwtUtil.java @@ -15,12 +15,11 @@ public static String extractTokenFromCookie(Cookie[] cookies) { return ""; } - public static Long decodeToken(String token) { + public static Long getIdFromToken(String token) { return Long.valueOf(Jwts.parserBuilder() .setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes())) .build() .parseClaimsJws(token) .getBody().getSubject()); } - } diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 96d31d1b..60d4acd3 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -24,7 +24,7 @@ public String login(MemberLoginRequest request) { } public MemberCheckResponse checkMember(String token) { - Long memberId = JwtUtil.decodeToken(token); + Long memberId = JwtUtil.getIdFromToken(token); Member member = memberDao.findById(memberId); if (member == null) { throw new IllegalArgumentException("Invalid member"); @@ -33,7 +33,7 @@ public MemberCheckResponse checkMember(String token) { } public Member getMemberFromToken(String token) { - Long memberId = JwtUtil.decodeToken(token); + Long memberId = JwtUtil.getIdFromToken(token); return memberDao.findById(memberId); } diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index 44cbf144..3b1cbba2 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import roomescape.member.LoginMember; +import roomescape.auth.LoginMember; @RestController public class ReservationController { diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index 55f125b1..6e10d158 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -4,7 +4,7 @@ import org.springframework.stereotype.Service; -import roomescape.member.LoginMember; +import roomescape.auth.LoginMember; @Service public class ReservationService { diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 9d253b5d..cce9fb06 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -21,7 +21,7 @@ @TestPropertySource(locations = "classpath:application.properties") public class MissionStepTest { - String createToken(String email, String password) { + private String createToken(String email, String password) { Map params = new HashMap<>(); params.put("email", email); From c9a3e42161a13cb0c0117ba53f550fd7327211a8 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 01:32:03 +0900 Subject: [PATCH 10/26] =?UTF-8?q?refactor:=20=EC=8B=9C=ED=81=AC=EB=A6=BF?= =?UTF-8?q?=20=ED=82=A4=20=EA=B0=90=EC=B6=94=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/jwt/JwtProvider.java | 6 +++++- src/main/java/roomescape/jwt/JwtUtil.java | 13 ++++++++++++- src/main/java/roomescape/member/MemberService.java | 6 ++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/roomescape/jwt/JwtProvider.java b/src/main/java/roomescape/jwt/JwtProvider.java index e6efbff6..a597fcd6 100644 --- a/src/main/java/roomescape/jwt/JwtProvider.java +++ b/src/main/java/roomescape/jwt/JwtProvider.java @@ -1,5 +1,6 @@ package roomescape.jwt; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import io.jsonwebtoken.Jwts; @@ -9,7 +10,8 @@ @Component public class JwtProvider { - private String secretKey = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E="; + @Value("${roomescape.auth.jwt.secret}") + private String secretKey; public String createToken(Member member) { return Jwts.builder() @@ -20,3 +22,5 @@ public String createToken(Member member) { .compact(); } } + + diff --git a/src/main/java/roomescape/jwt/JwtUtil.java b/src/main/java/roomescape/jwt/JwtUtil.java index cfdbdf39..5c7fa502 100644 --- a/src/main/java/roomescape/jwt/JwtUtil.java +++ b/src/main/java/roomescape/jwt/JwtUtil.java @@ -1,11 +1,22 @@ package roomescape.jwt; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import jakarta.servlet.http.Cookie; +@Component public class JwtUtil { + private static String secretKey; + + @Value("${roomescape.auth.jwt.secret}") + public void setSecretKey(String secretKey) { + JwtUtil.secretKey = secretKey; + } + public static String extractTokenFromCookie(Cookie[] cookies) { for (Cookie cookie : cookies) { if (cookie.getName().equals("token")) { @@ -17,7 +28,7 @@ public static String extractTokenFromCookie(Cookie[] cookies) { public static Long getIdFromToken(String token) { return Long.valueOf(Jwts.parserBuilder() - .setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes())) + .setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes())) .build() .parseClaimsJws(token) .getBody().getSubject()); diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 60d4acd3..ee9162b8 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -1,5 +1,6 @@ package roomescape.member; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import roomescape.jwt.JwtProvider; @@ -10,9 +11,10 @@ public class MemberService { private MemberDao memberDao; private JwtProvider jwtProvider; - public MemberService(MemberDao memberDao) { + @Autowired + public MemberService(MemberDao memberDao, JwtProvider jwtProvider) { this.memberDao = memberDao; - this.jwtProvider = new JwtProvider(); + this.jwtProvider = jwtProvider; } public String login(MemberLoginRequest request) { From 36c3bcb9f2d508d2f4795173cdfaf31ffb707e0c Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 04:31:07 +0900 Subject: [PATCH 11/26] =?UTF-8?q?chore:=20[1=EB=8B=A8=EA=B3=84]=20JPA=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8d52aebc..9bc129a0 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' From a8ac74fb59dbef0ee5716ca65593e5710abb078e Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 04:31:07 +0900 Subject: [PATCH 12/26] =?UTF-8?q?chore:=20[4=EB=8B=A8=EA=B3=84]=20JPA=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8d52aebc..9bc129a0 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' From d261be0e879240ec7c7d510ec2adb4c5f473f8ee Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 04:41:58 +0900 Subject: [PATCH 13/26] =?UTF-8?q?chore:=20[4=EB=8B=A8=EA=B3=84]=20JPA=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=84=A4=EC=A0=95?= 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 f4c9d071..26e36658 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,7 +3,7 @@ spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.datasource.url=jdbc:h2:mem:database roomescape.auth.jwt.secret=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= -#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 From 61e7358900989be37cf6082254f47e75dbfba99a Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 04:46:13 +0900 Subject: [PATCH 14/26] =?UTF-8?q?feat:=20[4=EB=8B=A8=EA=B3=84]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A0=81=EC=9A=A9=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/JpaMissionStepTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/test/java/roomescape/JpaMissionStepTest.java diff --git a/src/test/java/roomescape/JpaMissionStepTest.java b/src/test/java/roomescape/JpaMissionStepTest.java new file mode 100644 index 00000000..70ada05e --- /dev/null +++ b/src/test/java/roomescape/JpaMissionStepTest.java @@ -0,0 +1,37 @@ +package roomescape; + +import static org.assertj.core.api.FactoryBasedNavigableListAssert.*; + +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 org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; + +import roomescape.time.Time; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@TestPropertySource(locations = "classpath:application.properties") + +@DataJpaTest +public class JpaMissionStepTest { + @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()); + } +} From 4716b9d9deb0000f8d79193397f4325cf2e79f55 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 04:49:50 +0900 Subject: [PATCH 15/26] =?UTF-8?q?feat:=20[4=EB=8B=A8=EA=B3=84]=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EB=A7=A4=ED=95=91=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/theme/Theme.java | 67 +++++++++++++---------- src/main/java/roomescape/time/Time.java | 43 +++++++++------ 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/src/main/java/roomescape/theme/Theme.java b/src/main/java/roomescape/theme/Theme.java index 430a6239..80c0048d 100644 --- a/src/main/java/roomescape/theme/Theme.java +++ b/src/main/java/roomescape/theme/Theme.java @@ -1,33 +1,42 @@ package roomescape.theme; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity public class Theme { - private Long id; - private String name; - private String description; - - public Theme() { - } - - public Theme(Long id, String name, String description) { - this.id = id; - this.name = name; - this.description = description; - } - - public Theme(String name, String description) { - this.name = name; - this.description = description; - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + private String description; + + public Theme() { + } + + public Theme(Long id, String name, String description) { + this.id = id; + this.name = name; + this.description = description; + } + + public Theme(String name, String description) { + this.name = name; + this.description = description; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } } diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java index 008ed93c..e3b8ad2e 100644 --- a/src/main/java/roomescape/time/Time.java +++ b/src/main/java/roomescape/time/Time.java @@ -1,27 +1,36 @@ package roomescape.time; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity public class Time { - private Long id; - private String value; - public Time(Long id, String value) { - this.id = id; - this.value = value; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String value; + + public Time(Long id, String value) { + this.id = id; + this.value = value; + } - public Time(String value) { - this.value = value; - } + public Time(String value) { + this.value = value; + } - public Time() { + public Time() { - } + } - public Long getId() { - return id; - } + public Long getId() { + return id; + } - public String getValue() { - return value; - } + public String getValue() { + return value; + } } From 047c001089196e608bcf45e72f95a7d2f242aab7 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 05:37:56 +0900 Subject: [PATCH 16/26] =?UTF-8?q?feat:=20[4=EB=8B=A8=EA=B3=84]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=ED=95=98=EA=B8=B0?= 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/TimeRepository.java | 8 ++++++++ src/main/resources/application.properties | 2 +- src/main/resources/schema.sql | 10 +++++----- .../{JpaMissionStepTest.java => JpaTest.java} | 13 ++++--------- 5 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 src/main/java/roomescape/time/TimeRepository.java rename src/test/java/roomescape/{JpaMissionStepTest.java => JpaTest.java} (57%) diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java index e3b8ad2e..9254f840 100644 --- a/src/main/java/roomescape/time/Time.java +++ b/src/main/java/roomescape/time/Time.java @@ -1,5 +1,6 @@ package roomescape.time; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -11,6 +12,8 @@ public class Time { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + + @Column(name = "time_value") private String value; public Time(Long id, String value) { @@ -23,7 +26,6 @@ public Time(String value) { } public Time() { - } public Long getId() { @@ -33,4 +35,8 @@ public Long getId() { public String getValue() { return value; } + + public String getTime() { + return value; + } } diff --git a/src/main/java/roomescape/time/TimeRepository.java b/src/main/java/roomescape/time/TimeRepository.java new file mode 100644 index 00000000..99ec06ee --- /dev/null +++ b/src/main/java/roomescape/time/TimeRepository.java @@ -0,0 +1,8 @@ +package roomescape.time; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface TimeRepository extends CrudRepository { +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 26e36658..9eefccb4 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,5 +5,5 @@ spring.datasource.url=jdbc:h2:mem:database roomescape.auth.jwt.secret=Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true -spring.jpa.ddl-auto=create-drop +spring.jpa.ddl-auto=none spring.jpa.defer-datasource-initialization=true diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 75c947a5..f4dec86f 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,4 +1,4 @@ -CREATE TABLE time +CREATE TABLE IF NOT EXISTS time ( id BIGINT NOT NULL AUTO_INCREMENT, time_value VARCHAR(20) NOT NULL, @@ -6,7 +6,7 @@ CREATE TABLE time PRIMARY KEY (id) ); -CREATE TABLE theme +CREATE TABLE IF NOT EXISTS theme ( id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, @@ -15,7 +15,7 @@ CREATE TABLE theme PRIMARY KEY (id) ); -CREATE TABLE member +CREATE TABLE IF NOT EXISTS member ( id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, @@ -25,7 +25,7 @@ CREATE TABLE member PRIMARY KEY (id) ); -CREATE TABLE reservation +CREATE TABLE IF NOT EXISTS reservation ( id BIGINT NOT NULL AUTO_INCREMENT, date VARCHAR(255) NOT NULL, @@ -57,4 +57,4 @@ VALUES ('10: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 + ('어드민', '2024-03-01', 3, 3); diff --git a/src/test/java/roomescape/JpaMissionStepTest.java b/src/test/java/roomescape/JpaTest.java similarity index 57% rename from src/test/java/roomescape/JpaMissionStepTest.java rename to src/test/java/roomescape/JpaTest.java index 70ada05e..ddf342d2 100644 --- a/src/test/java/roomescape/JpaMissionStepTest.java +++ b/src/test/java/roomescape/JpaTest.java @@ -1,23 +1,17 @@ package roomescape; -import static org.assertj.core.api.FactoryBasedNavigableListAssert.*; +import static org.assertj.core.api.Assertions.*; 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 org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestPropertySource; import roomescape.time.Time; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) -@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) -@TestPropertySource(locations = "classpath:application.properties") +import roomescape.time.TimeRepository; @DataJpaTest -public class JpaMissionStepTest { +public class JpaTest { @Autowired private TestEntityManager entityManager; @@ -35,3 +29,4 @@ public class JpaMissionStepTest { assertThat(persistTime.getTime()).isEqualTo(time.getTime()); } } + From 3d5715fc82e70da982edd65fdbc268f3f3171f85 Mon Sep 17 00:00:00 2001 From: mangsuyo Date: Mon, 1 Jul 2024 18:45:12 +0900 Subject: [PATCH 17/26] =?UTF-8?q?feat:=20[5=EB=8B=A8=EA=B3=84]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=A0=81=EC=9A=A9=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/reservation/Reservation.java | 107 +++++++++++------- src/main/java/roomescape/theme/Theme.java | 7 +- src/main/java/roomescape/time/Time.java | 4 +- src/main/java/roomescape/time/TimeDao.java | 63 ++++++----- src/test/java/roomescape/MissionStepTest.java | 14 +++ 5 files changed, 117 insertions(+), 78 deletions(-) diff --git a/src/main/java/roomescape/reservation/Reservation.java b/src/main/java/roomescape/reservation/Reservation.java index 83a7edf1..e8da33d5 100644 --- a/src/main/java/roomescape/reservation/Reservation.java +++ b/src/main/java/roomescape/reservation/Reservation.java @@ -1,51 +1,70 @@ package roomescape.reservation; +import jakarta.persistence.Column; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import roomescape.theme.Theme; import roomescape.time.Time; public class Reservation { - private Long id; - private String name; - private String date; - private Time time; - private Theme theme; - - public Reservation(Long id, String name, String date, Time time, Theme theme) { - this.id = id; - this.name = name; - this.date = date; - this.time = time; - this.theme = theme; - } - - public Reservation(String name, String date, Time time, Theme theme) { - this.name = name; - this.date = date; - this.time = time; - this.theme = theme; - } - - public Reservation() { - - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getDate() { - return date; - } - - public Time getTime() { - return time; - } - - public Theme getTheme() { - return theme; - } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String name; + + @Column(nullable = false) + private String date; + + @ManyToOne + @JoinColumn(name = "time_id") + private Time time; + + @ManyToOne + @JoinColumn(name = "theme_id") + private Theme theme; + + public Reservation(Long id, String name, String date, Time time, Theme theme) { + this.id = id; + this.name = name; + this.date = date; + this.time = time; + this.theme = theme; + } + + public Reservation(String name, String date, Time time, Theme theme) { + this.name = name; + this.date = date; + this.time = time; + this.theme = theme; + } + + public Reservation() { + + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getDate() { + return date; + } + + public Time getTime() { + return time; + } + + public Theme getTheme() { + return theme; + } } diff --git a/src/main/java/roomescape/theme/Theme.java b/src/main/java/roomescape/theme/Theme.java index 80c0048d..54a911e5 100644 --- a/src/main/java/roomescape/theme/Theme.java +++ b/src/main/java/roomescape/theme/Theme.java @@ -1,5 +1,6 @@ package roomescape.theme; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -11,9 +12,13 @@ public class Theme { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + + @Column(nullable = false) private String name; - private String description; + @Column(nullable = false) + private String description; + public Theme() { } diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java index 9254f840..a4ca4261 100644 --- a/src/main/java/roomescape/time/Time.java +++ b/src/main/java/roomescape/time/Time.java @@ -13,9 +13,9 @@ public class Time { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "time_value") + @Column(name = "time_value", nullable = false, length = 20) private String value; - + public Time(Long id, String value) { this.id = id; this.value = value; diff --git a/src/main/java/roomescape/time/TimeDao.java b/src/main/java/roomescape/time/TimeDao.java index f39a9a32..1bf11b07 100644 --- a/src/main/java/roomescape/time/TimeDao.java +++ b/src/main/java/roomescape/time/TimeDao.java @@ -1,41 +1,42 @@ package roomescape.time; +import java.sql.PreparedStatement; +import java.util.List; + 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