머스테치

iseon_u·2023년 3월 22일
0

Book

목록 보기
8/16
post-thumbnail

CH04 - 머스테치


레이아웃 방식

  • 공통 영역을 별도로 파일로 분리하여 필요한 곳에 가져다 사용하는 방식

header.mustache

<!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>

footer.mustache

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

</body>
</html>
  • 페이지 로딩 속도를 높이기 위해 css 는 header, js 는 footer
  • bootstrap.js 의 경우 제이쿼리에 의존하기 때문에 코드를 제이쿼리 아래에 작성

index.mustache

{{>layout/header}}
<h1>스프링 부트로 시작하는 웹 서비스</h1>
{{>layout/footer}}
  • {{>}} 현재 머스테치 파일 기준으로 다른 파일을 가져온다

JS 스코프

index.js

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

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

main.init();
  • var main = {…} 을 사용한 이유
    • 같은 스코프의 중복된 함수 이름은 나중에 로딩된 함수가 덮어쓰게 된다
    • index.js 만의 스코프를 만들어 사용

전체 조회 페이지

{{>layout/header}}
<h1>Spring Boot</h1>
<div class="col-md-12">
    <div class="row">
        <div class="col-md-6">
            <a href="/posts/save" role="button" class="btn btn-primary">Write</a>
        </div>
    </div>
    <br>
    <!--목록 출력 영역-->
    <table class="table table-horizontal table-bordered">
        <thead class="thead-strong">
        <tr>
            <th>게시글 번호</th>
            <th>제목</th>
            <th>작성자</th>
            <th>최종수정일</th>
        </tr>
        </thead>
        <tbody id="tbody">
        {{#posts}} <!--1-->
            <tr>
                <td>{{id}}</td> <!--2-->
                <td>{{title}}</td>
                <td>{{author}}</td>
                <td>{{modifiedDate}}</td>
            </tr>
        {{/posts}}
        </tbody>
    </table>
</div>
{{>layout/footer}}
  1. {{#posts}}
    • posts 라는 List 를 순회
    • for 문
  2. {{변수명}}
    • List 에서 뽑아낸 객체의 필드를 사용

SpringDataJpa 에서 제공하지 않는 메소드 사용

PostsRepository.java

public interface PostsRepository extends JpaRepository<Posts, Long> {

    @Query("SELECT p FROM Posts p ORDER BY p.id DESC")
    List<Posts> findAllDesc();

}
  • @Query 를 사용해 쿼리 작성
  • 기본 메소드보다 가독성이 좋다

규모가 있는 프로젝트 데이터 조회

  • 조회용 프레임워크를 추가로 사용
    • Querydsl, jooq, MyBatis
  • 조회 - Querydsl
  • 등록/수정/삭제 - SpringDataJpa
  • Querydsl 장점
    • 타입 안정성이 보장
    • 국내 많은 회사들이 사용

PostsService.java

@Transactional(readOnly = true)
    public List<PostsListsResponeDto> findAllDesc() {
        return postsRepository.findAllDesc().stream()
                .map(PostsListResponseDto::new)
                .collect(Collectors.toLists());
    }
  • @Transactional(readOnly = true)
    • 트랜잭션의 범위는 유지
    • 조회 기능만 사용 → 조회 속도 개선
    • 등록, 수정, 삭제가 없는 서비스 메서드에서 사용
profile
🧑🏻‍💻 Hello World!

0개의 댓글