Spring/스프링부트와 AWS로 혼자구현하는 웹 서비스

4장. 머스테치로 화면 구성하기

LTSGOD 2023. 1. 25. 10:50

템플릿 엔진

 

지정된 템플릿 양식과 데이터가 합쳐저 HTML문서를 출력하는 S/W를 이야기함.

 

 

서버템플릿 엔진

-> 서버에서 구동됨.

 

JSP 같은 경우에는 서버에서 자바코드로 문자열을 만든뒤 이것을 HTML로 변환하여 브라우저로 전달

 

javascript같은 경우에는 브라우저 위에서 작동한다. 즉 브라우저에서 작동될때는 서버템플릿엔진의 손을 벗어나 제어X

즉 vue.js 나 react.js (클라이언트 템플릿엔진)는 브라우저에서 즉 화면을 생성. 서버에서 이미 코드가 벗어난 경우이다. 

클라이언트 템플릿 엔진

 

머스테치란?

 

수많은 언어를 지원하는 가장 심플한 템플릿 엔진.

그외에도, JSP, Velocity, Freemarker, Thymeleaf등등이 있다.

 

java/org/example/awsspring/web/IndexController.java

@Controller
public class IndexController {

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

컨트롤러 생성

 

java/org/example/awsspring/web/IndexControllerTest.java

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

   @Autowired
   private TestRestTemplate restTemplate;

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

      //then
      Assertions.assertThat(body).contains("스프링 부트로 시작하는 웹 서비스");
   }
}

테스트 코드

 

 

TestRestTemplate 을 통해 "/"로 호출했을 때 index.mustache 에 포함된 코드들이 있는지 확인하면 됨.


4.3 게시글 등록 화면 만들기

 

앞서 3장에서 PostsApiController로 api는 구현했다.

여기서 바로 화면을 구현함.

그냥 HTML만 사용하면 멋이 없기에 오픈소스인 부트스트랩을 이용해서 화면을 만들어봄.

 

부트스트랩, 제이쿼리 등 프론트엔드 라이브러리를 사용할 수 있는 방법은 2가지로 나뉨.

 

  1. 외부 CDN 사용
  2. 직접 라이브러리를 받아서 사용하는 방법.

 

여기서는 1번 방법을 사용함.

 

2개의 라이브러리를 index.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>

header.mustache

 

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

footer.mustache

 

보면 css와 js의 위치가 서로다름.

 

페이지 로딩속도를 높이기 위해 css는 header에, js는 footer에 두었다.

 

HTML은 위에서부터 코드가 실행되기에 head가 다 실행되고 body가 실행됨.

 

즉, head가 다불러지지않으면 사용자 쪽에서는 백지 화면만 노출된다.

특히 js의 용량이 크면 클수록 body부분의 실행이 늦어지기 때문에 js는 body하단에 두어 화면이 다 그려진 뒤에 호출하는 것이 좋다.

 

그리고 boostrap.js 의 경우 제이쿼리가 꼭 있어야하기에 먼저 호출.( 제이쿼리에 의존한다고 함.)

 

{{>layout/header}}

<h1>스프링부트로 시작하는 웹 서비스 Ver.2</h1>

{{>layout/footer}}

{{>layout/header}} 

{{>}} 는 현재 머스테치 파일 (index.mustache)를 기준으로 다른파일을 가져옴.

 

 

public interface PostsRepository extends JpaRepository<Posts,Long> {

   @Query("select p from Posts p order by p.id desc")
   List<Posts> findAllDesc();
}

PostsRepository에 코드 추가

public class PostsListResponseDto {
   private Long id;
   private String title;
   private String author;
   private LocalDateTime modifiedDate;

   public PostsListResponseDto(Posts entity) {
      this.id = entity.getId();
      this.title = entity.getTitle();
      this.author = entity.getAuthor();
      this.modifiedDate = entity.getModifiedDate();
   }
}

PostsListResponseDto 추가

-> 처음 화면 불러오면 게시글 리스트 쫙 뽑아주는 거 Dto

 

@Transactional(readOnly = true)
public List<PostsListResponseDto> findAllDesc(){
   return postsRepository.findAllDesc().stream()
      .map(PostsListResponseDto::new)
      .collect(Collectors.toList());
}

Service에 코드 추가

PostsListResponseDto 로 변환해서 List 반환

 

@GetMapping("/")
public String index(Model model){
   model.addAttribute("posts",postsService.findAllDesc());
   return "index";
}

Controller에 추가

Model

-> 서버 템플릿 엔진에서 사용할 수 있는 객체를 저장할 수 있다.

 

 


4.5

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

 

update api는 이미 만들었으므로 pass.

 

@GetMapping("/posts/update/{id}")
public String postsUpdate(@PathVariable Long id, Model model){
   PostsResponseDto dto = postsService.findById(id);
   model.addAttribute("post",dto);

   return "posts-update";
}

Controller update

 

{{>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="id" value="{{post.id}}" readonly>
            </div>
            <div class="form-group">
                <label for="title">제목</label>
                <input type="text" class="form-control" id="title" value="{{post.title}}">
            </div>
            <div class="form-group">
                <label for="author"> 작성자 </label>
                <input type="text" class="form-control" id="author" value="{{post.author}}" readonly>
            </div>
            <div class="form-group">
                <label for="content"> 내용 </label>
                <textarea class="form-control" id="content">{{post.content}}</textarea>
            </div>
        </form>
        <a href="/" role="button" class="btn btn-secondary">취소</a>
        <button type="button" class="btn btn-primary" id="btn-update">수정 완료</button>
        <button type="button" class="btn btn-danger" id="btn-delete">삭제</button>
    </div>
</div>

{{>layout/footer}}

update 머스타치 추가

 

삭제 추가

 

이번 장에서 배운것

 

서버 템플릿 엔진과 클라이언트 템플릿 엔진의 차이

머스타치의 기본 사용방법

스프링 부트 에서의 화면 처리 방식

js/css선언 위치를 다르게 하여 웹사이트의 로딩 속도를 향상하는 방법

js객체를 이용하여 브라우저의 전역변수 충돌 문제를 회피하는 방법.