[SpringBoot(2)] Mustache

배지원·2022년 11월 9일
0

실습

목록 보기
11/24
post-custom-banner

📄 Mustache를 통해 API통신 데이터 출력

이전까지 진행했던 실습은 기능만 넣어 API통신을 swagger를 통해 진행했다면 이제는 그 데이터를 유저가 볼수있는 view화면으로 출력시킬 수 있도록 진행할 것이다. 그래서 프로젝트를 새로 만들어 처음부터 진행할 것이다.

1. Mustache 란?

(1) 정의

  • 다양한 언어를 합쳐서 사용할 수 있는 템플릿 엔진이다.
  • HTML, 구성파일, 소스코드 등 무엇이든 사용 가능하고 if~else문이나 반복문이 없기 때문에 Logic-Less Templates라고 불린다.

템플릿 엔진이란?

  • 템플릿의 문법과 데이터(JSON, XML 등)를 이용해서 HTML 문서를 만들어주는 소프트웨어라 이해하면 된다.

템플릿 이란?

  • 프로그램 로직을 표연하는 계층과 서비스를 사용하는 유저가 보는 데이터 출력을 위한 프리젠테이션 계층을 분리하기 위한 수단으로 Controller에서 View로 데이터를 보내면 데이터를 View에서 볼 수 있게 도와주는 것으로 Mustache 말고도 JSP, Thymeleaf가 있는데 JSP는 잘 사용 않하는 추세이다.

(2) Mustache 문법

①변수

  • 사용방식 : {{ 변수명 }}
  • 문자열은 자동 HTML 이스케이프 된다.
  • 이스케이프란, 특정 문자를 HTML로 변환하는 행위
  • 이스케이프되지 않느 문자열을 출력하려면 {{{ , }}} 사용

예제

[데이터]
"item" : "computer",
"price" : "<b>15000</b>"
---------
[템플릿]
{{item}}
{{name}}
{{price}}
{{{price}}}
---------
[결과]
computer

&lt,b&gt;15000&lt,/b&gt;
<b>15000</b>

② 파일 불러오기

  • 웹페이지에서는 위쪽의 네비게이션(메뉴바)와 맨 아래쪽의 회사정보가 출력되는 공간은 어떤 페이지를 가든지 고정되어 있는 경우가 있다. 따라서 이러한 경우에는 가운데 공간의 코드만 변경이 되기 때문에 위쪽과 아래쪽의 코드는 파일을 따로 만들어 호출해서 사용하는식으로 사용한다.

서로 다른 파일

[a 파일]
header
---------
[b 파일]
body
---------
[c 파일]
footer

b파일 안에서 다른 파일 호출

{{>layout/a}}
body
{{>layout/c}}
------------
결과
header
body
footer
  • 위와 같이 {{> 파일경로/파일이름}} 처럼 입력하면 해당 파일에 있는 데이터를 불러올 수 있다.

더 자세한 내용은 다음 블로그 참조 Mustache 정리


(3) 디렉토리 구조

  • Mustache의 일잔적인 파일 위치는 src/main/resource/templates에 위치해야한다. 해당 디렉토리가 없을 경우 직접 생성해야한다.
  • (파일명).mustache 파일을 생성하면 된다.

2. 프로젝트 생성

  • Spring intializer를 통해 기본 설정

  • github 등록 및 푸시

    깃허브에 올리는 기초 설정 파일은 아래와 같다(이 외에는 올리지 말것)
    .gitignore
    application.yml
    build.gradle
    gradlew
    gradlew.bat
    settings.gradle
    SpringMustacheBbsApplication.java
    SpringMustacheBbsApplicationTests.java


3. SpringBoot, Mustache 연동

(1) MustacheController

  • Controller를 통해 Model에 값을 저장후 출력할 view로 값을 보낸다.(MVC 패턴 사용)
  • @PathVariable을 통해 사용자가 입력한 값을 model에 저장
@Controller
public class MustacheController {
    
    @GetMapping("/hi/{id}")
    public String mustacheCon2(@PathVariable("id") String id, Model model){
        model.addAttribute("username","rok");    // username이라는 변수에 rok값을 넣어 model에 저장
        model.addAttribute("id",id);    // greetings라는 이름의 view를 리턴(이때 model을 보내줌)

        return "greetings";
    }
}

(2) mustache 파일(View File)

  • mustache파일을 생성하고 웹페이지에 출력할 틀을 만들어준다.
  • Controller에서 Model에 저장된 데이터의 변수명을 입력하여 변수명에 해당하는 값을 출력한다.

실행결과

※ 만약 html만 데이터가 바뀐경우 Ctrl + F9를 통해 빠르게 적용 가능

