Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spring Data JPA] 정다영 미션 제출합니다. #55

Open
wants to merge 13 commits into
base: day024
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Spring Data JPA

<h3>4단계 JPA 전환</h3>

- [x] gradle 의존성 추가
- [x] 엔티티 매핑
- [x] 연관관계 매핑

<h3>5단계 내 예약 목록 조회</h3>

내 예약 목록을 조회 API 구현
- [x] Reservation 테이블의 수정
- 관리자가 어드민 화면에서 예약을 생성하는 경우 name 값을 string으로 전달
- 사용자가 예약 화면에서 예약 생성하는 경우 로그인 정보를 이용하여 Member의 ID를 Reservation에 저장하도록 합니다.
- [x] 화면 응답 (reservation-mine.html.html)

<h3>6단계 예약 대기 </h3>

예약 대기 API
- [ ] 예약 대기 요청 기능
- 대기 순서가 undefined번째라고 뜨는 문제
- [ ] 예약 대기 취소 기능
- 삭제할 id를 찾지 못하는 문제
- [x] 내 예약 목록 조회 시 예약 대기 목록도 함께 포함
- [x] 중복 예약이 불가능 하도록 구현하세요.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -29,6 +28,7 @@ dependencies {
runtimeOnly 'com.h2database:h2'
}


test {
useJUnitPlatform()
}
}
2 changes: 1 addition & 1 deletion src/main/java/roomescape/PageController.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ public String login() {
public String signup() {
return "signup";
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/roomescape/RoomescapeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ public class RoomescapeApplication {
public static void main(String[] args) {
SpringApplication.run(RoomescapeApplication.class, args);
}
}
}
25 changes: 25 additions & 0 deletions src/main/java/roomescape/instructure/JwtTokenProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape.instructure;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import roomescape.member.MemberResponse;

@Component
public class JwtTokenProvider {
@Value("${roomescape.auth.jwt.secret}")
String secretKey;

public String createToken( MemberResponse member) {
String accessToken = Jwts.builder()
.setSubject(member.getId().toString())
.claim("name", member.getName())
.claim("email", member.getEmail())
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
.compact();

return accessToken;
}
}
26 changes: 26 additions & 0 deletions src/main/java/roomescape/member/AdminInterceptor.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
61 changes: 61 additions & 0 deletions src/main/java/roomescape/member/LoginMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package roomescape.member;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoginMember는 엔티티가 아니어서 @Entity를 붙이지 않는 게 맞지 않나 싶습니다..!
엔티티는 실제로 데이터베이스와 일대일 매핑이 되는 영속성을 띄는 객체이기 때문에 LoginMember는 엔티티가 아니라 DTO 같습니다!

아래에 있는 JPA 관련 어노테이션들도 다 붙이면 안 될 것 같습니다!

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;
}
}
35 changes: 35 additions & 0 deletions src/main/java/roomescape/member/LoginMemberArgumentResolver.java
Original file line number Diff line number Diff line change
@@ -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());
}
}
19 changes: 16 additions & 3 deletions src/main/java/roomescape/member/Member.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -40,4 +52,5 @@ public String getPassword() {
public String getRole() {
return role;
}
}

}
37 changes: 34 additions & 3 deletions src/main/java/roomescape/member/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,59 @@
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 roomescape.instructure.JwtTokenProvider;

import java.net.URI;

@RestController
public class MemberController {
private JwtTokenProvider jwtUtil;
private MemberService memberService;

public MemberController(MemberService memberService) {
public MemberController(MemberService memberService, JwtTokenProvider jwtUtil) {
this.memberService = memberService;
this.jwtUtil = jwtUtil;
}

@PostMapping("/members")
public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) {
public ResponseEntity<MemberResponse> createMember(@RequestBody MemberRequest memberRequest) {
MemberResponse member = memberService.createMember(memberRequest);
return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member);
}

@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody MemberRequest memberRequest, HttpServletResponse response){
MemberResponse member = memberService.findMember(memberRequest.getEmail(), memberRequest.getPassword());
if (member == null) { //멤버 X
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<MemberResponse> checkLogin(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
String token = memberService.extractTokenFromCookie(cookies);

Long memberId = memberService.extractMemberIdFromToken(token);
MemberResponse member = memberService.findMemberById(memberId);

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", "");
Expand All @@ -34,4 +65,4 @@ public ResponseEntity logout(HttpServletResponse response) {
response.addCookie(cookie);
return ResponseEntity.ok().build();
}
}
}
55 changes: 0 additions & 55 deletions src/main/java/roomescape/member/MemberDao.java

This file was deleted.

14 changes: 14 additions & 0 deletions src/main/java/roomescape/member/MemberRepository.java
Original file line number Diff line number Diff line change
@@ -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, Long> {
Member findByEmailAndPassword(String email, String password);
Optional<Member> findByName(String name);
}
Loading