[Spring] 3주차 - Mustache로 화면 구성
스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 04장
템플릿 엔진
지정된 템플릿 양식 + 데이터를 합쳐 HTML 문서를 출력하는 소프트웨어
웹 사이트의 화면을 어떤 형태로 만들지 도와주는 양식
- 서버 템플릿 엔진: JSP, Freemaker 등
- 서버에서 Java 코드로 문자열을 만든 뒤 HTML로 변환하여 브라우저로 전달
- 클라이언트 템플릿 엔진: React, Vue 등
- 이를 이용한 SPA(Single Page Application)는 브라우저에서 화면 생성
- 서버에서는 json 또는 xml 형식의 데이터만 전달 -> 클라이언트에서 조립
- 스프링 부트를 사용하면서 자바스크립트를 서버 사이드에서 렌더링하도록 구현하는 것은 쉽지 않음
머스테치(Mustache)
- 자바스크립트, 파이썬, php 등 다양한 언어를 지원하는 가장 심플한 템플릿 엔진
- JSP와 같이 HTML 템플릿을 만들어주는 템플릿 엔진
- 자바에서 사용될 때는 서버, 자바스크립트에서 사용될 때는 클라이언트 템플릿 엔진으로 모두 사용 가능
- 자바에서 사용되는 서버 템플릿 엔진 (JSP, Velocity, Freemaker, Thymeleaf 등) 대비 장점
- 간단한 문법
- 로직 코드 사용 X -> View와 서버의 역할 명확히 분리
- 하나의 문법으로 클라이언트/서버 템플릿 모두 사용 가능
- 인텔리제이 커뮤니티 버전으로도 플러그인 사용 가능
파일 위치: src/main/resources/templates
index.mustache 생성
역할: 첫 페이지
간단하게 html 문서 작성
web/IndexController 클래스 생성
역할: 머스테치에 URL 매핑하는 작업
- 머스테치 스타터의 역할: Controller에서 문자열을 반환할 때 앞의 경로(
/src/main/resources/templates
)와 뒤의 파일 확장자(.mustache
)를 자동 지정
@GetMapping("/")
public String index() {
return "index";
}
/src/main/resources/templates/index.mustache로 전환되어 View Resolver(URL 요청의 결과를 전달할 타입과 값을 지정하는 관리자)가 처리
테스트
게시글 등록 화면 구현
지난 주에 PostsApiController로 API 구현하였음
- 부트스트랩, jQuery(프론트엔드 라이브러리) 활용: 외부 CDN 활용
- 레이아웃 방식(공통 영역을 별도 파일로 분리하여 필요한 곳에 가져다 쓰는 방식)으로 추가
- css는 header에, JavaScript는 footer에 배치하여 페이지 로딩 속도 향상
- 부트스트랩이 제이쿼리에 의존하는 관계 (제이쿼리가 있어야 부트스트랩 실행)
{{>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>
</div>
</div>
</div>
{{>layout/footer}}
- 글 등록 버튼을 누르면 "/posts/save"로 이동 (아직 API 호출하는 자바스크립트 코드 넣지 않은 상태)
IndexController 클래스에 추가
...
@GetMapping("/posts/save")
public String postsSave() {
return "posts-save";
}
...
posts-save.mustache 생성 및 서버 실행
게시글 등록하는 API 추가
✔ src/main/resources/static에 위치한 정적 파일(자바스크립트, CSS, 이미지 등)은 URL에서 /(절대 경로)로 설정됨
데이터베이스에 정상적으로 저장된다.
전체 조회 기능 구현
- index.mustache에 머스테치 문법 사용
- {{#posts}}: posts라는 List 순회
- {{변수명}}: List에서 뽑아낸 객체의 필드 사용
- PostsRepository 인터페이스에 쿼리 추가
public interface PostsRepository extends JpaRepository<Posts, Long> {
@Query("SELECT p FROM Posts p ORDER BY p.id DESC")
List<Posts> findAllDesc();
}
- PostsListResponseDto 클래스 생성
- PostsService 클래스에 코드 추가
- postsRopository 결과로 넘어온 Posts의 Stream을 map을 통해 PostsListResponseDto 변환 -> List로 반환
@RequiredArgsConstructor
@Service
public class PostsService {
private final PostsRepository postsRepository;
...
@Transactional(readOnly = true)
public List<PostsListResponseDto> findallDesc() {
return postsRepository.findAllDesc().stream()
.map(PostsListResponseDto::new)
.collect(Collectors.toList());
}
}
- IndexController 클래스 수정
- Model: 서버 템플릿 엔진에서 사용할 수 있는 객체를 저장
- postsService.findAllDesc()로 가져온 결과를 posts로 index.mustache에 전달
private final PostsService postsService;
@GetMapping("/")
public String index(Model model) { // 서버 템플릿 엔진에서 사용할 수 있는 객체를 저장
model.addAttribute("posts", postsService.findAllDesc());
return "index";
}
Author And Source
이 문제에 관하여([Spring] 3주차 - Mustache로 화면 구성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@smjan27/Spring-Study-3저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)