📣 이때 만약 한글이 깨진다면 application.yml파일에 추가

server:
 port: 8080
 servlet:
   encoding:
     force-response: true

4. Mustache 디자인(Bootstrap 사용)

(1) Bootstrap 적용하기

  • 부트스트랩은 반응형이며 웹프로젝트 개발을 위한 가장 인기있는 HTML,CSS,JS 프레임워크로 웹사이트 개발 프레임 워크다.

공식 홈페이지 : https://getbootstrap.com/

부트 스트랩에 있는 디자인과 반응형 코드를 사용하기 위해서는 부트스트랩과 내 코드를 연동시켜줘야 하므로 다음 코드를 입력해줘야 한다.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
  </head>
  <body>
    <h1>Hello, world!</h1>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
  </body>
</html>

적용화면

  • 부트스트랩과 연동을 한 후에 부트스트랩에서 제공하는 디자인 코드를 복사+붙여넣기 하면 디자인이 적용된 것을 확인 할 수 있다.

📌 부트스트랩은 모바일, PC, 태블릿 등 반응형이기 때문에 모양이 제한될 수 있다. 따라서 사용자는 Grid사용법을 익히고 커스터마이징을 해야한다. 하지만 나는 백엔드를 배우기 때문에 자세히는 다루지 않을 것이다.


(2) 페이지 디자인하기

  • 크게 header, body, footer로 3구역으로 나누어 디자인을 한다. 이때, header와 footer는 대부분 웹 페이지에서는 고정된 값으로 메뉴바와 회사정보를 나타내는 곳으로 코드자체도 고정된 값이고 body부분만 변하면 되므로 파일을 따로 만들어 body에서 호출해서 사용하도록 한다.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="#">Navbar</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                <li class="nav-item">
                    <a class="nav-link active" aria-current="page" href="#">Home</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Link</a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                       aria-expanded="false">
                        Dropdown
                    </a>
                    <ul class="dropdown-menu">
                        <li><a class="dropdown-item" href="#">Action</a></li>
                        <li><a class="dropdown-item" href="#">Another action</a></li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li><a class="dropdown-item" href="#">Something else here</a></li>
                    </ul>
                </li>
                <li class="nav-item">
                    <a class="nav-link disabled">Disabled</a>
                </li>
            </ul>
            <form class="d-flex" role="search">
                <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-success" type="submit">Search</button>
            </form>
        </div>
    </div>
</nav>

body

{{>layout/header}}
<div>
    <h1>{{id}} {{username}} Hello!</h1>
    <button type="button" class="btn btn-primary">버튼1</button>
    <button type="button" class="btn btn-secondary">버튼2</button>
    <button type="button" class="btn btn-success">버튼3</button>

    <ul class="list-group">
        <li class="list-group-item">An item</li>
        <li class="list-group-item">A second item</li>
        <li class="list-group-item">A third item</li>
    </ul>
</div>
{{>layout/footer}}

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
        crossorigin="anonymous"></script>
</body>
<footer>
    <div class="mb-5 container-fluid">
        <hr>
        <p>@ RokBoard <a href="localhost:8080">Privacy</a> <a href="#">Terms</a></p>
    </div>
</footer>
</html>


5. 폼 데이터 주고 받기

ArticleController

@Controller
@Slf4j
@RequestMapping("/articles")
public class ArticleController {

    @GetMapping("/new")
    public String newArticleForm(){
        return "articles/new";
    }

    @PostMapping("/posts")
    public String createArticle(ArticleDto form){
        log.info(form.toString());
        return "";
    }
}

ArticleDto

@Getter
@ToString
public class ArticleDto {
    private Long id;
    private String title;
    private String content;

    public ArticleDto(Long id, String title, String content) {
        this.id = id;
        this.title = title;
        this.content = content;
    }
}

Form 파일

  • 위에서 했던 예제 이어서 진행
{{>layouts/header}}
<form action="/articles/posts" method="post">
    <input type="text" name="title">
    <input type="text" name="content">
    <button type="submit" class="btn btn-primary">Submit</button>
    <a href="/articles">back</a>
</form>
{{>layouts/footer}}
  • actiom : http request(사용자가 입력한 값)가 어디로 갈지
  • method : 값을 입력하는 형식(Post 없으면 기본값 GET)
  • input name ="title" : title이라고 서버에서 받아줘야 한다.
  • type="submit" : 버튼을 누르면 실행함(데이터 전송)

결과

  • View 화면에서 값을 넣고 버튼클릭시 데이터가 넘어가 콘솔화면에 log가 찍혀 있는것을 확인할 수 있다.

전체적인 흐름

profile
Web Developer
post-custom-banner

0개의 댓글