From 415a8e4c20e8097e501a8790af6ecc432d9f2f6d Mon Sep 17 00:00:00 2001 From: silverchaeJ Date: Wed, 24 Jul 2024 17:56:27 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=86=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 + .../springintro/aop/TimeTraceAop.java | 26 +++ .../controller/HomeController.java | 11 ++ .../controller/ItemController.java | 48 +++++ .../controller/ItemCreateForm.java | 25 +++ .../controller/MemberController.java | 46 +++++ .../controller/MemberCreateForm.java | 26 +++ .../landvibe/springintro/domain/Item.java | 51 ++++++ .../landvibe/springintro/item/ItemConfig.java | 31 ++++ .../repository/ItemRepository.java | 11 ++ .../repository/JdbcItemReposity.java | 169 ++++++++++++++++++ .../JdbcTemplateItemRepository.java | 59 ++++++ .../repository/JpaItemReposity.java | 35 ++++ .../repository/MemoryItemRepository.java | 36 ++++ .../SpringDataJpaItemRepository.java | 10 ++ .../springintro/service/ItemService.java | 67 +++++++ .../springintro/service/MemberService.java | 64 +++++++ src/main/resources/application.properties | 12 ++ .../resources/templates/fragments/header.html | 5 + src/main/resources/templates/home.html | 26 ++- .../repository/MemoryItemRepositoryTest.java | 52 ++++++ .../service/ItemServiceIntegrationTest.java | 54 ++++++ .../springintro/service/ItemServiceTest.java | 59 ++++++ 23 files changed, 912 insertions(+), 14 deletions(-) create mode 100644 src/main/java/landvibe/springintro/aop/TimeTraceAop.java create mode 100644 src/main/java/landvibe/springintro/controller/HomeController.java create mode 100644 src/main/java/landvibe/springintro/controller/ItemController.java create mode 100644 src/main/java/landvibe/springintro/controller/ItemCreateForm.java create mode 100644 src/main/java/landvibe/springintro/controller/MemberController.java create mode 100644 src/main/java/landvibe/springintro/controller/MemberCreateForm.java create mode 100644 src/main/java/landvibe/springintro/domain/Item.java create mode 100644 src/main/java/landvibe/springintro/item/ItemConfig.java create mode 100644 src/main/java/landvibe/springintro/repository/ItemRepository.java create mode 100644 src/main/java/landvibe/springintro/repository/JdbcItemReposity.java create mode 100644 src/main/java/landvibe/springintro/repository/JdbcTemplateItemRepository.java create mode 100644 src/main/java/landvibe/springintro/repository/JpaItemReposity.java create mode 100644 src/main/java/landvibe/springintro/repository/MemoryItemRepository.java create mode 100644 src/main/java/landvibe/springintro/repository/SpringDataJpaItemRepository.java create mode 100644 src/main/java/landvibe/springintro/service/ItemService.java create mode 100644 src/main/java/landvibe/springintro/service/MemberService.java create mode 100644 src/test/java/landvibe/springintro/repository/MemoryItemRepositoryTest.java create mode 100644 src/test/java/landvibe/springintro/service/ItemServiceIntegrationTest.java create mode 100644 src/test/java/landvibe/springintro/service/ItemServiceTest.java diff --git a/build.gradle b/build.gradle index 07d2578..36d7b8c 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,9 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + runtimeOnly 'com.h2database:h2' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' diff --git a/src/main/java/landvibe/springintro/aop/TimeTraceAop.java b/src/main/java/landvibe/springintro/aop/TimeTraceAop.java new file mode 100644 index 0000000..fcd2b2d --- /dev/null +++ b/src/main/java/landvibe/springintro/aop/TimeTraceAop.java @@ -0,0 +1,26 @@ +package landvibe.springintro.aop; + + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; +@Component +@Aspect + +public class TimeTraceAop { + @Around("execution(* landvibe.springintro..*(..))") + public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { + long start = System.currentTimeMillis(); + System.out.println("START : " + joinPoint.toString()); // 어떤 메소드를 call + try { + return joinPoint.proceed(); // 다음 메소드가 진행 + } + finally { + long finish = System.currentTimeMillis(); + long timeMs = finish - start; + System.out.println("END : " + joinPoint.toString() + " " + timeMs + + "ms"); // 어떤 메소드를 call 했는지 + } + } +} diff --git a/src/main/java/landvibe/springintro/controller/HomeController.java b/src/main/java/landvibe/springintro/controller/HomeController.java new file mode 100644 index 0000000..80a6bd3 --- /dev/null +++ b/src/main/java/landvibe/springintro/controller/HomeController.java @@ -0,0 +1,11 @@ +package landvibe.springintro.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +@Controller +public class HomeController { + @GetMapping("/") + public String home() { + return "home"; + } +} diff --git a/src/main/java/landvibe/springintro/controller/ItemController.java b/src/main/java/landvibe/springintro/controller/ItemController.java new file mode 100644 index 0000000..2423e74 --- /dev/null +++ b/src/main/java/landvibe/springintro/controller/ItemController.java @@ -0,0 +1,48 @@ +package landvibe.springintro.controller; + +import landvibe.springintro.domain.Item; +import landvibe.springintro.service.ItemService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; + +import java.util.List; + + +@Controller +public class ItemController { + private final ItemService itemService; + + @Autowired + public ItemController(ItemService itemService) { + this.itemService = itemService; + } + + @GetMapping("/items/new") + public String createForm(){ + return "items/createForm"; + } + + + + @PostMapping("/items/new") + public String create(@ModelAttribute ItemCreateForm form) { + Item item = new Item(); + item.setName(form.getName()); + item.setPrice(form.getPrice()); + item.setCount(form.getCount()); + itemService.create(item); + return "redirect:/"; + } + + @GetMapping("/items") + public String list(Model model){ + List items = itemService.findItems(); + model.addAttribute("items", items); + return "items/itemList"; + } + +} diff --git a/src/main/java/landvibe/springintro/controller/ItemCreateForm.java b/src/main/java/landvibe/springintro/controller/ItemCreateForm.java new file mode 100644 index 0000000..7ae7f57 --- /dev/null +++ b/src/main/java/landvibe/springintro/controller/ItemCreateForm.java @@ -0,0 +1,25 @@ +package landvibe.springintro.controller; + +public class ItemCreateForm { + private String name; + private Integer price; + private Integer count; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Integer getPrice() { + return price; + } + public void setPrice(Integer price) { + this.price = price; + } + public Integer getCount() { + return count; + } + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/landvibe/springintro/controller/MemberController.java b/src/main/java/landvibe/springintro/controller/MemberController.java new file mode 100644 index 0000000..0d78c87 --- /dev/null +++ b/src/main/java/landvibe/springintro/controller/MemberController.java @@ -0,0 +1,46 @@ +package landvibe.springintro.controller; + +import landvibe.springintro.domain.Item; +import landvibe.springintro.service.ItemService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; + +import java.util.List; + +public class MemberController { + + private final ItemService itemService; + + @Autowired + public MemberController(ItemService itemService) { + this.itemService = itemService; + } + + @GetMapping("/members/new") + public String createForm(){ + return "members/createMemberForm"; + } + + + + @PostMapping("/members/new") + public String create(@ModelAttribute MemberCreateForm form) { + Item item = new Item(); + item.setName(form.getName()); + item.setName(form.getId()); + item.setPw(form.getPw()); + itemService.create(item); + return "redirect:/"; + } + + @GetMapping("/members") + public String memberlist(Model model){ + List members = itemService.findMembers(); + model.addAttribute("members", members); + return "members/memberList"; + } + +} diff --git a/src/main/java/landvibe/springintro/controller/MemberCreateForm.java b/src/main/java/landvibe/springintro/controller/MemberCreateForm.java new file mode 100644 index 0000000..a646ecd --- /dev/null +++ b/src/main/java/landvibe/springintro/controller/MemberCreateForm.java @@ -0,0 +1,26 @@ +package landvibe.springintro.controller; + +public class MemberCreateForm { + private String id; + private String pw; + private String name; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getId(){ + return id; + } + public void setId(String id){ + this.id=id; + } + public String getPw(){ + return pw; + } + public void setPw(String pw){ + this.pw=pw; + } + +} diff --git a/src/main/java/landvibe/springintro/domain/Item.java b/src/main/java/landvibe/springintro/domain/Item.java new file mode 100644 index 0000000..f845c3f --- /dev/null +++ b/src/main/java/landvibe/springintro/domain/Item.java @@ -0,0 +1,51 @@ +package landvibe.springintro.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +@Entity +public class Item { + + + @Id + @GeneratedValue + private Long id; + private String pw; + private String name; + private Integer price; + private Integer count; + public long getId() { + return id; + } + public String getPw(){ + return pw; + } + public void setPw(String pw){ + this.pw=pw; + } + + + + public void setId(Long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Integer getPrice() { + return price; + } + public void setPrice(Integer price) { + this.price = price; + } + public Integer getCount() { + return count; + } + public void setCount(Integer count) { + this.count = count; + } + } diff --git a/src/main/java/landvibe/springintro/item/ItemConfig.java b/src/main/java/landvibe/springintro/item/ItemConfig.java new file mode 100644 index 0000000..2b060ae --- /dev/null +++ b/src/main/java/landvibe/springintro/item/ItemConfig.java @@ -0,0 +1,31 @@ +package landvibe.springintro.item; + +import landvibe.springintro.repository.ItemRepository; +import landvibe.springintro.service.ItemService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ItemConfig { + /* private final DataSource dataSource; + + private final EntityManager em; + + @Autowired + public ItemConfig(DataSource dataSource,EntityManager em) { + this.dataSource = dataSource; + this.em=em; + }*/ + private final ItemRepository itemRepository; + public ItemConfig(ItemRepository itemRepository) { + this.itemRepository = itemRepository; + } + @Bean + public ItemService itemService() { + return new ItemService(itemRepository); + } + /* @Bean + public ItemRepository itemRepository() { + return new JpaItemReposity(em); + }*/ +} \ No newline at end of file diff --git a/src/main/java/landvibe/springintro/repository/ItemRepository.java b/src/main/java/landvibe/springintro/repository/ItemRepository.java new file mode 100644 index 0000000..be0aca4 --- /dev/null +++ b/src/main/java/landvibe/springintro/repository/ItemRepository.java @@ -0,0 +1,11 @@ +package landvibe.springintro.repository; + +import landvibe.springintro.domain.Item; +import java.util.List; +import java.util.Optional; +public interface ItemRepository { + Item save(Item item); + Optional findById(Long id); + Optional findByName(String name); + List findAll(); +} \ No newline at end of file diff --git a/src/main/java/landvibe/springintro/repository/JdbcItemReposity.java b/src/main/java/landvibe/springintro/repository/JdbcItemReposity.java new file mode 100644 index 0000000..3f3ba37 --- /dev/null +++ b/src/main/java/landvibe/springintro/repository/JdbcItemReposity.java @@ -0,0 +1,169 @@ +package landvibe.springintro.repository; + + + +import landvibe.springintro.domain.Item; +import javax.sql.DataSource; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.springframework.jdbc.datasource.DataSourceUtils; + + class JdbcItemRepository implements ItemRepository { + private final DataSource dataSource; + + public JdbcItemRepository(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public Item save(Item item) { + String sql = "insert into item(name, price, count) values(?, ?, ?)"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + pstmt.setString(1, item.getName()); + pstmt.setInt(2, item.getPrice()); + pstmt.setInt(3, item.getCount()); + pstmt.executeUpdate(); + rs = pstmt.getGeneratedKeys(); + + if (rs.next()) { + item.setId(rs.getLong(1)); + } else { + throw new SQLException("id 조회 실패"); + } + return item; + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + close(conn, pstmt, rs); + } + } + + @Override + public Optional findById(Long id) { + String sql = "select * from item where id = ?"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + pstmt.setLong(1, id); + rs = pstmt.executeQuery(); + + if (rs.next()) { + Item item = new Item(); + item.setId(rs.getLong("id")); + item.setName(rs.getString("name")); + item.setCount(rs.getInt("count")); + item.setPrice(rs.getInt("price")); + return Optional.of(item); + } else { + return Optional.empty(); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + close(conn, pstmt, rs); + } + } + + @Override + public Optional findByName(String name) { + String sql = "select * from item where name = ?"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + pstmt.setString(1, name); + rs = pstmt.executeQuery(); + + if (rs.next()) { + Item item = new Item(); + item.setId(rs.getLong("id")); + item.setName(rs.getString("name")); + item.setCount(rs.getInt("count")); + item.setPrice(rs.getInt("price")); + return Optional.of(item); + } else { + return Optional.empty(); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + close(conn, pstmt, rs); + } + } + + @Override + public List findAll() { + String sql = "select * from item"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + rs = pstmt.executeQuery(); + List items = new ArrayList<>(); + + while (rs.next()) { + Item item = new Item(); + item.setId(rs.getLong("id")); + item.setName(rs.getString("name")); + item.setCount(rs.getInt("count")); + item.setPrice(rs.getInt("price")); + items.add(item); + } + return items; + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + close(conn, pstmt, rs); + } + } + + private Connection getConnection() { + return DataSourceUtils.getConnection(dataSource); + } + + private void close(Connection conn, PreparedStatement pstmt, ResultSet rs) { + try { + if (rs != null) { + rs.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + try { + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + try { + if (conn != null) { + close(conn); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private void close(Connection conn) throws SQLException { + DataSourceUtils.releaseConnection(conn, dataSource); + } +} diff --git a/src/main/java/landvibe/springintro/repository/JdbcTemplateItemRepository.java b/src/main/java/landvibe/springintro/repository/JdbcTemplateItemRepository.java new file mode 100644 index 0000000..c0245c7 --- /dev/null +++ b/src/main/java/landvibe/springintro/repository/JdbcTemplateItemRepository.java @@ -0,0 +1,59 @@ +package landvibe.springintro.repository; + +import landvibe.springintro.domain.Item; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + + public class JdbcTemplateItemRepository implements ItemRepository { + private final JdbcTemplate jdbcTemplate; + @Autowired + public JdbcTemplateItemRepository(DataSource dataSource) { + jdbcTemplate = new JdbcTemplate(dataSource); + } + @Override + public Item save(Item item) { + SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate); + jdbcInsert.withTableName("item").usingGeneratedKeyColumns("id"); + Map parameters = new HashMap<>(); + parameters.put("name", item.getName()); + parameters.put("count", item.getCount()); + parameters.put("price", item.getPrice()); + Number key = jdbcInsert.executeAndReturnKey(new + MapSqlParameterSource(parameters)); + item.setId(key.longValue()); + return item; + } + @Override + public Optional findById(Long id) { + List result = jdbcTemplate.query("select * from item where id = ?", rowMapper(), id); + return result.stream().findAny(); + } + @Override + public Optional findByName(String name) { + List result = jdbcTemplate.query("select * from item where name = ? ", rowMapper(), name); + return result.stream().findAny(); + } + @Override + public List findAll() { + return jdbcTemplate.query("select * from item", rowMapper()); + } + private RowMapper rowMapper() { + return (rs, rowNum) -> { + Item item = new Item(); + item.setId(rs.getLong("id")); + item.setName(rs.getString("name")); + item.setPrice(rs.getInt("price")); + item.setCount(rs.getInt("count")); + return item; + }; + } + } + diff --git a/src/main/java/landvibe/springintro/repository/JpaItemReposity.java b/src/main/java/landvibe/springintro/repository/JpaItemReposity.java new file mode 100644 index 0000000..f3c5153 --- /dev/null +++ b/src/main/java/landvibe/springintro/repository/JpaItemReposity.java @@ -0,0 +1,35 @@ +package landvibe.springintro.repository; +import jakarta.persistence.EntityManager; +import landvibe.springintro.domain.Item; +import java.util.List; +import java.util.Optional; + +public class JpaItemReposity implements ItemRepository { + private final EntityManager em; + public JpaItemReposity(EntityManager em) { + this.em = em; + } + @Override + public Item save(Item item) { + em.persist(item); + return item; + } + @Override + public Optional findById(Long id) { + Item item = em.find(Item.class, id); + return Optional.ofNullable(item); + } + @Override + public Optional findByName(String name) { + return em.createQuery("select i from Item i where i.name = :name", + Item.class) + .setParameter("name", name) + .getResultStream() + .findAny(); + } + @Override + public List findAll() { + return em.createQuery("select i from Item i", Item.class) + .getResultList(); + } +} diff --git a/src/main/java/landvibe/springintro/repository/MemoryItemRepository.java b/src/main/java/landvibe/springintro/repository/MemoryItemRepository.java new file mode 100644 index 0000000..22d131f --- /dev/null +++ b/src/main/java/landvibe/springintro/repository/MemoryItemRepository.java @@ -0,0 +1,36 @@ +package landvibe.springintro.repository; + + +import landvibe.springintro.domain.Item; +import org.springframework.stereotype.Repository; + +import java.util.*; + +public class MemoryItemRepository implements ItemRepository { + private static Map store = new HashMap<>(); + private static long sequence = 0L; + @Override + public Item save(Item item) { + item.setId(++sequence); + store.put(item.getId(), item); + return item; + } + @Override + public Optional findById(Long id) { + Item item = store.get(id); + return Optional.ofNullable(item); + } + @Override + public Optional findByName(String name) { + return store.values().stream() + .filter(item -> item.getName().equals(name)) + .findAny(); + } + @Override + public List findAll() { + return new ArrayList<>(store.values()); + } + public void clearStore() { + store.clear(); + } +} diff --git a/src/main/java/landvibe/springintro/repository/SpringDataJpaItemRepository.java b/src/main/java/landvibe/springintro/repository/SpringDataJpaItemRepository.java new file mode 100644 index 0000000..aa44720 --- /dev/null +++ b/src/main/java/landvibe/springintro/repository/SpringDataJpaItemRepository.java @@ -0,0 +1,10 @@ +package landvibe.springintro.repository; +import landvibe.springintro.domain.Item; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + +public interface SpringDataJpaItemRepository extends JpaRepository, + ItemRepository { + @Override + Optional findByName(String name); +} \ No newline at end of file diff --git a/src/main/java/landvibe/springintro/service/ItemService.java b/src/main/java/landvibe/springintro/service/ItemService.java new file mode 100644 index 0000000..0adc1cc --- /dev/null +++ b/src/main/java/landvibe/springintro/service/ItemService.java @@ -0,0 +1,67 @@ +package landvibe.springintro.service; + +import jakarta.transaction.Transactional; +import landvibe.springintro.domain.Item; +import landvibe.springintro.repository.ItemRepository; + +import java.util.List; +@Transactional +public class ItemService { + + private final ItemRepository repository; + + + public ItemService(ItemRepository repository) { + this.repository = repository; + } + + public Long create(Item item) { + long start = System.currentTimeMillis(); + try { + validateDuplicateItem(item.getName()); + repository.save(item); + return item.getId(); + }finally { + long end= System.currentTimeMillis(); + long timeMs=end-start; + System.out.println("create::timeMs = "+ timeMs); + } + + } + + + + /** + * + 상품 전체조회 + */ + public List findItems() { + + long start = System.currentTimeMillis(); + try { + return repository.findAll(); + }finally { + long end= System.currentTimeMillis(); + long timeMs=end-start; + System.out.println("create::timeMs = "+ timeMs); + } + } + + public List findMembers(){ + long start = System.currentTimeMillis(); + try { + return repository.findAll(); + }finally { + long end= System.currentTimeMillis(); + long timeMs=end-start; + System.out.println("create::timeMs = "+ timeMs); + } + } + + private void validateDuplicateItem(String itemName) { + repository.findByName(itemName) + .ifPresent(i -> { + throw new IllegalArgumentException("이미 존재하는 상품입니다."); + }); + } + } diff --git a/src/main/java/landvibe/springintro/service/MemberService.java b/src/main/java/landvibe/springintro/service/MemberService.java new file mode 100644 index 0000000..a10a4f6 --- /dev/null +++ b/src/main/java/landvibe/springintro/service/MemberService.java @@ -0,0 +1,64 @@ +package landvibe.springintro.service; + +import jakarta.transaction.Transactional; +import landvibe.springintro.domain.Item; +import landvibe.springintro.repository.ItemRepository; + +import java.util.List; +@Transactional +public class MemberService { + + private final ItemRepository repository; + + + public MemberService(ItemRepository repository) { + this.repository = repository; + } + + public Long create(Item item) { + long start = System.currentTimeMillis(); + try { + validateDuplicateItem(item.getName()); + repository.save(item); + return item.getId(); + }finally { + long end= System.currentTimeMillis(); + long timeMs=end-start; + System.out.println("create::timeMs = "+ timeMs); + } + + } + + + + + public List findItems() { + + long start = System.currentTimeMillis(); + try { + return repository.findAll(); + }finally { + long end= System.currentTimeMillis(); + long timeMs=end-start; + System.out.println("create::timeMs = "+ timeMs); + } + } + + public List findMembers(){ + long start = System.currentTimeMillis(); + try { + return repository.findAll(); + }finally { + long end= System.currentTimeMillis(); + long timeMs=end-start; + System.out.println("create::timeMs = "+ timeMs); + } + } + + private void validateDuplicateItem(String itemName) { + repository.findByName(itemName) + .ifPresent(i -> { + throw new IllegalArgumentException("이미 존재하는 상품입니다."); + }); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e7c1e8f..3064dbe 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,13 @@ spring.application.name=springintro +spring: +datasource: +url: jdbc:h2:tcp://localhost/~/test +driver-class-name: org.h2.Driver +username: sa +jpa: +show-sql: true +hibernate: +ddl-auto: none + +spring.thymeleaf.prefix=classpath:/templates/ +spring.thymeleaf.suffix=.html diff --git a/src/main/resources/templates/fragments/header.html b/src/main/resources/templates/fragments/header.html index 33dff78..288c4ab 100755 --- a/src/main/resources/templates/fragments/header.html +++ b/src/main/resources/templates/fragments/header.html @@ -11,5 +11,10 @@ + + + + + LANDVIBE diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 9702794..25b6515 100755 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -4,35 +4,33 @@ LANDVIBE - -
-
-

