Commit 969fb9e8 authored by madvirus's avatar madvirus
Browse files

Initial Commit

parents
package com.myshop.catalog.command.domain.product;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class Option {
@Column(name = "option_value")
private String value;
@Column(name = "option_title")
private String title;
private Option() {
}
public Option(String value, String title) {
this.value = value;
this.title = title;
}
public String getValue() {
return value;
}
public String getTitle() {
return title;
}
}
package com.myshop.catalog.command.domain.product;
import com.myshop.catalog.command.domain.category.CategoryId;
import com.myshop.common.jpa.MoneyConverter;
import com.myshop.common.model.Money;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@Entity
@Table(name = "product")
public class Product {
@EmbeddedId
private ProductId id;
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "product_category",
joinColumns = @JoinColumn(name = "product_id"))
private Set<CategoryId> categoryIds;
private String name;
@Convert(converter = MoneyConverter.class)
private Money price;
private String detail;
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE},
orphanRemoval = true, fetch = FetchType.LAZY)
@JoinColumn(name = "product_id")
@OrderColumn(name = "list_idx")
private List<Image> images = new ArrayList<>();
protected Product() {
}
public Product(ProductId id, String name, Money price, String detail, List<Image> images) {
this.id = id;
this.name = name;
this.price = price;
this.detail = detail;
this.images.addAll(images);
}
public ProductId getId() {
return id;
}
public String getName() {
return name;
}
public Money getPrice() {
return price;
}
public String getDetail() {
return detail;
}
public List<Image> getImages() {
return Collections.unmodifiableList(images);
}
public void changeImages(List<Image> newImages) {
images.clear();
images.addAll(newImages);
}
public String getFirstIamgeThumbnailPath() {
if (images == null || images.isEmpty()) return null;
return images.get(0).getThumbnailUrl();
}
}
package com.myshop.catalog.command.domain.product;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;
@Embeddable
@Access(AccessType.FIELD)
public class ProductId implements Serializable {
@Column(name = "product_id")
private String id;
protected ProductId() {
}
public ProductId(String id) {
this.id = id;
}
public String getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductId productId = (ProductId) o;
return Objects.equals(id, productId.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public static ProductId of(String id) {
return new ProductId(id);
}
}
package com.myshop.catalog.command.domain.product;
import org.springframework.data.repository.Repository;
import java.util.Optional;
public interface ProductRepository extends Repository<Product, ProductId> {
void save(Product product);
Optional<Product> findById(ProductId id);
void flush();
}
package com.myshop.catalog.query.category;
import com.myshop.catalog.command.domain.category.CategoryId;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "category")
public class CategoryData {
@EmbeddedId
private CategoryId id;
@Column(name = "name")
private String name;
protected CategoryData() {
}
public CategoryData(CategoryId id, String name) {
this.id = id;
this.name = name;
}
public CategoryId getId() {
return id;
}
public String getName() {
return name;
}
}
package com.myshop.catalog.query.category;
import com.myshop.catalog.command.domain.category.CategoryId;
import org.springframework.data.repository.Repository;
import java.util.List;
import java.util.Optional;
public interface CategoryDataDao extends Repository<CategoryData, CategoryId> {
Optional<CategoryData> findById(CategoryId id);
List<CategoryData> findAll();
}
package com.myshop.catalog.query.product;
import com.myshop.catalog.query.category.CategoryData;
import java.util.List;
public class CategoryProduct {
private CategoryData category;
private List<ProductSummary> items;
private int page;
private int size;
private long totalCount;
private int totalPages;
public CategoryProduct(CategoryData category,
List<ProductSummary> items,
int page,
int size,
long totalCount,
int totalPages) {
this.category = category;
this.items = items;
this.page = page;
this.size = size;
this.totalCount = totalCount;
this.totalPages = totalPages;
}
public CategoryData getCategory() {
return category;
}
public List<ProductSummary> getItems() {
return items;
}
public int getPage() {
return page;
}
public int getSize() {
return size;
}
public long getTotalCount() {
return totalCount;
}
public int getTotalPages() {
return totalPages;
}
}
package com.myshop.catalog.query.product;
import javax.persistence.Column;
import java.time.LocalDateTime;
public class ImageData {
@Column(name = "image_path")
private String path;
private LocalDateTime uploadTime;
}
package com.myshop.catalog.query.product;
import com.myshop.catalog.command.domain.category.CategoryId;
import com.myshop.catalog.command.domain.product.Image;
import com.myshop.catalog.command.domain.product.ProductId;
import com.myshop.common.jpa.MoneyConverter;
import com.myshop.common.model.Money;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@Entity
@Table(name = "product")
public class ProductData {
@EmbeddedId
private ProductId id;
@ElementCollection
@CollectionTable(name = "product_category",
joinColumns = @JoinColumn(name = "product_id"))
private Set<CategoryId> categoryIds;
private String name;
@Convert(converter = MoneyConverter.class)
private Money price;
private String detail;
// TODO 목록에서 사용할 것
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE},
orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "product_id")
@OrderColumn(name = "list_idx")
private List<Image> images = new ArrayList<>();
protected ProductData() {
}
public ProductData(ProductId id, String name, Money price, String detail, List<Image> images) {
this.id = id;
this.name = name;
this.price = price;
this.detail = detail;
this.images.addAll(images);
}
public ProductId getId() {
return id;
}
public String getName() {
return name;
}
public Money getPrice() {
return price;
}
public String getDetail() {
return detail;
}
public List<Image> getImages() {
return Collections.unmodifiableList(images);
}
public String getFirstIamgeThumbnailPath() {
if (images == null || images.isEmpty()) return null;
return images.get(0).getThumbnailUrl();
}
}
package com.myshop.catalog.query.product;
import com.myshop.catalog.command.domain.category.CategoryId;
import com.myshop.catalog.command.domain.product.ProductId;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
import java.util.Optional;
public interface ProductDataDao extends Repository<ProductData, ProductId> {
Optional<ProductData> findById(ProductId id);
Page<ProductData> findByCategoryIdsContains(CategoryId id, Pageable pageable);
}
package com.myshop.catalog.query.product;
import com.myshop.catalog.NoCategoryException;
import com.myshop.catalog.command.domain.category.CategoryId;
import com.myshop.catalog.command.domain.product.ProductId;
import com.myshop.catalog.query.category.CategoryData;
import com.myshop.catalog.query.category.CategoryDataDao;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import static java.util.stream.Collectors.toList;
@Service
public class ProductQueryService {
private ProductDataDao productDataDao;
private CategoryDataDao categoryDataDao;
public ProductQueryService(ProductDataDao productDataDao,
CategoryDataDao categoryDataDao) {
this.productDataDao = productDataDao;
this.categoryDataDao = categoryDataDao;
}
@Transactional
public CategoryProduct getProductInCategory(Long categoryId, int page, int size) {
CategoryData category = categoryDataDao.findById(new CategoryId(categoryId))
.orElseThrow(() -> new NoCategoryException());
Page<ProductData> productPage = productDataDao.findByCategoryIdsContains(category.getId(), Pageable.ofSize(size).withPage(page - 1));
return new CategoryProduct(category,
toSummary(productPage.getContent()),
page,
productPage.getSize(),
productPage.getTotalElements(),
productPage.getTotalPages());
}
private List<ProductSummary> toSummary(List<ProductData> products) {
return products.stream().map(
prod -> new ProductSummary(
prod.getId().getId(),
prod.getName(),
prod.getPrice().getValue(),
prod.getFirstIamgeThumbnailPath())).collect(toList());
}
public Optional<ProductData> getProduct(String productId) {
return productDataDao.findById(new ProductId(productId));
}
}
package com.myshop.catalog.query.product;
public class ProductSummary {
private String id;
private String name;
private int price;
private String image;
public ProductSummary(String productId, String name, int price, String image) {
this.id = productId;
this.name = name;
this.price = price;
this.image = image;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
public String getImage() {
return image;
}
}
package com.myshop.catalog.ui;
import com.myshop.catalog.query.category.CategoryData;
import com.myshop.catalog.query.category.CategoryDataDao;
import com.myshop.catalog.query.product.CategoryProduct;
import com.myshop.catalog.query.product.ProductData;
import com.myshop.catalog.query.product.ProductQueryService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
@Controller
public class ProductController {
private CategoryDataDao categoryDataDao;
private ProductQueryService productQueryService;
public ProductController(CategoryDataDao categoryDataDao,
ProductQueryService productQueryService) {
this.categoryDataDao = categoryDataDao;
this.productQueryService = productQueryService;
}
@RequestMapping("/categories")
public String categories(ModelMap model) {
List<CategoryData> categories = categoryDataDao.findAll();
model.addAttribute("categories", categories);
return "category/categoryList";
}
@RequestMapping("/categories/{categoryId}")
public String list(@PathVariable("categoryId") Long categoryId,
@RequestParam(name = "page", required = false, defaultValue = "1") int page,
ModelMap model) {
CategoryProduct productInCategory = productQueryService.getProductInCategory(categoryId, page, 10);
model.addAttribute("productInCategory", productInCategory);
return "category/productList";
}
@RequestMapping("/products/{productId}")
public String detail(@PathVariable("productId") String productId,
ModelMap model,
HttpServletResponse response) throws IOException {
Optional<ProductData> product = productQueryService.getProduct(productId);
if (product.isPresent()) {
model.addAttribute("product", product.get());
return "category/productDetail";
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return null;
}
}
}
package com.myshop.common;
public class ValidationError {
private String name;
private String code;
public ValidationError(String name, String code) {
this.name = name;
this.code = code;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
public boolean hasName() {
return name != null;
}
public static ValidationError of(String code) {
return new ValidationError(null, code);
}
public static ValidationError of(String name, String code) {
return new ValidationError(name, code);
}
}
package com.myshop.common;
import java.util.List;
public class ValidationErrorException extends RuntimeException {
private List<ValidationError> errors;
public ValidationErrorException(List<ValidationError> errors) {
this.errors = errors;
}
public List<ValidationError> getErrors() {
return errors;
}
}
package com.myshop.common;
public class VersionConflictException extends RuntimeException {
}
package com.myshop.common.event;
public abstract class Event {
private long timestamp;
public Event() {
this.timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
}
package com.myshop.common.event;
import com.myshop.eventstore.api.EventStore;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class EventStoreHandler {
private EventStore eventStore;
public EventStoreHandler(EventStore eventStore) {
this.eventStore = eventStore;
}
@EventListener(Event.class)
public void handle(Event event) {
eventStore.save(event);
}
}
package com.myshop.common.event;
import org.springframework.context.ApplicationEventPublisher;
public class Events {
private static ApplicationEventPublisher publisher;
static void setPublisher(ApplicationEventPublisher publisher) {
Events.publisher = publisher;
}
public static void raise(Object event) {
if (publisher != null) {
publisher.publishEvent(event);
}
}
}
package com.myshop.common.event;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EventsConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
public InitializingBean eventsInitializer() {
return () -> Events.setPublisher(applicationContext);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment