티스토리 뷰

반응형

이 글은 jojoldu님의 과정을 보고 학습하며 작성한 글입니다. 좋은 글을 써주셔서 감사합니다!

  • Using Language : Java8
  • Using Tools : IntelliJ, SourceTree, SpringBoot1.5.10, Gradle

부제 : 화면 제작

1. Handlebars의 정의

먼저, Handlebars란 서버 템플릿 엔진이라고 한다.
여기서 템플릿 엔진이란 동적 페이지 생성을 위해 필요한 기술로,
템플릿 엔진을 사용하게 되면 보다 간략한 표현을 이용해서 데이터를 가공하여
웹 페이지를 보여줄 수 있다고 한다.
장점으로는 기존의 HTML 보다 간단한 문법을 사용하고 같은 템플릿을 사용하는 경우에는
재사용성이 높고 유지보수에 용이하다는 점이 있다.

2. Handlebars와 IntelliJ의 연동

먼저, Handlebars를 사용하기 위해서 build.gradle에 의존성을 추가해준다.
롬복과 스프링부트에 의존성을 추가한 것 과 같이, Handlebars사용도 단순히 아래 문장하나만
추가해주면, 별도의 설정 없이 사용할 수 있다.

(나는 이 부분에서 pl을 pi로 작성하고 삼일 내내 의존성 추가가 안된다고 울었다.
실제로 여태 작성한 모든 코드들을 다시 적어보고 혹여나 파일들 경로가 잘못되었을까
프로젝트도 다시 파려는 생각을 했다 진짜 너무 슬프다 다시 생각해도 여러분은 그러지 말길..)

compile 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.2.15'

Handlebars 의존성 추가 이외에도 플러그 인을 설치 받으면 언어 지원을 받을 수 있다고 한다.
(IntelliJ의 경우에 해당)

Settings에서 Plugins를 검색 후 Marketplace에서 handlebars를 검색해준다.
아래의 두 개의 결과에서 첫번째 항목은 Install해준다.

그 후 IntelliJ를 재시작 해주면 사용이 가능하다.

3. Handlebars를 이용한 메인 페이지 생성

src/main/resources/templates에 main.hbs라는 이름을 가진 메인화면 파일을 생성해준다.

<main.hbs>


위의 코드는 메인 페이지를 구성해준 코드 이고 이제 메인페이지를 호출하는 controller를 생성한다.


경로 : src/main/java/com/udud/webservice/web/webController.java


위 webController에서 사용된 @GetMapping 애노테이션은 기존 스프링의 @RequestMapping의 업버전이다. 

기존 스프링에서 사용되는 @RequestMapping(value="/", method=RequestMethod.POST or GET)을
Post방식이면 @PostMapping("/"), Get방식이면 @GetMapping("/")으로 사용할 수 있다.

다음으로는 작성한 코드들이 실행이 되는지 확인하기 위해서 테스트 코드 검증을 실시한다.

4. Handlebars를 이용한 메인 페이지 테스트 코드

WebControllerTest.java라는 이름을 가진 테스트 클래스를 생성한다.

경로 : src/test/java/com/udud/webservice/web
이 테스트 클래스에서는 "/"로 URL을 호출했을때 메인 페이지가 제대로 실행되는지에 대한
테스트를 진행한다.

제대로 실행되는지 확인하기 위해서는 "/"로 호출했을 때 main.hbs에 사용된 코드 유무를 확인한다.

전체 코드를 확인할 필요 없이 "스프링부트로 시작하는 웹 서비스" 라는 문자열이 있는지 비교한다.

문자열 비교를 위해서 assertThat을 사용해준다.


<WebControllerTest.java>


코드를 작성하고 메인페이지_로딩을 실행해주면 테스트가 통과된 모습을 확인할 수 있다.


테스트 성공 후 Application파일을 실행시켜 직접 URL을 호출해 준다. (localhost:8080)


main.hbs가 controller를 거쳐서 제대로 실행되는 모습을 확인하였으므로 다음 화면들을 구성해준다.


5. 게시글 등록 기능 구현_service메소드 구현

