부트스트랩 사용하기

웹 사이트를 쉽게 만들어주는 틀 같은 것

 

 

 

1. 아래 URL에 접속하여 css 파일을 다운받고 압축풀어서 bootstrap.min.css 를 복사한다. 

https://getbootstrap.com/docs/5.0/getting-started/download/

 

2. 그리고 resources/static/css/bootstrap.min.css 폴더에 추가해보자 

 

 

3. 실행 후 http://localhost:8080/css/bootstrap.min.css 접속했을때 나오면 정상작동!

 

 

 

/resources/static 에 넣으면 스프링 부트가 정적 리소스를 제공한다 

 

주의!

정적리소스인 /resources/static 에 html을 넣어두면 모두 공개된다 실제 서비스도 공개되기때문에 

공개할 필요가 없는 html 을 저장하는것을 주의해야한다 

 

 

 

 

정적 리소스 - 상품 목록 HTML

resources/static/html/items.html

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <link 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'" 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>
                <td><a href="item.html">1</a></td>
                <td><a href="item.html">테스트 상품1</a></td>
                <td>10000</td>
                <td>10</td>
            </tr>
            <tr>
                <td><a href="item.html">2</a></td>
                <td><a href="item.html">테스트 상품2</a></td>
                <td>20000</td>
                <td>20</td>
            </tr>
            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

 

 

 

 

 

정직 리소스를 사용하면 노출 위험이 있으니 보안과 동적 콘텐츠 생성할 수 있는 컨트롤러와 뷰 템플릿으로 개발해보자 

 

뷰 템플릿? 

HTML 과 비슷하지만 서버 측에서 동적으로 생성되며 클라이언트에게 전달된다. 
그러므로 클라이언트에게 전달하기 전에 템플릿을 처리하여 필요한 데이터를 삽입해준다
위치는 주로 /resources/templates 에 위치한다. 

 

 

 

items.html 정적 HTML을 뷰 템플릿(templates) 영역으로 복사하기

/resources/static/items.html → 복사 → /resources/templates/basic/items.html

 

 

 

 


 

 

컨트롤러 의존성 주입(Dependency Injection) 간편화하기

 

 

[ BasicItemController ]

@Controller
@RequestMapping("/basic/items")
public class BasicItemController {

    private final ItemRepository itemRepository;
    
    //생성자
    @Autowired
    public BasicItemController(ItemRepository itemRepository){
    	this.itemRepository = itemRepository;
    }
    
}

 

 

@Autowired
public BasicItemController(ItemRepository itemRepository){
    this.itemRepository = itemRepository;
}
  • 스프링에서 해당 생성자가 @Autowired 로 의존관계를 주입해주는데 생성자가 하나밖에 없으면 @Autowired를 생략가능하다 
  • @RequiredArgsConstructor
    • final 이 붙은 멤버변수만 사용해서 생성자를 자동으로 만들어주는 어노테이션
  • 따라서 private final ItemRepository itemRepository; 에 final을 지우면 안된다 그럼 itemRepository 의존관계가 주입이 안되기 때문

 

 

간결해진 [ BasicItemController ] 

@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {

    private final ItemRepository itemRepository;
}

 

 

 


 

이제 컨트롤러와 뷰 템플릿을 개발하기

 

 

1. 상품목록 - 타임리프

컨트롤러  [ BasicItemController ] 

@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {

    private final ItemRepository itemRepository;
    
    @GetMapping
    public String items(Model model) {
    	List<Item> items = itemRepository.findAll();
        model.addAttribute("items", items);
        return "basic/items";
    }
}

 

데이터가 없는 상태이니까 테스트용으로 데이터를 넣어보기 

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

 

 

 

 

 

 

뷰템플릿 [ items.html ]

 

타임리프 사용하기 

th:href 가 있으면 기존거를 안쓴다 

<html xmlns:th="http://www.thymeleaf.org">

<link th:href="@{/css/bootstrap.min.css}"
        href="../css/bootstrap.min.css" rel="stylesheet">
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <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='@{/basic/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}">
                <td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
                <td><a href="item.html" th:href="@{|/basic/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>

 

 

 

 

HTML 에 사용한 타임리프 속성 알아보기 

 

상품 등록 버튼 누르면 http://localhost:8080/basic/items/add 경로로 이동

th:onclick="|location.href='@{/basic/items/add}'|"

<button class="btn btn-primary float-end"
        onclick="location.href='addForm.html'"
        th:onclick="|location.href='@{/basic/items/add}'|"
        type="button">상품 등록
</button>

 

 

리터럴 '|  |' 문자

 

타임리프에서 문자와 표현식 등은 분리되어 있기 때문에 더해서 사용해야 해야하는데 

| | 을 쓰게 되면 더하기 연산자 없이 한꺼번에 쓸 수 있다 

 

그냥 사용하게 되면 

  • th:onclick="'location.href=' + '\'' + @{/basic/items/add} + '\''"

리터럴 문법

  • th:onclick="|location.href='@{/basic/items/add}'|"

 

 

th:each - 상품 목록 반복출력
th:text 는 단순하게 데이터를 넣어주는 것 (테스트용으로 데이터를 넣은게 바로 들어간다)
<tr th:each="item : ${items}">
    <td><a href="item.html" th:text="${item.id}">회원id</a></td>
    <td><a href="item.html" th:text="${item.itemName}">상품명</a></td>
    <td th:text="${item.price}">10000</td>
    <td th:text="${item.quantity}">10</td>
</tr>

 

  • model.addAttribute("items", items);에서 "items"이 HTML 템플릿에서 ${items}에 접근하여 해당 데이터들을 item 에 넣어준다

 

th:href 문법

 

회원 ID, 상품명을 클릭시 이동하는 URL 은 같다 (상품id만 나오면 된다.  /basic/items/1과 같은 URL이 생성)

  • th:href="@{/basic/items/{itemId}(itemId=${item.id})}" : 
    • (itemId=${item.id}) 값이 {itemId} 경로 변수에 들어간다.
  • th:href="@{|/basic/items/${item.id}|}"  : 리터럴을 사용해서 위보다 URL을 간단히 만든 것
<tr th:each="item : ${items}">
    <td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
    <td><a href="item.html" th:href="@{|/basic/items/${item.id}|}" th:text="${item.itemName}">상품명</a></td>
    <td th:text="${item.price}">10000</td>
    <td th:text="${item.quantity}">10</td>
</tr>

 

 

 

 

반응형
LIST

+ Recent posts