스프링 부트와 AWS로 혼자 구현하는 웹 서비스 책을 읽고 - 3일차

박세건·2023년 8월 30일
0

템플릿 엔진을 이용해서 화면 구성

이전에 토이프로젝트에서는 그냥 html과 타임리프를 사용해서 화면을 구성했는데 이번 책을 통해서는 '머스테치'라고 하는 템플릿을 사용해서 화면 영역을 개발해보자!

템플릿 엔진 : 지정된 템플릿 양식과 데이터가 합쳐져서 HTML 문서를 출력하는 소프트웨어
템플릿 엔진으로는 jsp,freemarker, 리액트 ,뷰
템플릿엔진은 서버 템플릿엔진과 클라이언트 템플릿엔진
jsp,freemarker가 서버 템플릿엔진
리액트 뷰 는 클라이언트 템플릿 엔진

머스테치 : 수많은 언어를 지원하는가장 심플한 템플릿 엔진
루비, 자라스크립트 파이썬, PHP, 자바, 펄 Go, ASP 등 현존하는 대부분의 언어를 지원
따라서 자바에서는 서버템플릿으로 자바스크립트에서는 클라이언트 템플릿엔진으로 사용할 수 있다.

이전 프로젝트에서 내가 사용했던 타임리프는 서버템플릿엔진에 속한다.

머스테치 장점

  • 문법이 다른 템플릿 엔진보다 심플
  • 로직 코드를 사용할 수 없어 view의 역할과 서버의 역할이 명확하게 분리됩니다.
  • java와 javascript 2가지가 다 있어, 하나의 문법으로 클라이언트/서버 템플릿 모두 사용가능
  • 인텔리제이 커뮤니티 버전을 사용해도 플러그인 사용가능, 타임리프나 JSP는 얼티메이트버전에서만 지원

일반적인 Index 페이지를 만들어보자

index.mustache

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>스프링 부트 웹서비스</title>
</head>
<body>
<h1>스프링 부트 웹서비스</h1>
</body>
</html>

indexController

package com.qkrtprjs.springbootproject.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {
    @GetMapping("/")
    public String index() {
        return "index";
    }
}

TEST

package com.qkrtprjs.springbootproject.web;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.swing.*;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class IndexControllerTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void 메인페이지_로딩() {
        //when
        String body = this.restTemplate.getForObject("/", String.class);

        //then
        assertThat(body).contains("스프링 부트 웹서비스");
    }

}

한글을 인식하지 못해서 테스트를 통과하지못함

yml에

server:
  servlet:
    encoding:
      force-response: true  #머스테치 한글깨짐 오류 해결

추가


정상적

게시글 글 등록 화면 mustache로 만들기

화면을 만들기 전에 레이아웃 기능을 사용할 것인데
레이아웃은 항상 html에 헤더나 풋터 이런 공통적인 요소들을 계속 만들어줘서하는 수고를 공통으로 작업하게 해줘서 간편하게 해주는 기능이다.

팁은 css는 헤더에 넣어주고 js는 풋터에 넣어줘서 페이지 로딩속도를 높입니다.

layout
footer

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

<!--index.js 추가-->
<script src="/js/app/index.js"></script>
</body>
</html>

header

<!DOCTYPE HTML>
<html>
<head>
    <title>스프링부트 웹서비스</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>

이렇게 레이아웃을 설정해주면

index.mustache에서는

{{>layout/header}}
<h1>스프링 부트 웹서비스</h1>
<div class="col-md-12">
    <div class="row">
        <div class="col-md-6">
            <a href="/posts/save" role="button" class="btn btn-primary">글 등록</a>
            {{#userName}}
                Logged in as: <span id="user">{{userName}}</span>
                <a href="/logout" class="btn btn-info active" role="button">Logout</a>
            {{/userName}}
            {{^userName}}
                <a href="/oauth2/authorization/google" class="btn btn-success active" role="button">Google Login</a>
                <a href="/oauth2/authorization/naver" class="btn btn-secondary active" role="button">Naver Login</a>
            {{/userName}}
        </div>
    </div>
{{>layout/footer}}

이렇게만 작성해도 헤더와 푸터가 적용이된다.

posts-save.mustache
글 작성을 위한 폼 html

{{>layout/header}}

<h1>게시글 등록</h1>

<div class="col-md-12">
    <div class="col-md-4">
        <form>
            <div class="form-group">
                <label for="title">제목</label>
                <input type="text" class="form-control" id="title" placeholder="제목을 입력하세요">
            </div>
            <div class="form-group">
                <label for="author"> 작성자 </label>
                <input type="text" class="form-control" id="author" placeholder="작성자를 입력하세요">
            </div>
            <div class="form-group">
                <label for="content"> 내용 </label>
                <textarea class="form-control" id="content" placeholder="내용을 입력하세요"></textarea>
            </div>
        </form>
        <a href="/" role="button" class="btn btn-secondary">취소</a>
        <button type="button" class="btn btn-primary" id="btn-save">등록</button>
    </div>
</div>

{{>layout/footer}}

틀은 작성이 되었고 이제 기능을 만들어보자
기능을 위해서는 js와 ajax를 사용해서 값을 받아온다.

index.js

let main = {
    init: function () {
        let _this = this;
        $('#btn-save').on('click', function () {
            _this.save();
        });
    },
    save: function () {
        let data = {
            title: $('#title').val(),
            author: $('#author').val(),
            content: $('#content').val()
        };

        $.ajax({
            type: 'POST',
            url: '/api/v1/posts',
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(data)
        }).done(function () {
            alert('글이 등록되었습니다.');
            window.location.href = '/';
        }).fail(function (error) {
            alert(JSON.stringify(error));
        });
    }
}
main.init();

js 작성할때에 중요한점은 만약 한가지 html에 여러개의 js를 사용하고있고
여러개의 js에 같은 이름의 함수들이 존재할 수 있고 중복된 함수 이름은 오류를 발생할 수도있기때문에 아래 코드에서처럼 let main 이라는 객체를 만들어서 function을 선언해주는 것입니다.
객체 안에서만 function이 유효하기 때문에 다른 JS 와 겹칠 위험이 사라집니다!

//main 객체 설정
let main = {
    init: function () {
        let _this = this;
        $('#btn-save').on('click', function () {
            _this.save();
        });
    },
    save: function () {
        let data = {
            title: $('#title').val(),
            author: $('#author').val(),
            content: $('#content').val()
        };

        $.ajax({
            type: 'POST',
            url: '/api/v1/posts',
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify(data)
        }).done(function () {
            alert('글이 등록되었습니다.');
            window.location.href = '/';
        }).fail(function (error) {
            alert(JSON.stringify(error));
        });
    }
}
main.init();

위와 같이 save라는 함수를 다른 js가 갖고있어도 위에서 호출하는 save는 main.save 가 되기때문에 오류가 발생하지 않는 것입니다!!
꼭 js를 작성할때에 이 틀을 기억하자!!

직접 애플리케이션을 실행시켜서 확인해보자

정상적으로 js와 ajax가 작동되는 것을 확인할 수 있다 js, ajax 문법이나 기능들은 이전에 게시판 만들어보기 시리즈에서 다루었기때문에 궁금하면 확인바랍니다.
참고

profile
멋있는 사람 - 일단 하자

0개의 댓글