Skip to content

Commit

Permalink
Merge pull request #7 from yeon-so/yeon-so
Browse files Browse the repository at this point in the history
11주차 과제
  • Loading branch information
bbhye1 authored Nov 6, 2023
2 parents e1ed3c9 + 872f26b commit 6e9675e
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 25 deletions.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ public CreateProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}

public Product createProduct(String name, Money price) {
Product product = Product.create(name, price);
public Product createProduct(String name, String image, Money price) {

Product product = Product.create(name, image, price);

productRepository.save(product);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,36 @@
import com.example.demo.dtos.CreateProductDto;
import com.example.demo.dtos.ProductListDto;
import com.example.demo.models.Money;
import com.example.demo.utils.ImageStorage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("products")
@CrossOrigin
public class ProductController {
private final GetProductListService getProductListService;
private final CreateProductService createProductService;
private final ImageStorage imageStorage;

public ProductController(GetProductListService getProductListService,
CreateProductService createProductService) {
CreateProductService createProductService,
ImageStorage imageStorage) {
this.getProductListService = getProductListService;
this.createProductService = createProductService;
this.imageStorage = imageStorage;
}

@GetMapping
public ProductListDto list() {
return getProductListService.getProductListDto();
}

/*
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void create(@RequestBody CreateProductDto dto) {
Expand All @@ -34,4 +43,18 @@ public void create(@RequestBody CreateProductDto dto) {
createProductService.createProduct(name, price);
}
*/

@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public void create(
@ModelAttribute CreateProductDto dto
) throws IOException {
String name = dto.name().strip();
Money price = new Money(dto.price());
String image = imageStorage.save(dto.image());

createProductService.createProduct(name, image, price);
}

}
3 changes: 3 additions & 0 deletions src/main/java/com/example/demo/dtos/CreateProductDto.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.example.demo.dtos;

import org.springframework.web.multipart.MultipartFile;

public record CreateProductDto(
String name,
MultipartFile image,
Long price
) {
}
1 change: 1 addition & 0 deletions src/main/java/com/example/demo/dtos/ProductListDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public List<ProductDto> getProducts() {
public record ProductDto(
String id,
String name,
String image,
Long price
) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public ProductListDto fetchProductListDto() {
new ProductListDto.ProductDto(
resultSet.getString("id"),
resultSet.getString("name"),
resultSet.getString("image"),
resultSet.getLong("price")
)
);
Expand Down
15 changes: 12 additions & 3 deletions src/main/java/com/example/demo/models/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.persistence.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;

Expand All @@ -15,6 +16,9 @@ public class Product {
@Column(name = "name")
private String name;

@Column(name = "image")
private String image;

@CreationTimestamp
private LocalDateTime createdAt;

Expand All @@ -28,14 +32,15 @@ public class Product {
private Product() {
}

public Product(ProductId id, String name, Money price) {
public Product(ProductId id, String name, String image, Money price) {
this.id = id;
this.name = name;
this.image = image;
this.price = price;
}

public static Product create(String name, Money price) {
return new Product(ProductId.generate(), name, price);
public static Product create(String name, String image, Money price) {
return new Product(ProductId.generate(), name, image, price);
}

public ProductId id() {
Expand All @@ -49,4 +54,8 @@ public String name() {
public Money price() {
return price;
}

public String image() {
return image;
}
}
35 changes: 35 additions & 0 deletions src/main/java/com/example/demo/utils/ImageStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.example.demo.utils;

import io.hypersistence.tsid.TSID;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

@Component
public class ImageStorage {
public String save(MultipartFile multipartFile) {

if(multipartFile == null || multipartFile.isEmpty()) {
return "No Image";
}

String id = TSID.Factory.getTsid().toString();

String filename = "data/" + id + ".jpg";

File file = new File(filename);

try (OutputStream outputStream =
new FileOutputStream(file)) {
outputStream.write(multipartFile.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}

return file.getPath();
}
}
2 changes: 1 addition & 1 deletion src/test/java/com/example/demo/Fixtures.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static Product product() {
public static Product product(int number) {
ProductId productId = new ProductId("012300000000" + number);
return new Product(
productId, "Product #" + number, new Money(123_000L));
productId, "Product #" + number,"test.jpg", new Money(123_000L));
}

public static Cart cart() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.example.demo.application.product;

import com.example.demo.utils.ImageStorage;
import com.example.demo.models.Money;
import com.example.demo.models.Product;
import com.example.demo.repositories.ProductRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockMultipartFile;

import java.io.FileInputStream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
Expand All @@ -20,16 +24,19 @@ void setUp() {
productRepository = mock(ProductRepository.class);

createProductService = new CreateProductService(productRepository);

}

@Test
void createProduct() {
void createProduct() throws Exception {
String name = "제-품";
Money price = new Money(100_000L);
String image = "test.jpg";

Product product = createProductService.createProduct(name, price);
Product product = createProductService.createProduct(name, image, price);

assertThat(product.name()).isEqualTo(name);
assertThat(product.image()).isEqualTo(image);
assertThat(product.price()).isEqualTo(price);

verify(productRepository).save(product);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@
import com.example.demo.application.product.GetProductListService;
import com.example.demo.dtos.ProductListDto;
import com.example.demo.models.Money;
import com.example.demo.utils.ImageStorage;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;

import java.io.FileInputStream;
import java.util.List;

import static com.example.demo.controllers.helpers.ResultMatchers.contentContains;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

Expand All @@ -34,39 +38,44 @@ class ProductControllerTest {
@MockBean
private CreateProductService createProductService;

@MockBean
private ImageStorage imageStorage;

@Test
@DisplayName("GET /products")
void list() throws Exception {
ProductListDto.ProductDto productDto =
new ProductListDto.ProductDto("test-id", "제품", 100_000L);
new ProductListDto.ProductDto("test-id", "제품", "test.jpg", 100_000L);

given(getProductListService.getProductListDto()).willReturn(
new ProductListDto(List.of(productDto)));

mockMvc.perform(get("/products"))
.andExpect(status().isOk())
.andExpect(contentContains("제품"));
.andExpect(contentContains(""));
}

@Test
@DisplayName("POST /products")
void create() throws Exception {
String json = String.format(
"""
{
"name": "멋진 제품",
"price": %d
}
""",
100_000L

String filename = "src/test/resources/files/test.jpg";

MockMultipartFile file = new MockMultipartFile(
"image", "test.jpg", "image/jpeg",
new FileInputStream(filename)
);

mockMvc.perform(post("/products")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
given(imageStorage.save(file)).willReturn("test.jpg");


mockMvc.perform(multipart("/products")
.file(file)
.param("name", "제품")
.param("price", String.valueOf(100_000L)))
.andExpect(status().isCreated());

verify(createProductService)
.createProduct("멋진 제품", new Money(100_000L));
.createProduct("제품", "test.jpg", new Money(100_000L));
}
}
3 changes: 2 additions & 1 deletion src/test/java/com/example/demo/models/ProductTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
class ProductTest {
@Test
void creation() {
Product product = Product.create("제품명", new Money(123_456L));
Product product = Product.create("제품명", "test.jpg", new Money(123_456L) );

assertThat(product.id()).isNotNull();
assertThat(product.name()).isEqualTo("제품명");
assertThat(product.image()).isEqualTo("test.jpg");
assertThat(product.price()).isEqualTo(new Money(123_456L));
}
}

0 comments on commit 6e9675e

Please sign in to comment.