코드 그라데이션

통합을 위한 작업 - 프로젝트 구조 본문

Spring/Thymeleaf

통합을 위한 작업 - 프로젝트 구조

완벽한 장면 2023. 11. 27. 03:08

재구조화 실시

프로젝트 디렉토리 구조

 

클래스

Item.java

@Data
@NoArgsConstructor
public class Item {

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


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

 

 

ItemRepository.java

@Repository // 인터페이스가 아니므로 붙인 듯. 안에 @Component 있음
public class ItemRepository {

    private static final Map<Long, Item> store = new HashMap<>();
    private static long sequence = 0L;

    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());
    }

    public void update(Long itemId, Item item) {
        Item findItem = findById(itemId);
        findItem.setItemName(item.getItemName());
        findItem.setPrice(item.getPrice());
        findItem.setQuantity(item.getQuantity());
    }

    public void clearStore() { // 테스트용 메서드
        store.clear();
    }

}

 

 

FormItemController.java

@Controller
@RequestMapping("/form/items")
@RequiredArgsConstructor
public class FormItemController {

    private final ItemRepository itemRepository;


    @GetMapping
    public String items(Model model) {
        // 상품 목록을 조회
        List<Item> items = itemRepository.findAll();
        // 조회한 상품 목록을 모델에 추가
        model.addAttribute("items", items);
        // "form/items" 뷰 템플릿을 호출하여 상품 목록을 화면에 표시
        return "form/items";
    }


    @GetMapping("/{itemId}")
    public String item(@PathVariable long itemId, Model model) {
        // 경로 변수로부터 받은 itemId를 사용하여 상품을 조회.
        Item item = itemRepository.findById(itemId);
        // 조회한 상품을 모델에 추가. 이후 뷰 템플릿에서 사용할 수 있다.
        model.addAttribute("item", item);
        // "form/item" 뷰 템플릿을 호출하여 상품 상세 정보를 화면에 표시.
        return "form/item";
    }


    @GetMapping("/add")
    public String addForm() {
        return "form/addForm";
    }


    /**
     * 상품을 추가하는 메서드.
     *
     * @param item               추가할 상품 정보를 나타내는 객체
     * @param redirectAttributes Spring MVC 리다이렉트 시 데이터를 전달하기 위한 객체
     * @return 상품 추가 후 해당 상품 상세 정보 페이지로 리다이렉트
     */
    @PostMapping("/add")
    public String addItem(Item item, RedirectAttributes redirectAttributes) {
        // 상품 정보를 데이터베이스에 저장하고 저장된 상품 정보를 반환.
        Item savedItem = itemRepository.save(item);

        // 리다이렉트 시 URL에 파라미터를 추가하기 위해 RedirectAttributes를 사용.
        // "itemId" 파라미터에 저장된 상품의 ID를 추가.
        redirectAttributes.addAttribute("itemId", savedItem.getId());

        // "status" 파라미터를 추가하고 값을 true로 설정. (예: 성공적으로 상품을 추가한 상태를 나타냄)
        redirectAttributes.addAttribute("status", true);

        // 상품 추가 후 해당 상품의 상세 정보 페이지로 리다이렉트.
        return "redirect:/form/items/{itemId}";
    }



    /**
     * 지정된 ID를 가진 아이템의 수정 폼을 표시한다.
     *
     * @param itemId 수정할 아이템의 ID
     * @param model 뷰에 데이터를 담기 위한 모델
     * @return 수정 폼 뷰의 이름
     */
    @GetMapping("/{itemId}/edit")
    public String editForm(@PathVariable Long itemId, Model model) {
        // 아이템 레포지토리에서 아이템을 ID를 사용하여 검색.
        Item item = itemRepository.findById(itemId);

        // 검색한 아이템을 모델에 추가하여 뷰에서 표시할 수 있도록 함.
        model.addAttribute("item", item);

        // 수정 폼 뷰의 이름을 반환.
        return "form/editForm";
    }


    /**
     * 상품을 수정하는 메서드.
     *
     * @param itemId 수정할 상품의 ID
     * @param item   수정된 상품 정보를 나타내는 객체
     * @return 상품 수정 후 해당 상품 상세 정보 페이지로 리다이렉트
     */
    @PostMapping("/{itemId}/edit")
    public String edit(@PathVariable Long itemId, @ModelAttribute Item item) {
        // 상품 수정 메서드를 호출하여 상품 정보를 업데이트 (itemRepository.update 메서드 사용)
        itemRepository.update(itemId, item);

        // 수정된 상품 정보를 포함하는 해당 상품의 상세 정보 페이지로 리다이렉트.
        return "redirect:/form/items/{itemId}";
    }

}

 

 

