diff --git a/README.md b/README.md
new file mode 100644
index 00000000..0527c82f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# Spring Core (배포)
+
+
7단계 - @Configuration
+
+- [x] JWT 관련 로직을 roomescape와 같은 계층의 auth 패키지의 클래스로 분리
+- [x] 불필요한 DB 접근 최소화
+ - JWT 토큰에는 사용자 식별 정보와 권한 정보가 들어갑니다.
+ 만약 이 두 정보만 필요하다면 DB 접근이 필요하지 않습니다.
+
+
+
8단계 - Profile과 Resource
+
+schema.sql 대신 데이터베이스를 초기화 클래스 생성
+- [x] Production용도 DataLoader 생성
+ 사용자 정보만 초기화
+- [x] Test용도 TestDataLoader생성
+ 테스트에 필요한 사전 값 초기화
+- [x] Environemt 분리 (토큰 비밀키)
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 8d52aebc..87e93013 100644
--- a/build.gradle
+++ b/build.gradle
@@ -15,9 +15,8 @@ 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 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.0.0'
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa' //jpa변경
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.2'
@@ -29,6 +28,7 @@ dependencies {
runtimeOnly 'com.h2database:h2'
}
+
test {
useJUnitPlatform()
-}
+}
\ No newline at end of file
diff --git a/src/main/java/auth/AuthConfig.java b/src/main/java/auth/AuthConfig.java
new file mode 100644
index 00000000..da937124
--- /dev/null
+++ b/src/main/java/auth/AuthConfig.java
@@ -0,0 +1,12 @@
+package auth;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AuthConfig {
+ @Bean
+ public JwtTokenProvider jwtTokenProvider() {
+ return new JwtTokenProvider();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/auth/JwtTokenProvider.java b/src/main/java/auth/JwtTokenProvider.java
new file mode 100644
index 00000000..a1e9bb6c
--- /dev/null
+++ b/src/main/java/auth/JwtTokenProvider.java
@@ -0,0 +1,41 @@
+package auth;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.Keys;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import roomescape.member.MemberResponse;
+
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+
+public class JwtTokenProvider {
+ @Value("${roomescape.auth.jwt.secret}")
+ private String secretKey;
+
+ @Bean
+ public SecretKey secretKey() {
+ return Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public String createToken(MemberResponse member) {
+ String accessToken = Jwts.builder()
+ .setSubject(member.getId().toString())
+ .claim("name", member.getName())
+ .claim("email", member.getEmail())
+ .signWith(secretKey())
+ .compact();
+
+ return accessToken;
+ }
+
+ public Long extractMemberIdFromToken(String token) {
+ Claims claims = Jwts.parserBuilder()
+ .setSigningKey(secretKey())
+ .build()
+ .parseClaimsJws(token)
+ .getBody();
+ return Long.valueOf(claims.getSubject());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/DataLoader.java b/src/main/java/roomescape/DataLoader.java
new file mode 100644
index 00000000..6d7d0c01
--- /dev/null
+++ b/src/main/java/roomescape/DataLoader.java
@@ -0,0 +1,23 @@
+package roomescape;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import roomescape.member.Member;
+import roomescape.member.MemberRepository;
+
+
+@Component
+@Profile("Production")
+public class DataLoader implements CommandLineRunner {
+ private final MemberRepository memberRepository;
+
+ public DataLoader(MemberRepository memberRepository) {
+ this.memberRepository = memberRepository;
+ }
+ @Override
+ public void run(final String... args) throws Exception {
+ final Member member1 = memberRepository.save(new Member("어드민", "admin@email.com", "password", "ADMIN"));
+ final Member member2 = memberRepository.save(new Member("브라운", "brown@email.com", "password", "USER"));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/PageController.java b/src/main/java/roomescape/PageController.java
index ac8ef940..e27ea032 100644
--- a/src/main/java/roomescape/PageController.java
+++ b/src/main/java/roomescape/PageController.java
@@ -44,4 +44,4 @@ public String login() {
public String signup() {
return "signup";
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/RoomescapeApplication.java b/src/main/java/roomescape/RoomescapeApplication.java
index 2ca0f743..51f1fbdb 100644
--- a/src/main/java/roomescape/RoomescapeApplication.java
+++ b/src/main/java/roomescape/RoomescapeApplication.java
@@ -1,11 +1,14 @@
package roomescape;
+import auth.AuthConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Import;
+@Import(AuthConfig.class)
@SpringBootApplication
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/roomescape/TestDataLoader.java b/src/main/java/roomescape/TestDataLoader.java
new file mode 100644
index 00000000..2b89b9ff
--- /dev/null
+++ b/src/main/java/roomescape/TestDataLoader.java
@@ -0,0 +1,56 @@
+package roomescape;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import roomescape.member.Member;
+import roomescape.member.MemberRepository;
+import roomescape.reservation.Reservation;
+import roomescape.reservation.ReservationRepository;
+import roomescape.theme.Theme;
+import roomescape.theme.ThemeRepository;
+import roomescape.time.Time;
+import roomescape.time.TimeRepository;
+
+@Profile("test")
+@Component
+public class TestDataLoader implements CommandLineRunner {
+ private final MemberRepository memberRepository;
+ private final ThemeRepository themeRepository;
+ private final TimeRepository timeRepository;
+ private final ReservationRepository reservationRepository;
+
+ @Autowired
+ public TestDataLoader(final MemberRepository memberRepository,
+ final ThemeRepository themeRepository,
+ final TimeRepository timeRepository,
+ final ReservationRepository reservationRepository) {
+ this.memberRepository = memberRepository;
+ this.themeRepository = themeRepository;
+ this.timeRepository = timeRepository;
+ this.reservationRepository = reservationRepository;
+ }
+
+ @Override
+ public void run(final String... args) throws Exception {
+ final Member member1 = memberRepository.save(new Member("어드민", "admin@email.com", "password", "ADMIN"));
+ final Member member2 = memberRepository.save(new Member("브라운", "brown@email.com", "password", "USER"));
+
+ final Theme theme1 = themeRepository.save(new Theme("테마1", "테마1입니다."));
+ final Theme theme2 = themeRepository.save(new Theme("테마2", "테마2입니다."));
+ final Theme theme3 = themeRepository.save(new Theme("테마3", "테마3입니다."));
+
+ final Time time1 = timeRepository.save(new Time("10:00"));
+ final Time time2 = timeRepository.save(new Time("12:00"));
+ final Time time3 = timeRepository.save(new Time("14:00"));
+ final Time time4 = timeRepository.save(new Time("16:00"));
+ final Time time5 = timeRepository.save(new Time("18:00"));
+ final Time time6 = timeRepository.save(new Time("20:00"));
+
+ reservationRepository.save(new Reservation("어드민", "2024-03-01", time1, theme1, member1));
+ reservationRepository.save(new Reservation("어드민", "2024-03-01", time2, theme2, member1));
+ reservationRepository.save(new Reservation("어드민", "2024-03-01", time3, theme3, member1));
+ reservationRepository.save(new Reservation("브라운", "2024-03-01", time4, theme1, member2));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/AdminInterceptor.java b/src/main/java/roomescape/member/AdminInterceptor.java
new file mode 100644
index 00000000..3e75303b
--- /dev/null
+++ b/src/main/java/roomescape/member/AdminInterceptor.java
@@ -0,0 +1,26 @@
+package roomescape.member;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+@Component
+public class AdminInterceptor implements HandlerInterceptor {
+
+ @Autowired
+ private MemberService memberService;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ String token = memberService.extractTokenFromCookie(request.getCookies());
+ Member member = memberService.extractMemberFromToken(token);
+
+ if (member == null || !member.getRole().equals("ADMIN")) {
+ response.setStatus(401);
+ return false;
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/LoginMember.java b/src/main/java/roomescape/member/LoginMember.java
new file mode 100644
index 00000000..d5490819
--- /dev/null
+++ b/src/main/java/roomescape/member/LoginMember.java
@@ -0,0 +1,61 @@
+package roomescape.member;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+
+@Entity
+public class LoginMember {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String name;
+ private String email;
+ private String role;
+
+ public LoginMember() {
+
+ }
+
+ public LoginMember(Long id, String name, String email, String role) {
+ this.id = id;
+ this.name = name;
+ this.email = email;
+ this.role = role;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/LoginMemberArgumentResolver.java b/src/main/java/roomescape/member/LoginMemberArgumentResolver.java
new file mode 100644
index 00000000..9c9b1871
--- /dev/null
+++ b/src/main/java/roomescape/member/LoginMemberArgumentResolver.java
@@ -0,0 +1,35 @@
+package roomescape.member;
+
+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;
+
+@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 {
+ String token = webRequest.getHeader("Cookie").split("=")[1];
+
+ Member member = memberService.extractMemberFromToken(token);
+
+ if (member == null) {
+ throw new RuntimeException("인증되지 않은 사용자입니다.");
+ }
+ return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getRole());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/Member.java b/src/main/java/roomescape/member/Member.java
index 903aaa9b..0e27fc65 100644
--- a/src/main/java/roomescape/member/Member.java
+++ b/src/main/java/roomescape/member/Member.java
@@ -1,19 +1,31 @@
package roomescape.member;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+
+@Entity
public class Member {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
+
private String name;
private String email;
private String password;
private String role;
- public Member(Long id, String name, String email, String role) {
+ public Member() {
+ }
+
+ public Member(Long id, String name, String email, String password, String role) {
this.id = id;
this.name = name;
this.email = email;
+ this.password = password;
this.role = role;
}
-
public Member(String name, String email, String password, String role) {
this.name = name;
this.email = email;
@@ -40,4 +52,5 @@ public String getPassword() {
public String getRole() {
return role;
}
-}
+
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java
index 881ae5e0..1de39ca4 100644
--- a/src/main/java/roomescape/member/MemberController.java
+++ b/src/main/java/roomescape/member/MemberController.java
@@ -3,11 +3,9 @@
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.http.HttpStatus;
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 org.springframework.web.bind.annotation.*;
import java.net.URI;
@@ -20,11 +18,34 @@ public MemberController(MemberService memberService) {
}
@PostMapping("/members")
- public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) {
+ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) {
MemberResponse member = memberService.createMember(memberRequest);
return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member);
}
+ @PostMapping("/login")
+ public ResponseEntity login(@RequestBody MemberRequest memberRequest, HttpServletResponse response){
+ MemberResponse member = memberService.findMember(memberRequest.getEmail(), memberRequest.getPassword());
+ if (member == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+ }
+ String token = memberService.createToken(member);
+ memberService.createCookie(response, token);
+
+ return ResponseEntity.status(HttpStatus.OK).build();
+ }
+
+ @GetMapping("/login/check")
+ public ResponseEntity checkLogin(HttpServletRequest request) {
+ Cookie[] cookies = request.getCookies();
+ String token = memberService.extractTokenFromCookie(cookies);
+
+ MemberResponse member = memberService.findMemberById(memberService.extractMemberFromToken(token).getId());
+
+ MemberResponse memberResponse = new MemberResponse(member.getId(), member.getName(), member.getEmail());
+ return ResponseEntity.ok().body(memberResponse);
+ }
+
@PostMapping("/logout")
public ResponseEntity logout(HttpServletResponse response) {
Cookie cookie = new Cookie("token", "");
@@ -34,4 +55,4 @@ public ResponseEntity logout(HttpServletResponse response) {
response.addCookie(cookie);
return ResponseEntity.ok().build();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java
deleted file mode 100644
index 81f77f4c..00000000
--- a/src/main/java/roomescape/member/MemberDao.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package roomescape.member;
-
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public class MemberDao {
- private JdbcTemplate jdbcTemplate;
-
- public MemberDao(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
-
- public Member save(Member member) {
- KeyHolder keyHolder = new GeneratedKeyHolder();
- jdbcTemplate.update(connection -> {
- var ps = connection.prepareStatement("INSERT INTO member(name, email, password, role) VALUES (?, ?, ?, ?)", new String[]{"id"});
- ps.setString(1, member.getName());
- ps.setString(2, member.getEmail());
- ps.setString(3, member.getPassword());
- ps.setString(4, member.getRole());
- return ps;
- }, keyHolder);
-
- return new Member(keyHolder.getKey().longValue(), member.getName(), member.getEmail(), "USER");
- }
-
- public Member findByEmailAndPassword(String email, String password) {
- return jdbcTemplate.queryForObject(
- "SELECT id, name, email, role FROM member WHERE email = ? AND password = ?",
- (rs, rowNum) -> new Member(
- rs.getLong("id"),
- rs.getString("name"),
- rs.getString("email"),
- rs.getString("role")
- ),
- email, password
- );
- }
-
- public Member findByName(String name) {
- return jdbcTemplate.queryForObject(
- "SELECT id, name, email, role FROM member WHERE name = ?",
- (rs, rowNum) -> new Member(
- rs.getLong("id"),
- rs.getString("name"),
- rs.getString("email"),
- rs.getString("role")
- ),
- name
- );
- }
-}
diff --git a/src/main/java/roomescape/member/MemberRepository.java b/src/main/java/roomescape/member/MemberRepository.java
new file mode 100644
index 00000000..ea332bd6
--- /dev/null
+++ b/src/main/java/roomescape/member/MemberRepository.java
@@ -0,0 +1,14 @@
+package roomescape.member;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import roomescape.reservation.Reservation;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface MemberRepository extends JpaRepository {
+ Member findByEmailAndPassword(String email, String password);
+ Optional findByName(String name);
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/MemberResponse.java b/src/main/java/roomescape/member/MemberResponse.java
index b9fa3b97..2de85dfd 100644
--- a/src/main/java/roomescape/member/MemberResponse.java
+++ b/src/main/java/roomescape/member/MemberResponse.java
@@ -22,4 +22,4 @@ public String getName() {
public String getEmail() {
return email;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java
index ccaa8cba..60e8f126 100644
--- a/src/main/java/roomescape/member/MemberService.java
+++ b/src/main/java/roomescape/member/MemberService.java
@@ -1,17 +1,68 @@
package roomescape.member;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import auth.JwtTokenProvider;
+
+import java.util.Optional;
@Service
public class MemberService {
- private MemberDao memberDao;
+ @Autowired
+ private MemberRepository memberRepository;
+ @Autowired
+ private JwtTokenProvider jwtTokenProvider;
- public MemberService(MemberDao memberDao) {
- this.memberDao = memberDao;
+ public MemberService(MemberRepository memberRepository, JwtTokenProvider jwtTokenProvider) {
+ this.memberRepository = memberRepository;
+ this.jwtTokenProvider = jwtTokenProvider;
}
public MemberResponse createMember(MemberRequest memberRequest) {
- Member member = memberDao.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER"));
+ Member member = memberRepository.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER"));
+ return new MemberResponse(member.getId(), member.getName(), member.getEmail());
+ }
+
+ public MemberResponse findMember(String email, String password) {
+ Member member = memberRepository.findByEmailAndPassword(email, password);
return new MemberResponse(member.getId(), member.getName(), member.getEmail());
}
-}
+
+ public MemberResponse findMemberById(Long memberId) {
+ Optional optionalMember = memberRepository.findById(memberId);
+ Member member = optionalMember.orElseThrow(() -> new IllegalArgumentException("Invalid member ID"));
+ return new MemberResponse(member.getId(), member.getName(), member.getEmail());
+ }
+
+ public String createToken(MemberResponse memberResponse) {
+ String accessToken = jwtTokenProvider.createToken(memberResponse);
+ return accessToken;
+ }
+
+ public void createCookie(HttpServletResponse response, String token) {
+ Cookie cookie = new Cookie("token", token);
+ cookie.setHttpOnly(true);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ }
+
+ public Member extractMemberFromToken(String token) {
+ Long memberId = jwtTokenProvider.extractMemberIdFromToken(token);
+ if (memberId != null) {
+ Optional optionalMember = memberRepository.findById(memberId);
+ return optionalMember.orElse(null);
+ }
+ return null;
+ }
+
+ public String extractTokenFromCookie(Cookie[] cookies) {
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals("token")) {
+ return cookie.getValue();
+ }
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/member/WebMvcConfigure.java b/src/main/java/roomescape/member/WebMvcConfigure.java
new file mode 100644
index 00000000..0cb241f5
--- /dev/null
+++ b/src/main/java/roomescape/member/WebMvcConfigure.java
@@ -0,0 +1,35 @@
+package roomescape.member;
+
+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.HandlerInterceptor;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+
+import java.util.List;
+
+@Configuration
+public class WebMvcConfigure implements WebMvcConfigurer {
+ @Autowired
+ private final LoginMemberArgumentResolver loginMemberArgumentResolver;
+ @Autowired
+ private AdminInterceptor adminInterceptor;
+
+ public WebMvcConfigure(LoginMemberArgumentResolver loginMemberArgumentResolver) {
+ this.loginMemberArgumentResolver = loginMemberArgumentResolver;
+ }
+
+ @Override
+ public void addArgumentResolvers(List resolvers) {
+ resolvers.add(loginMemberArgumentResolver);
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(adminInterceptor)
+ .addPathPatterns("/admin/**"); //admin에 적용
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/reservation/MyReservationResponse.java b/src/main/java/roomescape/reservation/MyReservationResponse.java
new file mode 100644
index 00000000..111998a3
--- /dev/null
+++ b/src/main/java/roomescape/reservation/MyReservationResponse.java
@@ -0,0 +1,43 @@
+package roomescape.reservation;
+
+public class MyReservationResponse {
+ private Long reservationId;
+ private String theme;
+ private String date;
+ private String time;
+ private String status;
+ private Long rank;
+
+ public MyReservationResponse(Long reservationId, String theme, String date, String time, String status, Long rank) {
+ this.reservationId = reservationId;
+ this.theme = theme;
+ this.date = date;
+ this.time = time;
+ this.status = status;
+ this.rank = rank;
+ }
+
+ public Long getReservationId() {
+ return reservationId;
+ }
+
+ public String getTheme() {
+ return theme;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public Long getRank() {
+ return rank;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/reservation/Reservation.java b/src/main/java/roomescape/reservation/Reservation.java
index 83a7edf1..e5315166 100644
--- a/src/main/java/roomescape/reservation/Reservation.java
+++ b/src/main/java/roomescape/reservation/Reservation.java
@@ -1,32 +1,44 @@
package roomescape.reservation;
+import jakarta.persistence.*;
+import roomescape.member.Member;
+import roomescape.member.MemberResponse;
import roomescape.theme.Theme;
import roomescape.time.Time;
+@Entity
public class Reservation {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
+
private String name;
private String date;
+
+ @ManyToOne
+ @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;
+ @ManyToOne
+ @JoinColumn(name = "member_id")
+ private Member member;
+
+ public Reservation() {
+ }
+
+ public Reservation(String name, String date, Time time, Theme theme, MemberResponse member) {
}
- public Reservation(String name, String date, Time time, Theme theme) {
+ public Reservation(String name, String date, Time time, Theme theme, Member member) {
this.name = name;
this.date = date;
this.time = time;
this.theme = theme;
- }
-
- public Reservation() {
-
+ this.member = member;
}
public Long getId() {
@@ -48,4 +60,13 @@ public Time getTime() {
public Theme getTheme() {
return theme;
}
-}
+
+ public Member getMember() {
+ return member;
+ }
+
+ public void setMember(Member member) {
+ this.member = member;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java
index b3bef399..b1775ea5 100644
--- a/src/main/java/roomescape/reservation/ReservationController.java
+++ b/src/main/java/roomescape/reservation/ReservationController.java
@@ -1,23 +1,26 @@
package roomescape.reservation;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+import roomescape.member.LoginMember;
+import roomescape.member.MemberRepository;
+import roomescape.waiting.WaitingService;
+import roomescape.waiting.WaitingResponse;
import java.net.URI;
import java.util.List;
+import java.util.stream.Collectors;
@RestController
public class ReservationController {
-
private final ReservationService reservationService;
+ private final WaitingService waitingService;
+ private final MemberRepository memberRepository;
- public ReservationController(ReservationService reservationService) {
+ public ReservationController(MemberRepository memberRepository, ReservationService reservationService, WaitingService waitingService) {
+ this.memberRepository = memberRepository;
this.reservationService = reservationService;
+ this.waitingService = waitingService;
}
@GetMapping("/reservations")
@@ -26,7 +29,12 @@ public List list() {
}
@PostMapping("/reservations")
- public ResponseEntity create(@RequestBody ReservationRequest reservationRequest) {
+ public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, LoginMember loginMember) {
+
+ if (loginMember != null && reservationRequest.getName() == null) { // 멤버가 아닌 경우 (참고)
+ reservationRequest.setName(loginMember.getName());
+ }
+
if (reservationRequest.getName() == null
|| reservationRequest.getDate() == null
|| reservationRequest.getTheme() == null
@@ -39,8 +47,18 @@ public ResponseEntity create(@RequestBody ReservationRequest reservationRequest)
}
@DeleteMapping("/reservations/{id}")
- public ResponseEntity delete(@PathVariable Long id) {
+ public ResponseEntity delete(@PathVariable Long id) {
reservationService.deleteById(id);
return ResponseEntity.noContent().build();
}
-}
+
+ @GetMapping("/reservations-mine")
+ public List mineReservation(LoginMember loginMember) {
+ List reservations = reservationService.findReservation(loginMember);
+ List waitings = waitingService.findWaitingsByMember(loginMember);
+
+ reservations.addAll(waitings);
+ return reservations;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/reservation/ReservationDao.java b/src/main/java/roomescape/reservation/ReservationDao.java
deleted file mode 100644
index a4972430..00000000
--- a/src/main/java/roomescape/reservation/ReservationDao.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package roomescape.reservation;
-
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-import roomescape.theme.Theme;
-import roomescape.time.Time;
-
-import java.sql.PreparedStatement;
-import java.util.List;
-
-@Repository
-public class ReservationDao {
-
- private final JdbcTemplate jdbcTemplate;
-
- public ReservationDao(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
-
- public List findAll() {
- return jdbcTemplate.query(
- "SELECT r.id AS reservation_id, r.name as reservation_name, r.date as reservation_date, " +
- "t.id AS theme_id, t.name AS theme_name, t.description AS theme_description, " +
- "ti.id AS time_id, ti.time_value AS time_value " +
- "FROM reservation r " +
- "JOIN theme t ON r.theme_id = t.id " +
- "JOIN time ti ON r.time_id = ti.id",
-
- (rs, rowNum) -> new Reservation(
- rs.getLong("reservation_id"),
- rs.getString("reservation_name"),
- rs.getString("reservation_date"),
- new Time(
- rs.getLong("time_id"),
- rs.getString("time_value")
- ),
- new Theme(
- rs.getLong("theme_id"),
- rs.getString("theme_name"),
- rs.getString("theme_description")
- )));
- }
-
- public Reservation save(ReservationRequest reservationRequest) {
- KeyHolder keyHolder = new GeneratedKeyHolder();
- jdbcTemplate.update(connection -> {
- PreparedStatement ps = connection.prepareStatement("INSERT INTO reservation(date, name, theme_id, time_id) VALUES (?, ?, ?, ?)", new String[]{"id"});
- ps.setString(1, reservationRequest.getDate());
- ps.setString(2, reservationRequest.getName());
- ps.setLong(3, reservationRequest.getTheme());
- ps.setLong(4, reservationRequest.getTime());
- return ps;
- }, keyHolder);
-
- Time time = jdbcTemplate.queryForObject("SELECT * FROM time WHERE id = ?",
- (rs, rowNum) -> new Time(rs.getLong("id"), rs.getString("time_value")),
- reservationRequest.getTime());
-
- Theme theme = jdbcTemplate.queryForObject("SELECT * FROM theme WHERE id = ?",
- (rs, rowNum) -> new Theme(rs.getLong("id"), rs.getString("name"), rs.getString("description")),
- reservationRequest.getTheme());
-
- return new Reservation(
- keyHolder.getKey().longValue(),
- reservationRequest.getName(),
- reservationRequest.getDate(),
- time,
- theme
- );
- }
-
- public void deleteById(Long id) {
- jdbcTemplate.update("DELETE FROM reservation WHERE id = ?", id);
- }
-
- public List findReservationsByDateAndTheme(String date, Long themeId) {
- return jdbcTemplate.query(
- "SELECT r.id AS reservation_id, r.name as reservation_name, r.date as reservation_date, " +
- "t.id AS theme_id, t.name AS theme_name, t.description AS theme_description, " +
- "ti.id AS time_id, ti.time_value AS time_value " +
- "FROM reservation r " +
- "JOIN theme t ON r.theme_id = t.id " +
- "JOIN time ti ON r.time_id = ti.id" +
- "WHERE r.date = ? AND r.theme_id = ?",
- new Object[]{date, themeId},
- (rs, rowNum) -> new Reservation(
- rs.getLong("reservation_id"),
- rs.getString("reservation_name"),
- rs.getString("reservation_date"),
- new Time(
- rs.getLong("time_id"),
- rs.getString("time_value")
- ),
- new Theme(
- rs.getLong("theme_id"),
- rs.getString("theme_name"),
- rs.getString("theme_description")
- )));
- }
-
- public List findByDateAndThemeId(String date, Long themeId) {
- return jdbcTemplate.query(
- "SELECT r.id AS reservation_id, r.name as reservation_name, r.date as reservation_date, " +
- "t.id AS theme_id, t.name AS theme_name, t.description AS theme_description, " +
- "ti.id AS time_id, ti.time_value AS time_value " +
- "FROM reservation r " +
- "JOIN theme t ON r.theme_id = t.id " +
- "JOIN time ti ON r.time_id = ti.id " +
- "WHERE r.date = ? AND r.theme_id = ?",
- new Object[]{date, themeId},
- (rs, rowNum) -> new Reservation(
- rs.getLong("reservation_id"),
- rs.getString("reservation_name"),
- rs.getString("reservation_date"),
- new Time(
- rs.getLong("time_id"),
- rs.getString("time_value")
- ),
- new Theme(
- rs.getLong("theme_id"),
- rs.getString("theme_name"),
- rs.getString("theme_description")
- )));
- }
-}
diff --git a/src/main/java/roomescape/reservation/ReservationRepository.java b/src/main/java/roomescape/reservation/ReservationRepository.java
new file mode 100644
index 00000000..d4b5e23b
--- /dev/null
+++ b/src/main/java/roomescape/reservation/ReservationRepository.java
@@ -0,0 +1,12 @@
+package roomescape.reservation;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ReservationRepository extends JpaRepository{
+ List findByDateAndThemeId(String date, Long themeId);
+ List findByMemberIdOrName(Long memberId, String name);
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/reservation/ReservationRequest.java b/src/main/java/roomescape/reservation/ReservationRequest.java
index 19f44124..e6c887b2 100644
--- a/src/main/java/roomescape/reservation/ReservationRequest.java
+++ b/src/main/java/roomescape/reservation/ReservationRequest.java
@@ -6,6 +6,16 @@ public class ReservationRequest {
private Long theme;
private Long time;
+ public void setMember(Long member) {
+ this.member = member;
+ }
+
+ private Long member;
+
+ public Long getMember() {
+ return member;
+ }
+
public String getName() {
return name;
}
@@ -21,4 +31,21 @@ 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;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java
index bd331332..1b224ad3 100644
--- a/src/main/java/roomescape/reservation/ReservationService.java
+++ b/src/main/java/roomescape/reservation/ReservationService.java
@@ -1,30 +1,80 @@
package roomescape.reservation;
import org.springframework.stereotype.Service;
+import roomescape.member.*;
+import roomescape.theme.Theme;
+import roomescape.theme.ThemeRepository;
+import roomescape.time.Time;
+import roomescape.time.TimeRepository;
import java.util.List;
+import java.util.stream.Collectors;
@Service
public class ReservationService {
- private ReservationDao reservationDao;
+ private ReservationRepository reservationRepository;
+ private ThemeRepository themeRepository;
+ private TimeRepository timeRepository;
+ private MemberRepository memberRepository;
+ private MemberService memberService;
- public ReservationService(ReservationDao reservationDao) {
- this.reservationDao = reservationDao;
+ public ReservationService(ReservationRepository reservationRepository, ThemeRepository themeRepository, TimeRepository timeRepository, MemberRepository memberRepository, MemberService memberService) {
+ this.reservationRepository = reservationRepository;
+ this.themeRepository = themeRepository;
+ this.timeRepository = timeRepository;
+ this.memberRepository = memberRepository;
+ this.memberService = memberService;
}
public ReservationResponse save(ReservationRequest reservationRequest) {
- Reservation reservation = reservationDao.save(reservationRequest);
+ Time time = timeRepository.findById(reservationRequest.getTime())
+ .orElseThrow(() -> new IllegalArgumentException("Time not found"));
- return new ReservationResponse(reservation.getId(), reservationRequest.getName(), reservation.getTheme().getName(), reservation.getDate(), reservation.getTime().getValue());
+ Theme theme = themeRepository.findById(reservationRequest.getTheme())
+ .orElseThrow(() -> new IllegalArgumentException("Theme not found"));
+
+ Member member = null;
+ if (reservationRequest.getMember() != null) {
+ member = memberRepository.findById(reservationRequest.getMember())
+ .orElseThrow(() -> new IllegalArgumentException("Member not found"));
+ }
+
+ Reservation reservation = new Reservation(
+ reservationRequest.getName(),
+ reservationRequest.getDate(),
+ time,
+ theme,
+ member
+ );
+
+ reservation = reservationRepository.save(reservation);
+
+ return new ReservationResponse(
+ reservation.getId(),
+ reservation.getName(),
+ reservation.getTheme().getName(),
+ reservation.getDate(),
+ reservation.getTime().getValue()
+ );
}
public void deleteById(Long id) {
- reservationDao.deleteById(id);
+ reservationRepository.deleteById(id);
}
public List findAll() {
- return reservationDao.findAll().stream()
+ return reservationRepository.findAll().stream()
.map(it -> new ReservationResponse(it.getId(), it.getName(), it.getTheme().getName(), it.getDate(), it.getTime().getValue()))
.toList();
}
-}
+
+ public List findReservation(LoginMember loginMember) {
+ List reservations = reservationRepository.findByMemberIdOrName(loginMember.getId(), loginMember.getName()).stream()
+ .map(it -> new MyReservationResponse(it.getId(),
+ it.getTheme().getName(),
+ it.getDate(),
+ it.getTime().getValue(), "예약", null)) // 예약에는 rank가 없으므로 null
+ .collect(Collectors.toList());
+ return reservations;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/theme/Theme.java b/src/main/java/roomescape/theme/Theme.java
index 430a6239..13be5ef4 100644
--- a/src/main/java/roomescape/theme/Theme.java
+++ b/src/main/java/roomescape/theme/Theme.java
@@ -1,7 +1,16 @@
package roomescape.theme;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+
+@Entity
public class Theme {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
+
private String name;
private String description;
@@ -30,4 +39,4 @@ public String getName() {
public String getDescription() {
return description;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/theme/ThemeController.java b/src/main/java/roomescape/theme/ThemeController.java
index 03bca41a..d3dc60b4 100644
--- a/src/main/java/roomescape/theme/ThemeController.java
+++ b/src/main/java/roomescape/theme/ThemeController.java
@@ -13,26 +13,25 @@
@RestController
public class ThemeController {
- private ThemeDao themeDao;
+ private ThemeRepository themeRepository;
- public ThemeController(ThemeDao themeDao) {
- this.themeDao = themeDao;
+ public ThemeController(ThemeRepository themeRepository) {
+ this.themeRepository = themeRepository;
}
-
@PostMapping("/themes")
public ResponseEntity createTheme(@RequestBody Theme theme) {
- Theme newTheme = themeDao.save(theme);
+ Theme newTheme = themeRepository.save(theme);
return ResponseEntity.created(URI.create("/themes/" + newTheme.getId())).body(newTheme);
}
@GetMapping("/themes")
public ResponseEntity> list() {
- return ResponseEntity.ok(themeDao.findAll());
+ return ResponseEntity.ok(themeRepository.findAll());
}
@DeleteMapping("/themes/{id}")
public ResponseEntity deleteTheme(@PathVariable Long id) {
- themeDao.deleteById(id);
+ themeRepository.deleteById(id);
return ResponseEntity.noContent().build();
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/theme/ThemeDao.java b/src/main/java/roomescape/theme/ThemeDao.java
deleted file mode 100644
index 945341d8..00000000
--- a/src/main/java/roomescape/theme/ThemeDao.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package roomescape.theme;
-
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-@Repository
-public class ThemeDao {
- private JdbcTemplate jdbcTemplate;
-
- public ThemeDao(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
-
- public List findAll() {
- return jdbcTemplate.query("SELECT * FROM theme where deleted = false", (rs, rowNum) -> new Theme(
- rs.getLong("id"),
- rs.getString("name"),
- rs.getString("description")
- ));
- }
-
- public Theme save(Theme theme) {
- KeyHolder keyHolder = new GeneratedKeyHolder();
- jdbcTemplate.update(connection -> {
- var ps = connection.prepareStatement("INSERT INTO theme(name, description) VALUES (?, ?)", new String[]{"id"});
- ps.setString(1, theme.getName());
- ps.setString(2, theme.getDescription());
- return ps;
- }, keyHolder);
-
- return new Theme(keyHolder.getKey().longValue(), theme.getName(), theme.getDescription());
- }
-
- public void deleteById(Long id) {
- jdbcTemplate.update("UPDATE theme SET deleted = true WHERE id = ?", id);
- }
-}
diff --git a/src/main/java/roomescape/theme/ThemeRepository.java b/src/main/java/roomescape/theme/ThemeRepository.java
new file mode 100644
index 00000000..6de5f68e
--- /dev/null
+++ b/src/main/java/roomescape/theme/ThemeRepository.java
@@ -0,0 +1,9 @@
+package roomescape.theme;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ThemeRepository extends JpaRepository {
+
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java
index 008ed93c..1eab14b0 100644
--- a/src/main/java/roomescape/time/Time.java
+++ b/src/main/java/roomescape/time/Time.java
@@ -1,9 +1,20 @@
package roomescape.time;
+import jakarta.persistence.*;
+
+@Entity
public class Time {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
+
+ @Column(name = "time_value")
private String value;
+ public Time() {
+
+ }
+
public Time(Long id, String value) {
this.id = id;
this.value = value;
@@ -13,10 +24,6 @@ public Time(String value) {
this.value = value;
}
- public Time() {
-
- }
-
public Long getId() {
return id;
}
@@ -24,4 +31,12 @@ public Long getId() {
public String getValue() {
return value;
}
-}
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/roomescape/time/TimeDao.java b/src/main/java/roomescape/time/TimeDao.java
deleted file mode 100644
index f39a9a32..00000000
--- a/src/main/java/roomescape/time/TimeDao.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package roomescape.time;
-
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-
-import java.sql.PreparedStatement;
-import java.util.List;
-
-@Repository
-public class TimeDao {
- private final JdbcTemplate jdbcTemplate;
-
- public TimeDao(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
-
- public List