이제 트랜잭션까지 관리하기 위해서 Service메소드를 구현한다.
Controller와 Service를 나누는 이유는 각각의 역할을 분리하기 위해서이다.
View연동 부분은 모두 Controller에서 관리하고 로직&트랜잭션 관리는 모두 Service에서 관리한다.

PostsService.java 클래스를 생성해준다.

경로 : src/main/java/com/udud/webservice/service


이전 과에서 생성한 데이터 저장용 PostsSaveRequestDto 클래스를 가져와서 엔티티를 저장한다.

6. 게시글 등록 기능 구현_service메소드 테스트

Service메소드를 테스트해주기 위해서 Test코드를 추가해준다.
그러기 위해서 PostServiceTest.java클래스를 생성한다.

경로 : src/test/java/com/udud/webservice/service



위 코드는 dto가 postsService.save에 전달되면,

assertThat을 사용해서 각 값 전달이 제대로 되었는지 확인하는 것이다.

Test코드가 실행되기 위해서는 PostsSaveRequestDto에 Builder가 필요하므로,
Builder 부분을 다음과 같이 추가시켜준다.



그 후 테스트 코드를 실행시켜주고 다음과 같은 결과창이 나오면 

service메소드가 잘 작동되는 것을 알 수 있다.



마지막으로, WebRestController의 save메소드를 service의 save로 교체해주면 작업은 끝난다.


다음으로는 게시글의 입력 화면을 처음에 연동한 Handlebars을 이용하여 만들어준다.

7. 게시글 등록 기능 구현_입력 화면 구현 준비

화면을 구현하려면 화면단까지 구성하여야 하는데 이러한 과정을 쉽게 하기 위해서
부트스트랩을 이용해준다.
부트스트랩이란 웹 사이트를 쉽게 만들 수 있게 도와주는 HTML, CSS, JS프레임워크로
Twitter에 의해 개발되었으며, GitHub에서 오픈 소스 제품으로 출시되었다고한다.

부트스트랩을 설치 후 사용하는 방법은 크게 3가지로 구분된다.

  1. 웹서버에 올려서 사용하는 방법
  2. CDN(Contents Delivery Network)를 이용하는 방법
  3. Bower라는 패키지를 이용하는 방법

이 중 가장 많이 사용하는 방법은 웹 서버에 올려서 사용하는 방법이고,
두번째 방법은 CDN 상황에 종속적이게 되어 CDN 상황에 따라 서비스가 느려지거나
문제가 생기는 경우가 있지만, 가장 간단히 라이브러리를 받아 사용할 수 있는 장점이 있다.

이번 프로젝트는 1번을 이용해서 진행한다. (AWS 이용)

먼저 부트스트랩을 사용하기 위해서 부트스트랩을 설치해준다.
그 후 dist폴더 아래의 css폴더에서 bootstrap.min.css를 src/main/resources/static/css/lib로 복사




dist 폴더 아래에 있는 bootstrap.min.js를 src/main/resources/static/js/lib로 복사해준다.

이렇게 하고 다시 IntelliJ를 확인하면 다음과 같이 옮긴 경로에 파일들이 추가된 모습을 볼 수 있다.


이제 설치된 부트스트랩을 사용하기 위해서 main.hbs에 부트스트랩 라이브러리들을 추가해준다.

<title>스프링부트 웹서비스</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <!--부트스트랩 css 추가-->
    <link rel="stylesheet" href="/css/lib/bootstrap.min.css">
...
...
<!--부트스트랩 js, jquery 추가-->
<script src="/js/lib/jquery.min.js"></script>
<script src="/js/lib/bootstrap.min.js"></script>

</body>
</html>

여기서 css와 js, jquery의 경로가 src/main/resources/static/… 으로 시작하지 않는 이유는
Springboot는 기본 경로인 src/main/resources/static 이 / 로 축약되어 정의되기 때문이다.

또한 css와 js, jquery의 라이브러리 추가 위치가 각각 head와 body부분으로 나누어서 추가되었는데
그 이유는 HTML은 코드가 위에서 아래로 순차적으로 실행이 되기 때문에 css, js, jquery가 모두
head부분에 들어가게 되면 화면 실행이 느려질 수 있으므로 화면을 그리는데 사용되는 css만
head부분에 넣어주고 js와 jquery는 body부분으로 빼서 호출하는게 된다.