TestDataInit - 테스트용 데이터 클래스 분리

@Component
@RequiredArgsConstructor
public class TestDataInit {

    private final ItemRepository itemRepository;

    /**
     * 테스트용 데이터 추가
     */
    @PostConstruct
    public void init() {
        itemRepository.save(new Item("itemA", 10000, 10));
        itemRepository.save(new Item("itemB", 20000, 20));
    }

}

 


타임리프

addForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <!-- 부트스트랩 CSS 파일을 불러옵니다. -->
    <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet">
    <style>
        /* 스타일 정의: .container 클래스에 최대 너비를 설정합니다. */
        .container {
            max-width: 560px;
        }
    </style>
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <!-- 페이지 제목을 출력합니다. -->
        <h2>상품 등록 폼</h2>
    </div>

    <form action="item.html" th:action method="post">
        <div>
            <!-- 상품명 입력 필드와 레이블 -->
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" name="itemName" class="form-control" placeholder="이름을 입력하세요">
        </div>
        <div>
            <!-- 가격 입력 필드와 레이블 -->
            <label for="price">가격</label>
            <input type="text" id="price" name="price" class="form-control" placeholder="가격을 입력하세요">
        </div>
        <div>
            <!-- 수량 입력 필드와 레이블 -->
            <label for="quantity">수량</label>
            <input type="text" id="quantity" name="quantity" class="form-control" placeholder="수량을 입력하세요">
        </div>

        <hr class="my-4">

        <div class="row">
            <div class="col">
                <!-- 상품 등록 버튼 -->
                <button class="w-100 btn btn-primary btn-lg" type="submit">상품 등록</button>
            </div>
            <div class="col">
                <!-- 취소 버튼: 버튼 클릭 시 'items.html' 페이지로 이동합니다. -->
                <button class="w-100 btn btn-secondary btn-lg"
                        onclick="location.href='items.html'"
                        th:onclick="|location.href='@{/form/items}'|"
                        type="button">취소</button>
            </div>
        </div>

    </form>

</div> <!-- /container -->
</body>
</html>

 

editForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <!-- 부트스트랩 CSS 파일을 불러옵니다. -->
    <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet">
    <style>
        /* 스타일 정의: .container 클래스에 최대 너비를 설정합니다. */
        .container {
            max-width: 560px;
        }
    </style>
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <!-- 페이지 제목을 출력합니다. -->
        <h2>상품 수정 폼</h2>
    </div>

    <form action="item.html" th:action method="post">
        <div>
            <!-- 상품 ID 입력 필드와 레이블: 수정 불가능한 필드로 item.id 값을 출력합니다. -->
            <label for="id">상품 ID</label>
            <input type="text" id="id" name="id" class="form-control" value="1" th:value="${item.id}" readonly>
        </div>
        <div>
            <!-- 상품명 입력 필드와 레이블: 현재 상품명을 출력하고 수정 가능합니다. -->
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">
        </div>
        <div>
            <!-- 가격 입력 필드와 레이블: 현재 가격을 출력하고 수정 가능합니다. -->
            <label for="price">가격</label>
            <input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}">
        </div>
        <div>
            <!-- 수량 입력 필드와 레이블: 현재 수량을 출력하고 수정 가능합니다. -->
            <label for="quantity">수량</label>
            <input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}">
        </div>

        <hr class="my-4">

        <div class="row">
            <div class="col">
                <!-- 저장 버튼: 수정 내용을 저장하는 버튼 -->
                <button class="w-100 btn btn-primary btn-lg" type="submit">저장</button>
            </div>
            <div class="col">
                <!-- 취소 버튼: 버튼 클릭 시 이전 페이지로 돌아가는 버튼 -->
                <button class="w-100 btn btn-secondary btn-lg"
                        onclick="location.href='item.html'"
                        th:onclick="|location.href='@{/form/items/{itemId}(itemId=${item.id})}'|"
                        type="button">취소</button>
            </div>
        </div>

    </form>

</div> <!-- /container -->
</body>
</html>

 

 

item.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <!-- 부트스트랩 CSS 파일을 불러옵니다. -->
    <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet">
    <style>
        /* 스타일 정의: .container 클래스에 최대 너비를 설정합니다. */
        .container {
            max-width: 560px;
        }
    </style>