LANDVIBE SHOP

회원 기능

회원 가입 - 회원 목록 + 회원 목록

-

상품 기능

-

- 상품 등록 - 상품 목록 -

-

주문 기능

+

상품 기능

+

+ + 상품 등록 + 상품 목록 +

주문 기능

+ 상품 주문 주문 내역

-
+
-
+
- + + \ No newline at end of file diff --git a/src/test/java/landvibe/springintro/repository/MemoryItemRepositoryTest.java b/src/test/java/landvibe/springintro/repository/MemoryItemRepositoryTest.java new file mode 100644 index 0000000..6f9b04f --- /dev/null +++ b/src/test/java/landvibe/springintro/repository/MemoryItemRepositoryTest.java @@ -0,0 +1,52 @@ +package landvibe.springintro.repository; + +import landvibe.springintro.domain.Item; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import java.util.List; +import static org.assertj.core.api.Assertions.*; + +public class MemoryItemRepositoryTest { + MemoryItemRepository repository = new MemoryItemRepository(); + @Test + void save() { + // given + Item item = createItem("과자", 10, 1000); + // when + repository.save(item); + // then + Item foundItem = repository.findById(item.getId()).get(); + assertThat(foundItem).isEqualTo(item); + } + @Test + void findByName() { + // given + Item 눈을감자 = createItem("눈을감자", 10, 1000); + Item 프링글스 = createItem("프링글스", 10, 1000); + repository.save(눈을감자); + repository.save(프링글스); + // when + Item foundItem = repository.findByName("눈을감자").get(); + // then + assertThat(foundItem).isEqualTo(눈을감자); + } @Test + void findAll() { + // given + Item 눈을감자 = createItem("눈을감자", 10, 1000); + Item 프링글스 = createItem("프링글스", 10, 1000); + repository.save(눈을감자); + repository.save(프링글스); + // when + List foundItems = repository.findAll(); + // then + assertThat(foundItems.size()).isEqualTo(2); + assertThat(foundItems).contains(눈을감자, 프링글스); + } + private static Item createItem(String name, int count, int price) { + Item item = new Item(); + item.setName(name); + item.setCount(count); + item.setPrice(price); + return item; + } + } diff --git a/src/test/java/landvibe/springintro/service/ItemServiceIntegrationTest.java b/src/test/java/landvibe/springintro/service/ItemServiceIntegrationTest.java new file mode 100644 index 0000000..6ff75d7 --- /dev/null +++ b/src/test/java/landvibe/springintro/service/ItemServiceIntegrationTest.java @@ -0,0 +1,54 @@ +package landvibe.springintro.service; + + +import landvibe.springintro.domain.Item; +import landvibe.springintro.repository.ItemRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +@SpringBootTest +@Transactional + +public class ItemServiceIntegrationTest { + + @Autowired + ItemService service; + @Autowired + ItemRepository repository; + @Test + public void 상품생성() throws Exception { + // given + Item item = createItem("눈을감자", 10, 1000); + // when + Long id = service.create(item); + // then + Item foundItem = repository.findById(id).get(); + assertThat(foundItem.getName()).isEqualTo(item.getName()); + assertThat(foundItem.getPrice()).isEqualTo(item.getPrice()); + assertThat(foundItem.getCount()).isEqualTo(item.getCount()); + } + @Test + void 중복이름_상품예외() { + // given + Item item = createItem("눈을감자", 10, 1000); + Item duplicatedItem = createItem("눈을감자", 10, 1000); + service.create(item); + // when & then + IllegalArgumentException ex = + assertThrows(IllegalArgumentException.class, + () -> service.create(duplicatedItem));// 예외 발생 + assertThat(ex.getMessage()).isEqualTo("이미 존재하는 상품입니다."); + } + private static Item createItem(String name, int count, int price) { + Item item = new Item(); + item.setName(name); + item.setCount(count); + item.setPrice(price); + return item; + } +} + + diff --git a/src/test/java/landvibe/springintro/service/ItemServiceTest.java b/src/test/java/landvibe/springintro/service/ItemServiceTest.java new file mode 100644 index 0000000..c633b2a --- /dev/null +++ b/src/test/java/landvibe/springintro/service/ItemServiceTest.java @@ -0,0 +1,59 @@ +package landvibe.springintro.service; + +import landvibe.springintro.domain.Item; +import landvibe.springintro.repository.ItemRepository; +import landvibe.springintro.repository.MemoryItemRepository; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.util.Optional; +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; +class ItemServiceTest { + ItemService service; + MemoryItemRepository repository; + + @BeforeEach + void setUp() { + repository = new MemoryItemRepository(); + service = new ItemService(repository); + } + + @AfterEach + void tearDown() { + repository.clearStore(); + } + + @Test + public void 상품생성() throws Exception { + // given + Item item = createItem("눈을감자", 10, 1000); + // when + Long id = service.create(item); + // then + Item foundItem = repository.findById(id).get(); + assertThat(foundItem).isEqualTo(item); + } + + @Test + void 중복이름_상품예외() { + // given + Item item = createItem("눈을감자", 10, 1000); + Item duplicatedItem = createItem("눈을감자", 10, 1000); + service.create(item); + // when & then + IllegalArgumentException ex = + assertThrows(IllegalArgumentException.class, + () -> service.create(duplicatedItem));// 예외 발생 + assertThat(ex.getMessage()).isEqualTo("이미 존재하는 상품입니다."); + } + + private static Item createItem(String name, int count, int price) { + Item item = new Item(); + item.setName(name); + item.setCount(count); + item.setPrice(price); + return item; + } +}