Skip to content
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
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
# spring-shopping-precourse
# spring-shopping-precourse

- [ ] 상품 (product)
- [x] 상품은 이름을 가지고 있다.
- [x] 상품은 가격을 가지고 있다.
- [x] 상품은 이미지 url을 가지고 있다.
- 상품은 클라이언트 코드에서 등록될 수 있다.
- 유효성 검사
- [x] 이름은 공백 포함 15자 이하다
- [x] 이름에는 특수문자도 포함된다.
- [x] 특수문자는 (), [], +, -, &, /, _ 외에는 안된다.
- [ ] 이름에는 비속어가 들어가면 안된다. (PurgoMalum에서 확인)
- [ ] 회원
- [x] 회원은 이메일을 가지고 있다.
- [ ] 회원은
43 changes: 43 additions & 0 deletions src/main/java/shopping/controller/MemberController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package shopping.controller;

import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import shopping.service.MemberService;

import java.util.Map;

@RestController
@RequestMapping("/api/members")
public class MemberController {

private final MemberService memberService;

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

// 회원 가입
@PostMapping("/register")
public ResponseEntity<Map<String, String>> registerMember(
@Valid @RequestBody MemberRegistrationRequest registrationRequest) {
// 비밀번호는 평문으로 입력받음
memberService.registerMember(registrationRequest.getEmail(), registrationRequest.getPassword());
return new ResponseEntity<>(Map.of("message", "Member registered successfully"), HttpStatus.CREATED);
}

// 로그인
@PostMapping("/login")
public ResponseEntity<Map<String, String>> loginMember(
@Valid @RequestBody MemberLoginRequest loginRequest) {
boolean authenticated = memberService.authenticateMember(loginRequest.getEmail(), loginRequest.getPassword());
if (authenticated) {
// 로그인 성공 시 토큰 발급 (간단히 메시지로 대체)
return new ResponseEntity<>(Map.of("message", "Login successful"), HttpStatus.OK);
} else {
// 로그인 실패 시
return new ResponseEntity<>(Map.of("message", "Invalid email or password"), HttpStatus.UNAUTHORIZED);
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/shopping/controller/MemberLoginRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package shopping.controller;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

public class MemberLoginRequest {

@NotBlank
@Email
private String email;

@NotBlank
private String password;

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
30 changes: 30 additions & 0 deletions src/main/java/shopping/controller/MemberRegistrationRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package shopping.controller;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

public class MemberRegistrationRequest {

@NotBlank
@Email
private String email;

@NotBlank
private String password;

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
59 changes: 59 additions & 0 deletions src/main/java/shopping/controller/ProductController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package shopping.controller;

import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import shopping.model.Product;
import shopping.service.ProductService;

import java.util.Optional;

@RestController
@RequestMapping("/api/products")
public class ProductController {

private final ProductService productService;

public ProductController(ProductService productService) {
this.productService = productService;
}

// 상품 생성
@PostMapping
public ResponseEntity<Product> createProduct(@Valid @RequestBody Product product) {
Product createdProduct = productService.createProduct(product);
return new ResponseEntity<>(createdProduct, HttpStatus.CREATED);
}

// 상품 조회
@GetMapping("/{productId}")
public ResponseEntity<Optional<Product>> getProductById(@PathVariable Long productId) {
Optional<Product> product = productService.getProductById(productId);
return new ResponseEntity<>(product, HttpStatus.OK);
}

// 상품 수정
@PutMapping("/{productId}")
public ResponseEntity<Product> updateProduct(
@PathVariable Long productId,
@Valid @RequestBody Product productDetails) {
Product updatedProduct = productService.updateProduct(productId, productDetails);
return new ResponseEntity<>(updatedProduct, HttpStatus.OK);
}

// 상품 삭제
@DeleteMapping("/{productId}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long productId) {
productService.deleteProduct(productId);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

// 상품 목록 조회
@GetMapping
public ResponseEntity<Iterable<Product>> getAllProducts() {
Iterable<Product> products = productService.getAllProducts();
return new ResponseEntity<>(products, HttpStatus.OK);
}
}

17 changes: 17 additions & 0 deletions src/main/java/shopping/controller/ProductWishRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package shopping.controller;

import jakarta.validation.constraints.NotNull;

public class ProductWishRequest {

@NotNull
private Long productId;

public Long getProductId() {
return productId;
}

public void setProductId(Long productId) {
this.productId = productId;
}
}
82 changes: 82 additions & 0 deletions src/main/java/shopping/controller/WishController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package shopping.controller;

import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import shopping.model.Member;
import shopping.model.Product;
import shopping.service.MemberService;
import shopping.service.ProductService;
import shopping.service.WishService;

import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/wishes")
public class WishController {

private final WishService wishService;

private final ProductService productService;

private final MemberService memberService;

public WishController(WishService wishService, ProductService productService, MemberService memberService) {
this.wishService = wishService;
this.productService = productService;
this.memberService = memberService;
}

// 위시 리스트에 상품 추가
@PostMapping
public ResponseEntity<Map<String, String>> addProductToWishList(
String email, // 로그인된 사용자 이메일
@RequestBody @Valid ProductWishRequest wishRequest) {

Optional<Member> memberOpt = memberService.findByEmail(email);
if (memberOpt.isEmpty()) {
return new ResponseEntity<>(Map.of("message", "User not found"), HttpStatus.NOT_FOUND);
}

Optional<Product> productOpt = productService.getProductById(wishRequest.getProductId());
if (productOpt.isEmpty()) {
return new ResponseEntity<>(Map.of("message", "Product not found"), HttpStatus.NOT_FOUND);
}

wishService.addProductToWishList(memberOpt.get(), productOpt.get());
return new ResponseEntity<>(Map.of("message", "Product added to wish list"), HttpStatus.OK);
}

// 위시 리스트에서 상품 삭제
@DeleteMapping("/{productId}")
public ResponseEntity<Map<String, String>> removeProductFromWishList(
String email, // 로그인된 사용자 이메일
@PathVariable Long productId) {

Optional<Member> memberOpt = memberService.findByEmail(email);
if (memberOpt.isEmpty()) {
return new ResponseEntity<>(Map.of("message", "User not found"), HttpStatus.NOT_FOUND);
}

boolean removed = wishService.removeProductFromWishList(memberOpt.get(), productId);
if (removed) {
return new ResponseEntity<>(Map.of("message", "Product removed from wish list"), HttpStatus.OK);
} else {
return new ResponseEntity<>(Map.of("message", "Product not found in wish list"), HttpStatus.NOT_FOUND);
}
}

// 로그인된 사용자의 위시 리스트 조회
@GetMapping
public ResponseEntity<Iterable<Product>> getWishList(String email) {
Optional<Member> memberOpt = memberService.findByEmail(email);
if (memberOpt.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}

Iterable<Product> wishList = wishService.getWishList(memberOpt.get());
return new ResponseEntity<>(wishList, HttpStatus.OK);
}
}
50 changes: 50 additions & 0 deletions src/main/java/shopping/model/Member.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package shopping.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Email
@NotBlank
private String email;

@NotBlank
private String password;

public Member (String email) {
this(email, "");
}
public Member(String email, String password) {
this.email = email;
this.password = password;
}

public Member() {
this(null, null);
}

public String getEmail() {
return email;
}

public String getPassword() {
return password;
}

public void setEmail(String email) {
this.email = email;
}

public void setPassword(String password) {
this.password = password;
}
}
Loading