diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..1503e9a Binary files /dev/null and b/.DS_Store differ diff --git a/build.gradle b/build.gradle index 7025e84..3621650 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web:3.4.4' implementation 'org.springframework.boot:spring-boot-starter-jdbc:3.4.4' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.4.4' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.5.1' @@ -33,6 +34,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test:3.4.4' testImplementation 'io.rest-assured:rest-assured:5.5.1' + } tasks.named('test') { diff --git "a/java-sprout \353\263\265\354\202\254\353\263\270" "b/java-sprout \353\263\265\354\202\254\353\263\270" new file mode 160000 index 0000000..bfab660 --- /dev/null +++ "b/java-sprout \353\263\265\354\202\254\353\263\270" @@ -0,0 +1 @@ +Subproject commit bfab6605327a6200b60b58f489adf0a32a802232 diff --git a/src/main/java/com/yourssu/roomescape/RoomescapeApplication.java b/src/main/java/com/yourssu/roomescape/RoomescapeApplication.java index 7b2ab6d..06c7a27 100644 --- a/src/main/java/com/yourssu/roomescape/RoomescapeApplication.java +++ b/src/main/java/com/yourssu/roomescape/RoomescapeApplication.java @@ -8,4 +8,4 @@ public class RoomescapeApplication { public static void main(String[] args) { SpringApplication.run(RoomescapeApplication.class, args); } -} +} \ No newline at end of file diff --git a/src/main/java/com/yourssu/roomescape/WebConfig.java b/src/main/java/com/yourssu/roomescape/WebConfig.java new file mode 100644 index 0000000..eaa6d46 --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/WebConfig.java @@ -0,0 +1,23 @@ +package com.yourssu.roomescape; + +import com.yourssu.roomescape.member.LoginMemberArgumentResolver; +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 { + + private final LoginMemberArgumentResolver loginMemberArgumentResolver; + + public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver) { + this.loginMemberArgumentResolver = loginMemberArgumentResolver; + } + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(loginMemberArgumentResolver); + } +} diff --git a/src/main/java/com/yourssu/roomescape/member/LoginCheckResponse.java b/src/main/java/com/yourssu/roomescape/member/LoginCheckResponse.java new file mode 100644 index 0000000..2730d4d --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/LoginCheckResponse.java @@ -0,0 +1,18 @@ +package com.yourssu.roomescape.member; + +public class LoginCheckResponse { + + private String name; + + public LoginCheckResponse(String memberName) { + this.name = memberName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/yourssu/roomescape/member/LoginMember.java b/src/main/java/com/yourssu/roomescape/member/LoginMember.java new file mode 100644 index 0000000..9321c6e --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/LoginMember.java @@ -0,0 +1,8 @@ +package com.yourssu.roomescape.member; + +import java.lang.annotation.*; + +@Target(ElementType.PARAMETER) // 파라미터에 붙일 수 있음 +@Retention(RetentionPolicy.RUNTIME) // 런타임에도 유지되어야 함 +public @interface LoginMember { +} diff --git a/src/main/java/com/yourssu/roomescape/member/LoginMemberArgumentResolver.java b/src/main/java/com/yourssu/roomescape/member/LoginMemberArgumentResolver.java new file mode 100644 index 0000000..770f807 --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/LoginMemberArgumentResolver.java @@ -0,0 +1,38 @@ +package com.yourssu.roomescape.member; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +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; + +@Slf4j +@Component +public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { + private final TokenService tokenService; + private final MemberService memberService; + + public LoginMemberArgumentResolver(TokenService tokenService, MemberService memberService) { + this.tokenService = tokenService; + this.memberService = memberService; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(LoginMember.class) + && parameter.getParameterType().equals(LoginMemberInfo.class); + } + + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory){ + log.info("✅ LoginMemberArgumentResolver is called!"); + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + Long memberId = tokenService.getMemberIdFromRequest(request); + Member member = memberService.findByMemberId(memberId); + return new LoginMemberInfo(member.getId(), member.getName(), member.getEmail(), member.getRole()); + } +} diff --git a/src/main/java/com/yourssu/roomescape/member/LoginMemberInfo.java b/src/main/java/com/yourssu/roomescape/member/LoginMemberInfo.java new file mode 100644 index 0000000..519073c --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/LoginMemberInfo.java @@ -0,0 +1,33 @@ +package com.yourssu.roomescape.member; + +public class LoginMemberInfo { + + private Long id; + private String name; + private String email; + private String role; + + public LoginMemberInfo(Long id, String name, String email, String role) { + this.id = id; + this.name = name; + this.email = email; + this.role = role; + } + + // Getter만 필요하면 이 정도면 충분해 + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getRole() { + return role; + } +} diff --git a/src/main/java/com/yourssu/roomescape/member/MemberController.java b/src/main/java/com/yourssu/roomescape/member/MemberController.java index f90da55..b72c3b1 100644 --- a/src/main/java/com/yourssu/roomescape/member/MemberController.java +++ b/src/main/java/com/yourssu/roomescape/member/MemberController.java @@ -1,8 +1,16 @@ package com.yourssu.roomescape.member; +import com.yourssu.roomescape.reservation.Reservation; +import com.yourssu.roomescape.reservation.ReservationRequest; +import com.yourssu.roomescape.reservation.ReservationResponse; +import com.yourssu.roomescape.reservation.ReservationService; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -12,9 +20,13 @@ @RestController public class MemberController { private MemberService memberService; + private HttpServletResponse response; + private TokenService tokenService; + private ReservationService reservationService; - public MemberController(MemberService memberService) { + public MemberController(MemberService memberService, TokenService tokenService) { this.memberService = memberService; + this.tokenService = tokenService; } @PostMapping("/members") @@ -23,6 +35,24 @@ 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) { + String email = memberRequest.getEmail(); + String password = memberRequest.getPassword(); + MemberResponse member = new MemberResponse(memberService.findByEmailAndPassword(email, password)); + // 토큰 생성부분 + String secretKey = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E="; + String accessToken = Jwts.builder().setSubject(member.getId().toString()).claim("email", member.getEmail()).claim("password", member.getPassword()).signWith(Keys.hmacShaKeyFor(secretKey.getBytes())).compact(); + + // 쿠키 생성부분 + Cookie cookie = new Cookie("token", accessToken); + cookie.setHttpOnly(true); + cookie.setPath("/"); + response.addCookie(cookie); + return ResponseEntity.ok().build(); + } + @PostMapping("/logout") public ResponseEntity logout(HttpServletResponse response) { Cookie cookie = new Cookie("token", ""); @@ -30,6 +60,38 @@ public ResponseEntity logout(HttpServletResponse response) { cookie.setPath("/"); cookie.setMaxAge(0); response.addCookie(cookie); - return ResponseEntity.ok().build(); + + return ResponseEntity.ok("로그인 성공"); + } + + @GetMapping("/login/check") + public ResponseEntity checkLogin(HttpServletRequest request){ + try { + Long memberId = tokenService.getMemberIdFromRequest(request); + Member member = memberService.findByMemberId(memberId); + + MemberResponse memberResponse = new MemberResponse( + member.getId(), + member.getName(), + member.getEmail(), + member.getRole() + ); + return ResponseEntity.ok(memberResponse); + } catch (Exception e) { + return ResponseEntity.status(401).build(); + } } -} + +// @PostMapping("/reservations") +// public ResponseEntity create(@RequestBody ReservationRequest request, @LoginMember LoginMemberInfo loginMember){ +// Member member; +// if(request.getName() != null && !request.getName().isBlank()){ +// member = memberService.findByName(request.getName()); +// } else { +// member = memberService.findByMemberId(loginMember.getId()); +// } +// +// ReservationResponse reservation = reservationService.save(request); +// return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())) +// .body(reservation); +// } diff --git a/src/main/java/com/yourssu/roomescape/member/MemberDao.java b/src/main/java/com/yourssu/roomescape/member/MemberDao.java index 7923c15..c3cb05e 100644 --- a/src/main/java/com/yourssu/roomescape/member/MemberDao.java +++ b/src/main/java/com/yourssu/roomescape/member/MemberDao.java @@ -52,4 +52,89 @@ public Member findByName(String name) { name ); } + + public Member findByMemberId(Long memberId){ + 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") + ), + memberId + ); + } +} + + + + moru +package com.yourssu.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 findByEmail(String email) { + return jdbcTemplate.queryForObject( + "SELECT id, name, email, role FROM member WHERE email = ?", + (rs, rowNum) -> new Member( + rs.getLong("id"), + rs.getString("name"), + rs.getString("email"), + rs.getString("role") + ), + email + ); + } } diff --git a/src/main/java/com/yourssu/roomescape/member/MemberRepository.java b/src/main/java/com/yourssu/roomescape/member/MemberRepository.java new file mode 100644 index 0000000..83ddb0f --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/MemberRepository.java @@ -0,0 +1,11 @@ +package com.yourssu.roomescape.member; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { + Member findByEmailAndPassword(String email, String password); + + Member findByName(String name); + + Member findByEmail(String email); +} diff --git a/src/main/java/com/yourssu/roomescape/member/MemberRequest.java b/src/main/java/com/yourssu/roomescape/member/MemberRequest.java index 7ee60b6..459a675 100644 --- a/src/main/java/com/yourssu/roomescape/member/MemberRequest.java +++ b/src/main/java/com/yourssu/roomescape/member/MemberRequest.java @@ -1,9 +1,53 @@ +//package com.yourssu.roomescape.member; +// +//import com.fasterxml.jackson.annotation.JsonProperty; +// +//// 클래스 +//public class MemberRequest { +// private String name; +// private String email; +// private String password; +// +// // 생성자 +// public MemberRequest(){} +// +// // 메서드 +// public String getName() { +// return name; +// } +// +// public String getEmail() { +// return email; +// } +// +// public String getPassword() { +// return password; +// } +// +// public void setName(String name) { +// this.name = name; +// } +//} + package com.yourssu.roomescape.member; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + public class MemberRequest { - private String name; - private String email; - private String password; + private final String name; + private final String email; + private final String password; + + @JsonCreator + public MemberRequest( + @JsonProperty("name") String name, + @JsonProperty("email") String email, + @JsonProperty("password") String password) { + this.name = name; + this.email = email; + this.password = password; + } public String getName() { return name; diff --git a/src/main/java/com/yourssu/roomescape/member/MemberResponse.java b/src/main/java/com/yourssu/roomescape/member/MemberResponse.java index fe37b56..d34d021 100644 --- a/src/main/java/com/yourssu/roomescape/member/MemberResponse.java +++ b/src/main/java/com/yourssu/roomescape/member/MemberResponse.java @@ -4,11 +4,20 @@ public class MemberResponse { private Long id; private String name; private String email; + private String password; - public MemberResponse(Long id, String name, String email) { + public MemberResponse(Long id, String name, String email, String password) { this.id = id; this.name = name; this.email = email; + this.password = password; + } + + public MemberResponse(Member member) { + this.id = member.getId(); + this.name = member.getName(); + this.password = member.getPassword(); + this.email = member.getEmail(); } public Long getId() { @@ -22,4 +31,8 @@ public String getName() { public String getEmail() { return email; } + + public String getPassword(){ + return password; + } } diff --git a/src/main/java/com/yourssu/roomescape/member/MemberService.java b/src/main/java/com/yourssu/roomescape/member/MemberService.java index ff138c4..6c4f7a4 100644 --- a/src/main/java/com/yourssu/roomescape/member/MemberService.java +++ b/src/main/java/com/yourssu/roomescape/member/MemberService.java @@ -6,12 +6,50 @@ public class MemberService { private MemberDao memberDao; + // 생성자 public MemberService(MemberDao memberDao) { this.memberDao = memberDao; } + public Member findByEmailAndPassword(String email, String password) { + return memberDao.findByEmailAndPassword(email, password); + } + + public String getMemberName(Long memberId){ + Member member = memberDao.findByMemberId(memberId); + return member.getName(); + } + + // MemberService + public MemberResponse findMemberById(Long memberId) { + Member member = memberDao.findByMemberId(memberId); + return new MemberResponse( + member.getId(), + member.getName(), + member.getEmail(), + member.getRole() + ); + } + + public Member findByName(String name) { + return memberDao.findByName(name); // DB에서 조회 + } + + 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()); + return new MemberResponse(member.getId(), member.getName(), member.getEmail(), member.getPassword()); + } + + public MemberResponse login(MemberRequest memberRequest) { + Member member = memberDao.findByEmailAndPassword(memberRequest.getEmail(), memberRequest.getPassword()); + if (member.getId() == null) { + throw new IllegalArgumentException("회원 ID가 존재하지 않습니다."); + } + return new MemberResponse(member); + } + + public Member findByMemberId(Long memberId) { + return memberDao.findByMemberId(memberId); } -} +} \ No newline at end of file diff --git a/src/main/java/com/yourssu/roomescape/member/ReservationRequest.java b/src/main/java/com/yourssu/roomescape/member/ReservationRequest.java new file mode 100644 index 0000000..751c349 --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/ReservationRequest.java @@ -0,0 +1,40 @@ +package com.yourssu.roomescape.member; + +public class ReservationRequest { + private String date; + private String time; + private String theme; + private String name; // + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getTheme() { + return theme; + } + + public void setTheme(String theme) { + this.theme = theme; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/yourssu/roomescape/member/TokenService.java b/src/main/java/com/yourssu/roomescape/member/TokenService.java new file mode 100644 index 0000000..7772174 --- /dev/null +++ b/src/main/java/com/yourssu/roomescape/member/TokenService.java @@ -0,0 +1,63 @@ +package com.yourssu.roomescape.member; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Service; + +@Service +public class TokenService { + private final String secretKey = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E="; + + // 쿠키 배열에서 토큰 추출하는 메서드 (내부용) + String extractTokenFromCookie(Cookie[] cookies) { + if (cookies == null || cookies.length == 0) { + throw new TokenNotFoundException(); + } + for (Cookie cookie : cookies) { + if ("token".equals(cookie.getName())) { + return cookie.getValue(); + } + } + throw new TokenNotFoundException(); + } + + private static class TokenNotFoundException extends RuntimeException { + public TokenNotFoundException() { + super("쿠키에서 토큰을 찾을 수 없습니다."); + } + } + + // 전달된 토큰을 파싱해서 JWT subject 값을 Long 타입의 memberId로 변환하는 메서드 + public Long getMemberIdFromToken(String token) { + return Long.valueOf( + Jwts.parser() + .setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes())) + .build() + .parseClaimsJws(token) + .getBody() + .getSubject() + ); + } + + // HttpServletRequest에서 쿠키를 추출하여 토큰 파싱까지 한 번에 처리하는 편리한 메서드 + public Long getMemberIdFromRequest(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + String token = extractTokenFromCookie(cookies); + if (token == null) { + return null; + } + return getMemberIdFromToken(token); + } + +// public String createToken(String email, String password) { +// +// return Jwts.builder() +// .setSubject(email) +// .claim("password", password) +// .signWith(Keys.hmacShaKeyFor(secretKey.getBytes())) +// .compact(); +// } + +} \ No newline at end of file diff --git a/src/main/java/com/yourssu/roomescape/reservation/Reservation.java b/src/main/java/com/yourssu/roomescape/reservation/Reservation.java index 66a0376..16372a2 100644 --- a/src/main/java/com/yourssu/roomescape/reservation/Reservation.java +++ b/src/main/java/com/yourssu/roomescape/reservation/Reservation.java @@ -18,8 +18,14 @@ public Reservation(Long id, String name, String date, Time time, Theme theme) { this.theme = theme; } - public Reservation(String name, String date, Time time, Theme theme) { + public Reservation(String name, String date, Theme theme, Time time) { this.name = name; + this.date = date; + this.theme = theme; + this.time = time; + } + + public Reservation(String date, Time time, Theme theme) { this.date = date; this.time = time; this.theme = theme; diff --git a/src/main/java/com/yourssu/roomescape/reservation/ReservationController.java b/src/main/java/com/yourssu/roomescape/reservation/ReservationController.java index 77f108d..9fff2b5 100644 --- a/src/main/java/com/yourssu/roomescape/reservation/ReservationController.java +++ b/src/main/java/com/yourssu/roomescape/reservation/ReservationController.java @@ -1,18 +1,24 @@ package com.yourssu.roomescape.reservation; +import com.yourssu.roomescape.member.LoginMember; +import com.yourssu.roomescape.member.LoginMemberInfo; +import com.yourssu.roomescape.member.Member; +import com.yourssu.roomescape.member.MemberService; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.net.URI; import java.util.List; +@Slf4j @RestController public class ReservationController { private final ReservationService reservationService; public ReservationController(ReservationService reservationService) { - this.reservationService = reservationService; + this .reservationService = reservationService; } @GetMapping("/reservations") @@ -21,14 +27,14 @@ 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 LoginMemberInfo loginMember) { + log.info("예약 요청 - 로그인한 회원 정보: ID = {}, 이름 = {}", loginMember.getId(), loginMember.getName()); + if (reservationRequest.getDate() == null || reservationRequest.getTheme() == null || reservationRequest.getTime() == null) { return ResponseEntity.badRequest().build(); } - ReservationResponse reservation = reservationService.save(reservationRequest); + ReservationResponse reservation = reservationService.save(reservationRequest, loginMember); return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())).body(reservation); } @@ -38,4 +44,4 @@ public ResponseEntity delete(@PathVariable Long id) { reservationService.deleteById(id); return ResponseEntity.noContent().build(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/yourssu/roomescape/reservation/ReservationDao.java b/src/main/java/com/yourssu/roomescape/reservation/ReservationDao.java index 5b643bb..da23e43 100644 --- a/src/main/java/com/yourssu/roomescape/reservation/ReservationDao.java +++ b/src/main/java/com/yourssu/roomescape/reservation/ReservationDao.java @@ -1,5 +1,7 @@ package com.yourssu.roomescape.reservation; +import com.yourssu.roomescape.member.Member; +import com.yourssu.roomescape.member.MemberDao; import com.yourssu.roomescape.theme.Theme; import com.yourssu.roomescape.time.Time; import org.springframework.jdbc.core.JdbcTemplate; @@ -43,8 +45,14 @@ public List findAll() { ))); } - public Reservation save(ReservationRequest reservationRequest) { + public Reservation save(ReservationRequest reservationRequest, Member member) { KeyHolder keyHolder = new GeneratedKeyHolder(); + String name; + if (reservationRequest.getName() == null) { + name = member.getName(); + } else { + name = reservationRequest.getName(); + } 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()); @@ -124,4 +132,75 @@ public List findByDateAndThemeId(String date, Long themeId) { rs.getString("theme_description") ))); } + public Theme findThemeById(Long themeId) { + return jdbcTemplate.queryForObject( + "SELECT * FROM theme WHERE id = ?", + (rs, rowNum) -> new Theme( + rs.getLong("id"), + rs.getString("name"), + rs.getString("description") + ), + themeId + ); + } + + public Time findTimeById(Long timeId) { + return jdbcTemplate.queryForObject( + "SELECT * FROM time WHERE id = ?", + (rs, rowNum) -> new Time( + rs.getLong("id"), + rs.getString("time_value") + ), + timeId + ); + } + public Member findMemberByName(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 findMemberById(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 + ); + } + + public Reservation save(Reservation reservation) { + 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, reservation.getDate()); + ps.setString(2, reservation.getName()); + ps.setLong(3, reservation.getTheme().getId()); + ps.setLong(4, reservation.getTime().getId()); + return ps; + }, keyHolder); + + return new Reservation( + keyHolder.getKey().longValue(), + reservation.getName(), + reservation.getDate(), + reservation.getTime(), + reservation.getTheme() + ); + } + } + diff --git a/src/main/java/com/yourssu/roomescape/reservation/ReservationRequest.java b/src/main/java/com/yourssu/roomescape/reservation/ReservationRequest.java index b413312..760d3da 100644 --- a/src/main/java/com/yourssu/roomescape/reservation/ReservationRequest.java +++ b/src/main/java/com/yourssu/roomescape/reservation/ReservationRequest.java @@ -21,4 +21,20 @@ public Long getTheme() { public Long getTime() { return time; } + + public void setName(String name) { + this.name = name; + } + + public void setDate(String date) { + this.date = date; + } + + public void setTheme(Long theme) { + this.theme = theme; + } + + public void setTime(Long time) { + this.time = time; + } } diff --git a/src/main/java/com/yourssu/roomescape/reservation/ReservationService.java b/src/main/java/com/yourssu/roomescape/reservation/ReservationService.java index 1dab4f6..44c6546 100644 --- a/src/main/java/com/yourssu/roomescape/reservation/ReservationService.java +++ b/src/main/java/com/yourssu/roomescape/reservation/ReservationService.java @@ -1,30 +1,68 @@ package com.yourssu.roomescape.reservation; +import com.yourssu.roomescape.member.LoginMemberInfo; +import com.yourssu.roomescape.member.Member; +import com.yourssu.roomescape.member.MemberDao; +import com.yourssu.roomescape.theme.Theme; +import com.yourssu.roomescape.time.Time; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; +@Slf4j @Service public class ReservationService { - private ReservationDao reservationDao; + private final MemberDao memberDao; + public ReservationDao reservationDao; - public ReservationService(ReservationDao reservationDao) { + public ReservationService(ReservationDao reservationDao, MemberDao memberDao) { this.reservationDao = reservationDao; + this.memberDao = memberDao; } - public ReservationResponse save(ReservationRequest reservationRequest) { - Reservation reservation = reservationDao.save(reservationRequest); + public ReservationResponse save(ReservationRequest request, LoginMemberInfo loginMember) { + Member member; - return new ReservationResponse(reservation.getId(), reservationRequest.getName(), reservation.getTheme().getName(), reservation.getDate(), reservation.getTime().getValue()); + if (request.getName() != null && !request.getName().isBlank()) { + // name으로 회원 조회 + member = reservationDao.findMemberByName(request.getName()); + } else { + // 로그인된 회원 정보로 조회 + log.info("로그인된 회원 정보로 예약 진행 - 회원 ID: {}", loginMember.getId()); + member = reservationDao.findMemberById(loginMember.getId()); + } + + Theme theme = reservationDao.findThemeById(request.getTheme()); + Time time = reservationDao.findTimeById(request.getTime()); + + Reservation reservation = new Reservation(member.getName(), request.getDate(), theme, time); + Reservation saved = reservationDao.save(reservation); + + return new ReservationResponse( + saved.getId(), + saved.getName(), + saved.getTheme().getName(), + saved.getDate(), + saved.getTime().getValue() + ); } public void deleteById(Long id) { reservationDao.deleteById(id); } + public Time getTimeById(Long id) { + return reservationDao.findTimeById(id); + } + + public Theme getThemeById(Long id) { + return reservationDao.findThemeById(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(); } -} +} \ No newline at end of file diff --git a/src/test/java/com/yourssu/roomescape/MissionStepTest.java b/src/test/java/com/yourssu/roomescape/MissionStepTest.java index 085d0d6..581ed53 100644 --- a/src/test/java/com/yourssu/roomescape/MissionStepTest.java +++ b/src/test/java/com/yourssu/roomescape/MissionStepTest.java @@ -1,5 +1,6 @@ package com.yourssu.roomescape; +import com.yourssu.roomescape.reservation.ReservationResponse; import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.response.ExtractableResponse; @@ -22,6 +23,8 @@ public class MissionStepTest { Map params = new HashMap<>(); params.put("email", "admin@email.com"); params.put("password", "password"); + params.put("name", "관리자"); + ExtractableResponse response = RestAssured.given().log().all() .contentType(ContentType.JSON) @@ -34,5 +37,68 @@ public class MissionStepTest { String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1]; assertThat(token).isNotBlank(); + + // 로그인체크 api 호출 + 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("브라운"); + } + + public 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]; } + }