User
package com.freemarket.freemarket.user.domain;
import com.freemarket.freemarket.global.auditing.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "users")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(updatable = true, nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String name;
private String phone;
@Column(nullable = false)
private boolean enabled = true;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserRole role = UserRole.ROLE_USER;
@Builder
public User(String email, String password, String name, String phone, boolean enabled, UserRole role) {
this.email = email;
this.password = password;
this.name = name;
this.phone = phone;
this.enabled = enabled;
this.role = role != null ? role : UserRole.ROLE_USER;
}
public void updateProfile(String name, String phone) {
this.name = name;
this.phone = phone;
}
public void changePassword(String password) {
this.password = password;
}
public void activateAccount() {
this.enabled = true;
}
public void deactivateAccount() {
this.enabled = false;
}
public void changeRole(UserRole role) {
this.role = role;
}
}
package com.freemarket.freemarket.user.domain;
public enum UserRole {
ROLE_USER("일반 사용자"),
ROLE_SELLER("판매자"),
ROLE_ADMIN("관리자");
private final String displayName;
UserRole(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
Review
package com.freemarket.freemarket.review.domain;
import com.freemarket.freemarket.oderItem.domain.OrderItem;
import com.freemarket.freemarket.product.domain.Product;
import com.freemarket.freemarket.user.domain.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "review")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Review {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "review_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_item_id", nullable = false)
private OrderItem orderItem;
@Column(nullable = false)
private int rating;
@Column(columnDefinition = "TEXT")
private String content;
@Builder
public Review(User user, Product product, OrderItem orderItem, int rating, String content) {
this.user = user;
this.product = product;
this.orderItem = orderItem;
this.rating = rating;
this.content = content;
}
public void update(int rating, String content) {
this.rating = rating;
this.content = content;
}
}
Product
package com.freemarket.freemarket.product.domain;
import com.freemarket.freemarket.global.auditing.BaseEntity;
import com.freemarket.freemarket.user.domain.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "products")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "product_id")
private Long id;
@Column(nullable = false)
private String name;
@Column(columnDefinition = "TEXT")
private String description;
@Column(nullable = false)
private long price;
@Column(nullable = false)
private int stock;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ProductCategory category;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ProductStatus status = ProductStatus.ACTIVE;
private String imageUrl;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "seller_id")
private User seller;
public Product(String name, String description, long price, int stock, ProductCategory category, ProductStatus status, String imageUrl, User seller) {
this.name = name;
this.description = description;
this.price = price;
this.stock = stock;
this.category = category;
this.status = status != null ? status : ProductStatus.ACTIVE;
this.imageUrl = imageUrl;
this.seller = seller;
}
@Builder
public void decreaseStock(int quantity) {
if (this.stock < quantity) {
throw new IllegalArgumentException("재고가 부족합니다.");
}
this.stock -= quantity;
if (this.stock == 0) {
this.status = ProductStatus.SOLD_OUT;
}
}
public void increaseStock(int quantity) {
this.stock += quantity;
if (this.stock > 0 && this.status == ProductStatus.SOLD_OUT) {
this.status = ProductStatus.ACTIVE;
}
}
public void update(String name, String description, long price, int stock, ProductCategory category, String imageUrl) {
this.name = name;
this.description = description;
this.price = price;
this.stock = stock;
this.category = category;
this.imageUrl = imageUrl;
if (stock > 0 && this.status == ProductStatus.SOLD_OUT) {
this.status = ProductStatus.ACTIVE;
} else if (stock == 0 && this.status == ProductStatus.ACTIVE) {
this.status = ProductStatus.SOLD_OUT;
}
}
public void changeStatus(ProductStatus status) {
this.status = status;
}
}
package com.freemarket.freemarket.product.domain;
public enum ProductCategory {
TEST("테스트");
private final String displayName;
ProductCategory(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
package com.freemarket.freemarket.product.domain;
public enum ProductStatus {
ACTIVE("판매중"),
SOLD_OUT("품절"),
DISCONTINUED("판매 중단"),
PENDING("승인 대기");
private final String displayName;
ProductStatus(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
Order
package com.freemarket.freemarket.order.domain;
import com.freemarket.freemarket.global.auditing.BaseEntity;
import com.freemarket.freemarket.oderItem.domain.OrderItem;
import com.freemarket.freemarket.user.domain.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "orders")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Order extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(nullable = false, unique = true)
private String orderNumber;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private OrderStatus status = OrderStatus.PENDING;
@Column(nullable = false)
private long totalPrice;
@Column(nullable = false)
private String recipientName;
@Column(nullable = false)
private String recipientPhone;
@Column(nullable = false)
private String shippingAddress;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
@Builder
public Order(User user, OrderStatus status, long totalPrice, String recipientName, String recipientPhone, String shippingAddress, List<OrderItem> items) {
this.user = user;
this.status = status != null ? status : OrderStatus.PENDING;
this.totalPrice = totalPrice;
this.recipientName = recipientName;
this.recipientPhone = recipientPhone;
this.shippingAddress = shippingAddress;
this.orderNumber = generateOrderNumber();
}
private String generateOrderNumber() {
return "ORD" + System.currentTimeMillis();
}
public void addItem(OrderItem item) {
items.add(item);
item.connectToOrder(this);
}
public void changeStatus(OrderStatus status) {
this.status = status;
}
public void cancel() {
if (this.status == OrderStatus.SHIPPING || this.status == OrderStatus.DELIVERED) {
throw new IllegalArgumentException("이미 배송중이거나, 배송 완료된 주문은 취소할 수 없습니다.");
}
this.status = OrderStatus.CANCELED;
for (OrderItem item : items) {
item.cancel();
}
}
}
package com.freemarket.freemarket.order.domain;
public enum OrderStatus {
PENDING("결제 대기"),
PAID("결제 완료"),
PREPARING("상품 준비중"),
SHIPPING("배송중"),
DELIVERED("배송 완료"),
CANCELED("주문 취소");
private final String displayName;
OrderStatus(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
OrderItem
package com.freemarket.freemarket.oderItem.domain;
import com.freemarket.freemarket.global.auditing.BaseTimeEntity;
import com.freemarket.freemarket.order.domain.Order;
import com.freemarket.freemarket.product.domain.Product;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "order_items")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OrderItem extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_item_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id", nullable = false)
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
@Column(nullable = false)
private String productName;
@Column(nullable = false)
private int quantity;
@Column(nullable = false)
private long price;
@Builder
public OrderItem(Order order, Product product, String productName, int quantity, long price) {
this.order = order;
this.product = product;
this.productName = productName;
this.quantity = quantity;
this.price = price;
}
public static OrderItem createOrderItem(Product product, int quantity) {
product.decreaseStock(quantity);
return OrderItem.builder()
.product(product)
.productName(product.getName())
.quantity(quantity)
.price(product.getPrice() * quantity)
.build();
}
public void cancel() {
if (this.product != null) {
this.product.increaseStock(this.quantity);
}
}
public void connectToOrder(Order order) {
this.order = order;
}
}