Develope Me!

[SpringBoot] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 게시글 등록 화면 만들기 본문

Java/SpringBoot

[SpringBoot] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 게시글 등록 화면 만들기

코잘알지망생 2022. 3. 13. 21:15

이번엔 게시글 등록 화면을 구현해보고자 한다.

PostsApiController 에서 API를 구현했기 때문에 바로 외부 CDN을 사용하는 방법으로 프론트엔드 라이브러리를 사용하여 화면을 만들것이다.

(실제 서비스에서는 외부 서비스에 문제가 생기면 같이 문제가 생겨버릴 수 있기 때문에 이 방법을 잘 사용하지 않는다고 한다.)

 

 

부트스트랩, 제이쿼리 라이브러리를 inder.mustache 파일에 추가해야 하는데 바로 추가하는 것이 아닌 레이아웃 방식으로 추가하고자 한다.

*레이아웃 방식: 공통 영역을 별도의 파일로 분리해놓고 필요한 곳에 가져다 쓰는 방식

src/main/resources/templates 디렉토리에 layout 디렉토리를 추가하여 레이아웃파일(footer,header)을 생성해줬다.

공통 코드는 깃허브의 코드를 참고하여 추가했다. 

 

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

</body>
</html>

 

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>

책 설명에 의하면  페이지 로딩 속도를 높이기 위해서 css는 header에 js는 footer에 위치됐다고 한다.

HTML은 head가 다 실행되고 난뒤 body가 실행된다. 

특히 js 용량이 크다면 body부분의 실행이 늦어질 수 있기 때문에 js는 하단에 위치시켜 화면이 다 그려진 뒤 호출하는 것이 좋다고 한다.

그래서 화면을 그리는 역할을 하는 css를 head에서 불어왔다.

추가로 bootstrap.js의 경우엔 제이쿼리가 꼭 있어야 해서 부트 스트랩보다 먼저 호출되도록 코드가 작성됐다. 

라이브러리를 비롯한 기타 HTML태그들이 레이아웃에 추가되었기 때문에 이제 index.mustache에는 필요코드만 남게 된다. 

 

index.mustache

<body>
{{>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}}
</body>

기존 index파일에 footer와 header 그리고  a태그 를 이용해 글 등록 페이지로 이동하는 글 등록 버튼을 추가해줬다.

이후 이동할 페이지의 주소인 posts/save에 해당하는 컨트롤러를 생성해준다.

*{{>}}: 현재 머스테치 파일을 기준으로 다른 파일을 가져올 수 있음

 

IndexController

...
@GetMapping("/posts/save")
    public String postsSave(){
        return "posts-save";
    }

페이지 관련 컨트롤러에 해당하는 indexController에  /posts/save를 호출하면 posts-save.mustache를 호출하는 메소드를 추가해줬다.

코드를 추가해줬다면 posts-save.mustache 파일을 생성해준다.

 

posts-save.mustache

{{>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="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>
        <a href="/" role="button" class="btn btn-secondary">취소</a>
        <button type="button" class="btn btn-primary" id="btn-save">등록</button>
    </div>
</div>

{{>layout/footer}}

 

 

ui를 완성한 뒤 로컬호스트로 실행을 했다.

아직 게시글 등록 화면에 등록 버튼은 API를 호출하는 JS가 없기 때문에 기능이 없다.

src/main/resources에 static/js/app 디렉토리를 추가해서 index.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',
            dataType: 'json',
            contentType:'application/json; charset=utf-8',
            data: JSON.stringify(data)
        }).done(function() {
            alert('글이 등록되었습니다.');
            window.location.href = '/';  // 글 등록 성공 -> 메인페이지(/)로 이동
        }).fail(function (error) {
            alert(JSON.stringify(error));
        });
    }
};

main.init();

index라는 변수의 속성으로 function을 추가해줬다. 그 이유는 뭘까?

 

var init = funtion(){
	...
};

var save = function(){
	...
};

init();

만약 index.mustache에 a.js가 추가되었다고 가정했을 때 a.js도 a.js만의 init과 save function이 있다면 어떻게 될까?

 

브라우저의 scope는 공용 공간으로 쓰기 때문에 나중에 로딩된 js의 init, save가 먼저 로딩된 js의 function을 덮어쓰게 된다.

여러 사람이 프로젝트 에서는 중복된 함수 이름이 발생할 수 있는데 그때마다 모든 funtion의 이름을 확인할 수는 없다.

이런 중복의 문제를 피하기 위해  index.js만의 유효범위(scope)를 만들어서 사용해준다.

var index 객체를 만들고 해당 객체에 필요한 모든 function을 선언해준다.

이렇게 하면 index 객체 안에서만 function이 유효하기 때문에 다른 js와의 중복의 위험을 없애준다. 

(최신 JS 버전이나 앵귤라,리액트,뷰 등은 이미 이런 기능을 지원하고 있다고도 한다)

 

그럼 생성된 index.js를 머스테치 파일에서 사용하기 위해 footer.mustache에 추가해준다. 

 

footer.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에 js 파일을 추가해줬다면 다시 localhost로 뷰를 출력해보자!

 

등록 성공 alert
DB 확인

등록이 성공됐다는 alert 메시지를 확인한 뒤 DB에 게시글이 잘 등록되었는 지를 확인했다!

 

 

Comments