</head>
<body>

<div class="container">

    <div class="py-5 text-center">
        <!-- 페이지 제목을 출력합니다. -->
        <h2>상품 상세</h2>
    </div>

    <!-- 추가: 'status' 파라미터가 있으면 '저장 완료' 메시지를 표시합니다. -->
    <h2 th:if="${param.status}" th:text="'저장 완료'"></h2>

    <div>
        <!-- 상품 ID 출력 필드와 레이블: 수정 불가능한 필드로 item.id 값을 출력합니다. -->
        <label for="itemId">상품 ID</label>
        <input type="text" id="itemId" name="itemId" class="form-control" value="1" th:value="${item.id}" readonly>
    </div>
    <div>
        <!-- 상품명 출력 필드와 레이블: 수정 불가능한 필드로 현재 상품명을 출력합니다. -->
        <label for="itemName">상품명</label>
        <input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}" readonly>
    </div>
    <div>
        <!-- 가격 출력 필드와 레이블: 수정 불가능한 필드로 현재 가격을 출력합니다. -->
        <label for="price">가격</label>
        <input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}" readonly>
    </div>
    <div>
        <!-- 수량 출력 필드와 레이블: 수정 불가능한 필드로 현재 수량을 출력합니다. -->
        <label for="quantity">수량</label>
        <input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}" readonly>
    </div>

    <hr class="my-4">

    <div class="row">
        <div class="col">
            <!-- 상품 수정 버튼: 상품 수정 폼으로 이동합니다. -->
            <button class="w-100 btn btn-primary btn-lg"
                    onclick="location.href='editForm.html'"
                    th:onclick="|location.href='@{/form/items/{itemId}/edit(itemId=${item.id})}'|"
                    type="button">상품 수정</button>
        </div>
        <div class="col">
            <!-- 목록으로 버튼: 목록 페이지로 이동합니다. -->
            <button class="w-100 btn btn-secondary btn-lg"
                    onclick="location.href='items.html'"
                    th:onclick="|location.href='@{/form/items}'|"
                    type="button">목록으로</button>
        </div>
    </div>

</div> <!-- /container -->
</body>
</html>

 

 

items.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <!-- 부트스트랩 CSS 파일을 불러옵니다. -->
    <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container" style="max-width: 600px">
    <div class="py-5 text-center">
        <!-- 페이지 제목을 출력합니다. -->
        <h2>상품 목록</h2>
    </div>

    <div class="row">
        <div class="col">
            <!-- 상품 등록 버튼: 상품 등록 폼으로 이동합니다. -->
            <button class="btn btn-primary float-end"
                    onclick="location.href='addForm.html'"
                    th:onclick="|location.href='@{/form/items/add}'|"
                    type="button">상품 등록</button>
        </div>
    </div>

    <hr class="my-4">
    <div>
        <table class="table">
            <thead>
            <!-- 테이블 헤더 열 정의 -->
            <tr>
                <th>ID</th>
                <th>상품명</th>
                <th>가격</th>
                <th>수량</th>
            </tr>
            </thead>
            <tbody>
            <!-- 각 상품 항목을 나타내는 반복문 -->
            <tr th:each="item : ${items}">
                <!-- 상품 ID를 표시하고 해당 상품 상세 페이지로 링크합니다. -->
                <td><a href="item.html" th:href="@{/form/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
                <!-- 상품명을 표시하고 해당 상품 상세 페이지로 링크합니다. -->
                <td><a href="item.html" th:href="@{|/form/items/${item.id}|}" th:text="${item.itemName}">상품명</a></td>
                <!-- 상품 가격을 표시합니다. -->
                <td th:text="${item.price}">10000</td>
                <!-- 상품 수량을 표시합니다. -->
                <td th:text="${item.quantity}">10</td>
            </tr>
            </tbody>
        </table>
    </div>

</div> <!-- /container -->

</body>
</html>
728x90

'Spring > Thymeleaf' 카테고리의 다른 글

요구사항 (또) 추가  (0) 2023.11.30
Thymeleaf 통합 (1) 입력 폼 처리  (1) 2023.11.29
타임리프 스프링 통합  (1) 2023.11.26
Thymeleaf (15) 템플릿 레이아웃 02  (0) 2023.11.24
Thymeleaf (14) 템플릿 레이아웃 01  (0) 2023.11.21
Comments