Spring/SpringMVC

스프링MVC 프로젝트 - 도메인 개발 & 상품 서비스 HTML

느리지만 꾸준하게 2022. 5. 3. 02:22

계속해서 만들던 대로 프로젝트를 여기서 생성하자.

 

실행해보면 잘 나온다.

// ItemServiceApplication

package hello.itemservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ItemServiceApplication {

   public static void main(String[] args) {
      SpringApplication.run(ItemServiceApplication.class, args);
   }

}

 

 

이제 welcome page를 추가하고 생성해보면 잘나온다.

// index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    <li>상품 관리
        <ul>
            <li><a href="/basic/items">상품 관리 - 기본</a></li>
        </ul>
    </li>
</ul>
</body>
</html>

 

 

 

 

 

요구사항 분석을 보면

  • 상품 도메인 모델
  • 상품 관리 기능

 

이렇게 두 가지가 있다.

 

 

상품 도메인 모델

  • 상품 ID
  • 상품명
  • 가격
  • 수량

 

상품 관리 기능

  • 상품 등록
  • 상품 상세
  • 상품 등록
  • 상품 수정

 

서비스 제공 흐름은 아래와 같다. 

 

컨트롤로 뷰를 구분해서 흐름을 파악해보자. 상품 상세 뷰 같은 경우는 상품 상세 컨트롤러와 상품 저장 컨트롤러 두개가 상품 상세 뷰를 호출해준다.

 

컨트롤러

  • 상품 목록
  • 상품 등록 폼
  • 상품 상세
  • 상품 수정 폼
  • 상품 저장(내부 호출)
  • 상품 수정(Redirect)

 

  • 상품 목록
  • 상품 등록 폼
  • 상품 상세
  • 상품 수정 폼

 

 

이제 도메인을 개발해보자.  

 

@Data를 쓰면 핵심 도메인 상황에서는 굉장히 위험하다.

지금 프로젝트에선 @Data를 쓰고 나중에는 @Getter @Setter을 쓰자.

package hello.itemservice.domain.item;

import lombok.Data;

@Data
public class Item {

    private Long id;
    private String itemName;
    private Integer price;
    private Integer quantity;

    public Item() {
    }

    public Item(String itemName, Integer price, Integer quantity) {
        this.itemName = itemName;
        this.price = price;
        this.quantity = quantity;
    }
}

 

 

 

 

ItemRepository도 만들어주자.

 

package hello.itemservice.domain.item;

import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


// 컴포넌트 스캔이 내장이 되어있다.
@Repository
public class ItemRepository {

    // 멀티 쓰레드 환경에서 여러개가 동시에 store에 접근하게 되면 HashMap 쓰면 안되고 ConcurrentHashMap을 써야한다.
    // 싱글톤으로 생성되기 때문에
    private static final Map<Long, Item> store = new HashMap<>(); // static

    // 얘도 Long해서 쓰면 안된다. 값이 꼬일 수 있기 때문에 일단 지금은 간단한 프로젝트이니 쓰자.
    private static Long sequence = 0L; // static

    public Item save(Item item) {
        item.setId(++sequence);
        store.put(item.getId(), item);
        return item;
    }

    public Item findById(Long id) {
        return store.get(id);
    }

    public List<Item> findAll() {
        return new ArrayList<>(store.values());
    }


    // 프로젝트 규모가 커지면 ItemParameterDto만드는게 깔끔하다.
    public void update(Long itemId, Item updateParam) {
        Item findItem = findById(itemId);
        findItem.setItemName(updateParam.getItemName());
        findItem.setPrice(updateParam.getPrice());
        findItem.setQuantity(updateParam.getQuantity());
    }

    public void clearStore() {
        store.clear();
    }
}

 

 

테스트 코드 ItemRepositoryTest도 만들어주자.

package hello.itemservice.domain.item;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

class ItemRepositoryTest {
    ItemRepository itemRepository = new ItemRepository();

    @AfterEach
    void afterEach() {
        itemRepository.clearStore();
    }

    @Test
    void save() {
        // given
        Item item = new Item("itemA", 10000, 10);

        // when
        Item savedItem = itemRepository.save(item);

        // then
        Item findItem = itemRepository.findById(item.getId());
        assertThat(findItem).isEqualTo(savedItem);
    }

    @Test
    void findAll() {
        // given
        Item item1 = new Item("item1", 10000, 10);
        Item item2 = new Item("item2", 20000, 20);

        itemRepository.save(item1);
        itemRepository.save(item2);

        // when
        List<Item> result = itemRepository.findAll();

        // then
        assertThat(result.size()).isEqualTo(2);
        assertThat(result).contains(item1, item2);


    }

    @Test
    void updateItem() {
        // given
        Item item = new Item("item1", 10000, 10);

        Item savedItem = itemRepository.save(item);
        Long itemId = savedItem.getId();

        // when
        Item updateParam = new Item("item2", 20000, 30);
        itemRepository.update(itemId, updateParam);

        // then
        Item findItem = itemRepository.findById(itemId);

        assertThat(findItem.getItemName()).isEqualTo(updateParam.getItemName());
        assertThat(findItem.getPrice()).isEqualTo(updateParam.getPrice());
        assertThat(findItem.getQuantity()).isEqualTo(updateParam.getQuantity());
    }
}

 

 

상품 서비스 HTML 파트는 부트스트랩을 이용해서 만들어 보자.

여기서 bootstrap.min.css 파일을 열어서 아래 경로와 같이 복사해주고 

 

 

 

http://localhost:8080/css/bootstrap.min.css 이 경로로 들어가보자. 잘 나오는 것을 확인할 수 있다.

 

 

 

html 파일들도 다 넣어주자. 

 

 

파일의 절대경로로 들어가도 잘 열리고 서버 실행하고 열어도 잘 열린다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 스프링 MVC 1편 - 벡앤드 웹 개발 핵심 기술>

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com