1. 서버 템플릿 엔진과 머스테치

  • 템플릿엔진 : 지정된 템플릿 양식과 데이터가 합쳐져서 HTML 문서를 출력하는 소프트웨어
    • 서버 템플릿 엔진 : JSP, Freemarker
      • 서버에서 Java 코드로 문자열을 만든 뒤 이 문자열을 HTML로 변환하여 브라우저로 전달
    • 클라이언트 템플릿 엔진 : 리액트, 뷰의 View 파일
      • 브라우저 위에서 작동. 브라우저에서 작동될 때는 서버 템플릿 엔진의 손을 벗어나기 때문에 제어가 불가능
      • Vue.js, React.js를 이용한 SPA(Single Page Application)의 경우, 브라우저에서 화면을생성.
      • 서버에서는 Json 혹은 Xml 형식의 데이터만 전달하고, 조립은 클라이언트에서 담당함

2. 머스테치

http://mustache.github.io/

  • 자바에서 사용할 때는 서버 템플릿 엔진으로, 자바 스크립트에서 사용할 때는 클라이언트 템플릿 엔진으로 사용 가능
  • 자바 단 : JSP, Velocity, Freemarker, Thymeleaf등
    • 각각의 단점
      • JSP, Velocity : 스프링 부트에서는 권장 X
      • Freemaker : 템플릿 엔진으로는 기능이 과함. 자유도가 높지만 숙련도가 낮을수록 Freemaker안에 비지니스 로직이 추가 될 확률이 높음
      • Thymeleaf : 스프링 진영에서 적극적으로 밀지만 문법이 어려움.
        HTML 태그에 속성으로 템플릿 기능을 사용하는 방식이 허들로 느껴지기도 함.
    • Mustache의 장점
      • 문법이 심플
      • 로직 코드를 사용할 수 없어 View의 역할과 서버의 역할이 명확히 분리됨
      • Mustache.js와 Mustache.java 2가지가 모두 존재해서 하나의 문법으로 클라이언트/서버 둘다 사용 가능
  • mustache 플러그인 설치

2-1. 기본페이지 만들기

  • build.gradle (의존성 추가)

    compile('org.springframework.boot:spring-boot-starter-mustache')

  • src/main/resources/templates/index.mustache

<!DOCTYPE HTML>
<html>
<head>
    <title>스프링 부트 웹서비스</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>스프링 부트로 시작하는 웹 서비스</h1>
</body>
</html>
  • IndexController를 추가해 index.mustache를 매핑

    build.gradle에 mustache starter를 설치했기 때문에
    컨트롤러에서 문자열을 반환할 때 앞의 경로와 뒤의 파일의 확장자는 자동으로 저장된다.
    따라서 "index"를 리턴하면
    src/main/resources/templates/index.mustache로 매핑됨
  • 테스트코드 생성

    URL 호출 시 페이지의 내용이 제대로 호출되는지에 대한 여부 테스트
    "/" 를 호출햇을 때, index.mustache에 포함된 코드들이 있는지를 확인하기 위해
    "스프링 부트로 시작하는 웹 서비스" 문자열이 코드에 포함되어 있는지를 체크함

포함되어 있기 때문에 정상적으로 Test passed 가 됨

  • 실제 서버에서 돌려보기
    실제 서버를 돌려보아도, 매핑이 제대로 된 것을 확인할 수 있다!

2-2. 게시글 등록화면 만들기

  • 레이아웃 방식
    : 공통 영역을 별도의 파일로 분리하여 필요한 곳에서 가져다 쓰는 방식
    이번에 추가할 라이브러리들인 부트스트랩과 제이쿼리는 머스태치화면 어디서든 필요함

  • header.mustache

  • footer.mustache

  • index.mustache

{{>layour/header}}
    <h1>스프링 부트로 시작하는 웹 서비스</h1>
{{>layour/footer}}

{{>layout/?}}
현재 머스테치 파일을 기준으로 다른 파일을 가져옴

  • IndexController (페이지에 관련 된 controller는 모두 여기서 처리)
    post-save.mustache를 만들어 줘야함.

  • posts-save

  • localhost:8080
  • localhost:8080/posts/save
  • 등록 기능을 구현하기 위해 API를 호출할 JS 작성
    • index.js의 첫 문장에 var main={...}을 선언하는 이유?

      var init - function(){
      		...
      };
      	var save = function() {
          	...
          };
          
          init();
      • 만약 js가 위와같이 작성되었다면 브라우저의 스코프는 공용공간으로 쓰이기 때문에 나중에 로딩 된 init,save가 먼저 로딩된 js의 function을 덮어쓰게 됨.
      • 여러 사람이 참여하는 프로젝트에서 중복된 함수 이름은 자주 발생할 수 있으므로
        index.js만의 유효범위를 만들어서 사용
      • var index라는 객체를 만들어 해당 객체에서 필요한 모든 function을 선언!
        index 객체 안에서만 function이 유효하기 때문에 다른 JS와 겹칠 위험이 사라짐
  • 생성된 js를 사용할 수 있도록 footer.mustache에 추가해줌
  • localhost:8080/posts/save

정상적으로 api 요청을 수행함

2-3 전체 조회화면 만들기

  • index.mustache의 UI 변경

    머스테치 문법

    • {{#posts}}
      • posts라는 List를 순회
      • Java의 for와 같은 역할
    • {{id}}등의 {{변수명}}
      • List에서 뽑아낸 객체의 필드를 사용
  • PostRepository 인터페이스에 쿼리 추가

  • postService에 코드 추가

    • findAllDesc 메소드의 트랜젝션 어노테이션 옵션이 추가
      @readOnly=true를 주면 트랜젝션의 점위는 유지하되, 조회 기능만 남겨두어 조회 속도가 개선 (등록, 수정,삭제 기능이 전혀 없는 메소드라면 사용 권장)
    • map(PostsListResponseDto)
      = map(posts -> new PostsListResposeDto(posts))
      • postRepository 결과로 넘어 온 Posts의 Stream을 map을 통해 PostListResponseDto로 변환 -> List로 반환
  • PostListResponsdeDto 생성

  • Controller 변경

    • Model
      - 서버 템ㅍㄹ릿 엔진에서 사용할 수 있는 객체를 저장
      - 여기서는 postService.findAllDesc()로 가져온 결과를 posts로 index.mustache에 전달

2-4 게시글 수정, 삭제화면만들기

  • posts-update.mustache
    • {{post.id}}
      • 머스태치는 객체의 필드 접근시 .으로 구분
      • Post클래스의 id에 접근하겠다.
    • readonly
      • Input 태그에 읽기 기능만 허용하는 속성
      • id와 author는 수정할 수 없도록 읽기만 허용하도록 추가

  • index.js 에 update function 추가
    • $('#btn-update').on('click')
      • btn-update란 id를 가진 HTML 엘리먼트에 click 이벤트가 발생할 때 update function을 실행하도록 이벤트를 등록한다.
    • update: function()
      • 신규로 추가될 update function
    • type:'PUT'
      • 여러 HTTP Method 중에 PUT 메소드 선택
      • PostsApiController에 있는 API에서 이미 @PutMapping을 선언했기 때문
    • url:'api/v1/posts'+id
      • 어느 게시글을 수정할지 URL Path로 구분하기 위해 Path에 id를 추가
  • IndexController에 메소드 추가

2-5 게시글 삭제 화면 만들기

  • index.js

  • PostService.class

  • PostsApiController.class

0개의 댓글