마지막으로 bootstrap은 jquery라이브러리가 있어야만 실행이 되므로 jquery먼저 호출되도록
코드를 추가해주며, 이런 경우를 bootstrap이 jquery에 의존한다고 한다.

이제 화면을 그리기 위한 모든 준비가 끝났다.

8. 게시글 등록 기능 구현_입력 화면 구현

main.hbs에 다음과 같이 입력 화면을 구현하는 코드를 작성해준다.


<!DOCTYPE HTML>
<html>
<head>
    <title>스프링부트 웹서비스</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />

    <!--부트스트랩 css 추가-->
    <link rel="stylesheet" href="/css/lib/bootstrap.min.css">
</head>
<body>
    <h1>스프링부트로 시작하는 웹 서비스</h1>

    <div class="col-md-12">
        <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#savePostsModal">글 등록</button>
    </div>

    <div class="modal fade" id="savePostsModal" tabindex="-1" role="dialog" aria-labelledby="savePostsLabel" aria-hidden="true">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="savePostsLabel">게시글 등록</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <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>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>
                    <button type="button" class="btn btn-primary" id="btn-save">등록</button>
                </div>
            </div>
        </div>
    </div>

    <!--부트스트랩 js, jquery 추가-->
    <script src="/js/lib/jquery.min.js"></script>
    <script src="/js/lib/bootstrap.min.js"></script>
</body>
</html>

제공해주신 코드를 그대로 가져다 썼다. 이렇게 하면 "글 등록"이라는 버튼이 생성되고,
이 버튼을 클릭시 게시글 등록 modal이 생성되어야 한다. 실제로 localhost:8080으로 확인해주자.



화면이 잘 생성된 모습을 확인할 수 있다. 하지만 아직 취소, 등록 버튼에 기능을 추가하지 않아서

해당 버튼을 눌렀을 때 아무런 변화가 없는 것을 확인 할 수 있다.
등록 버튼에 기능을 추가하기 위해서 다음 단계로 넘어간다.

9. 게시글 등록 기능 구현_등록 버튼 기능 구현

등록 버튼을 눌렀을 때 기능을 주기 위해서 main.js를 구현해준다.

경로 : src/main/resources/static/js/app


이 기능을 사용하기 위해서는 단순히 main.js에 한줄의 코드만 입력해주면된다.(신기)


이제 이 기능이 추가된 메인페이지와, 글 등록 모달이 제대로 구현 되는지 확인해 보겠습니다!

application을 실행 후 localhost:8080으로 접속해줍니다.

아래와 같이 글을 작성해 주고 등록 버튼을 클릭하면 글이 등록되었다는 알람창이 뜨게 됩니다!^_^



위에서 작성한 js파일에서 등록 버튼을 눌렀을 시 save기능까지 되도록 해 주었으므로, 

실제 DB에 데이터가 들어갔는지 확인해줍니다.
localhost:8080/h2-console에서 전에 했던 방법과 동일하게 연결해준 후,
select문을 이용해서 테이블에 저장된 값을 조회하여 확인해줍니다.



등록 모달창에서 작성한 글 그대로 값이 잘 저장된 모습을 볼 수 있다!

너무 뿌듯하네요^_^

다음 단계는 h2 DB에서 값을 확인하지 말고 게시글 목록을 만들어서 값을 확인하는 과정을
진행해 보도록 하겠습니다!

10. 게시글 목록 출력하기

이 프로젝트는 mysql이나 mariaDB같은 DB를 사용하지 않고 H2라는 메모리DB를 사용중이다.
이 DB는 신기하게도 프로젝트를 가동할때마다 새롭게 값들이 저장되도록 테이블에 저장된
내용들이 reset된다고 한다!
이렇게 되면 프로젝트를 가동할 때마다 데이터가 출력되는지 확인하기 위해서는
데이터 등록 - 출력 확인 이라는 두단계의 과정을 거쳐야 한다.

데이터 등록 과정을 건너뛰고 게시글 출력이 잘 되는지를 먼저 확인해 주기 위해서, 테이블에 기본값을 세팅해주는 작업을 해주겠다.

data-h2.sql이라는 이름을 가진 파일을 만들어주고, 다음과 같이 두개의 게시글을 insert해준다.

(사실 sql이라는 확장자를 가지는 파일은 어떻게 만드는지도 헤맸다 프로젝트를 진행할수록 멍청함을 느낀다.. 익숙해지는 날이 얼른 왔음 좋겠다!)

경로 : src/main/resources



이제 이 파일이 프로젝트가 실행될때 같이 실행 되도록 설정을 추가해주어야한다.

그러기 위해서는 application.yml 파일을 수정해준다.


선을 기준으로 상단 영역은 공통영역이되고, 하단은 각 profiles의 설정 영역이라고한다.

profiles: local에서 data-h2.sql을 기본 실행 스크립트로 지정한 것이다.
(자세한건,, 도움을 주실 분들은 설명 부탁드립니다..!)

다시 localhost:8080/h2-console 에 접속하여 데이터 값을 확인해줍니다.



data-h2.sql에 입력한 값 그대로 값이 나온것을 볼 수 있습니다.

이제 게시글 목록UI를 만들어줍니다.

11. 게시글 목록 UI생성

게시글 목록 UI를 만들어 주기 위해서 main.hbs에 아래 코드부분을 추가해줍니다!

아래에서 사용된 handlebars문법은 {{#each posts}}로, 

posts라는 리스트를 순회하는 하나씩 꺼내 각각의 필드값을 채워서 테이블에 출력시키는 문법이라고 합니다.



이제 이 UI를 사용하기 위해서 Controller, Service, Repository코드를 만들어줍니다.

먼저 Repository!

경로 : src/main/resources



다음으로는 Service부분을 만들어줍니다. 기존의 PostsService코드를 변경해줍니다.



놀랍게도 또 Import를 제대로 선택하지 않아서 에러가 납니다. (readOnly)

아래 보이는 Import를 진행해주면 에러가 수정됩니다.

readOnly=True기능은 조회기능만 사용하는 메소드에서 사용하면 조회 속도가 개선된다고 한다!


위에서 사용된 PostsMainResponseDto클래스가 없으므로 dto패키지에 클래스를 생성해줍니다.



View영역에선 LocalDateTime 타입을 모르기때문에 toStringDateTime을 이용해서 날짜를 문자열로

변경해서 저장해주었고, Entity가 DTO에 의존하게 될 경우 변화할 때마다 Entity까지 변경이 필요한
상황을 방지하기 위해서 꼭 DTO가 Entity에 의존하도록 코드륵 작성해 주어야 한다.

정말 마지막으로 WebController를 변경해준다.


@Controller
@AllArgsConstructor
public class WebController {

    private PostsService postsService;

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

이제 드디어 실행만 남았다.

프로젝트를 실행시키고 localhost:8080으로 접속해준다.

12. 결과! 가 아닌 방심하면 생기는 일

접속을 분명히 맞게했는데 주석처리가 제대로 안되어 있다^^;;




주석을 수정해준다..


13. 결과!

기본 등록 값들이 정상적으로 출력되고,


글을 등록하니 등록값도 정상 출력이 된다.(감격)


14. 이번시간에 배운점

매 회차마다 지식이 쌓이는 기분이라 뿌듯하다 물론 에러가 나고 오류가 나면 너무 슬프다

본 글의 댓글을 봐도 나랑 맞는 오류가 없을시엔 나만 모르네,,라는 좌절감이 생기지만

프로젝트를 닫고,, 하루의 휴식을 거쳐서 다시한번 오류를 검색하고 수정해보면 풀리는 성취감을
느끼고 있는 중이다.

다시 한번 오타의 소중함을 느꼈고 글을 쓰면서 과정을 돌아보는 과정이 정말 중요한 것 같다.
실습을 진행할때는 진행을 위해 넘어갔던 개념을 되 짚어보기 때문


반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함