진짜 개발자
본문 바로가기

FrameWork/Spring Boot

SpringBoot - SpringBoot로 웹 개발하기 - 3(게시판 글작성 기능 추가)

728x90
이동욱님의 SpringBoot로 웹서비스 출시하기를 보고 공부하기 3번째 포스팅입니다

이동욱님의 SpringBoot로 웹서비스 출시하기를 보고 공부하기 3번째 포스팅입니다. 이번 포스팅에서는 Handlebars template 엔진을 이용해 간단히 main페이지를 만들고, 게시판 작성기능을 구현하도록 하겠습니다.

 

 

1. Handlebars로 화면 만들기

1.1 의존성 추가

build.gradle에 위와 같이 의존성을 추가합니다.(implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.0')

*SpringBoot 2.X 버젼을 사용하신다면 handlebars의 version을 0.3.X 를 사용해야 합니다.

 

 

1.2 main 페이지 작성

이번에는 main 페이지를 작성하겠습니다.

 

handlebars의 기본 경로는 src/main/resources/templates 입니다. 따라서 위와 같이 src/main/resources/templates 하위에 main.hbs 파일을 추가합니다. (SpringBoot에서 handlebars를 지원하므로 별도의 resolver를 등록하지 않아도 controller에서 template을 찾을 수 있습니다.)

 

그 후 위와 같이 작성합니다.

 

 

1.3 Controller 추가

main를 응답해줄 Controller를 작성하겠습니다. 우선 web 패키지 하위에 WebController class를 추가합니다.

 

그 후 위의 코드를 추가합니다.

 

 

1.4 Controller Test 하기

방금 작성한 WebController를 테스트 하기 위해 src/test/java/galid/com/ldw_study/web/ 하위에 WebControllerTest class를 생성합니다.

 

위와 같이 방금 작성한 Controller에 요청을 보내는 테스트 코드를 작성합니다. 위의 코드는 페이지를 요청을 보낸 페이지가 제대로 응답되는지에 대한 테스팅을 하는 코드입니다. '/' 로 요청시 main.hbs를 응답하도록 했습니다. html도 따지고 보았을때는 어떠한 규격을 따르는 문자열코드 입니다. 따라서 main.hbs에 작성했던 일부내용이 응답페이지에 담겨있는지만 확인하면 됩니다.

 

테스팅에 성공했습니다 ~

 

어플리케이션을 실행한 뒤 실제 웹에서 호출해보면 ~ 성공입니다!

 

 

2. 게시판 글 작성기능 구현

2.1 Service Class 생성

사용자의 요청에 의해 특정 로직을 처리하는 코드를 보통은 service클래스 라고 합니다. MVC 패턴을 배웠다면 이해하실 수 있을 겁니다.

 

앞서 작성한 Contoller에서는 직접 Dao객체(PostsRepository)를 참조하여 로직을 작성하지 않고, 해당 요청시 처리할 로직을 service에게 위임하여 처리한 뒤 적절한 view를 return만 해줍니다. 이렇게 함으로써, Controller와 Service의 역할을 분리하고, Controller는 앞서 말씀드린 적절한 Service 요청, View 반환의 역할만 합니다.

 

우선 service 패키지를 생성한 뒤 PostsService 클래스를 생성합니다.

 

@Service

다들 아시다시피 해당 class를 Bean으로 등록하는 어노테이션입니다.

@Transactional

이 어노테이션은 트랜잭션 처리를 간편하게 도와주는 어노테이션입니다.

위와 같이 하나의 dto만을 등록할때에는 크게 문제가 없지만, 예를 들어 여러개의 dtos를 등록한다고 했을 때, 몇개의 dto만 저장되고 나머지는 저장이 되지 않는다면 큰 문제가 발생할 것입니다. 따라서 모든 dto가 정상저장 되었을때에만 commit하고 예외가 발생하면 rollback해주는 어노테이션 입니다.

DB에 데이터를 등록/수정/삭제 하는 경우에는 필수적으로 이 어노테이션을 부여한다고 합니다.

 

 

2.2 Service Test 작성

테스트 디렉토리 하위에 service 패키지를 만들고 PostsServiceTest 클래스를 생성합니다.

 

그 후 위와 같이 테스트 코드를 작성합니다. 허나 위와 같이 dto를 생성하기 위해서는 @Builder를 추가해주어야 합니다. 바로 추가하러 가보겠습니다.

 

@Builder, @AllArgsConstructor을 추가해주었습니다. @Builder를 사용하기 위해서는 매개변수를 가지는 생성자를 생성해야합니다. 이 때 @AllArgsConstructor을 통해 모든 필드를 매개변수로 가지는 생성자를 생성했습니다. Entity와는 다르게 매개변수로 받지 않아도되는 불필요한 값, 예를들자면 id(auto_increment)와 같은 필드가 없기 때문에 AllArgsConstructor을 사용했습니다.

 

다시 PostsServiceTest로 돌아와 테스트를 하면! 성공입니다.

 

 

2.3 게시판 글작성 Template 만들기

이번에는 게시판 글작성 template을 만들겠습니다.

 

2.3.1 Bootstrap(css, js), jquery 설정

css, js 는 부트스트랩을 이용할 것입니다.

 

위 그림과 같이 bootstrap 홈페이지로 접속하여 css cdn 주소를 복사하고, 페이지 상단의 <head>태그안에 기입합니다.

 

부트스트랩의 css들은 javascript들을 기반으로 동작하는 것들이 많기 때문에 별도의 js(javascript 파일)도 제공해줍니다. 역시 복사합니다. bootstrap에서 제공하는 jquery 의 cdn주소에 문제가 있는것인지 잘 설정을 못하는 것인지는 모르겠지만 문제가 있습니다. 따라서 jqeury의 경우 별도로 jquery 홈페이지에서 얻어올 것입니다.


 우선은 아래의 2개의 js주소만을 복사합니다. *위의 bootstrap.min.js의 경우 jquery가 꼭 필요하기 때문에 jquery가 먼저 로딩되어야 합니다. 때문에 jquery관련 cdn을 더 먼저 작성해야합니다. 


 또한, js관련 로딩은 페이지의 body태그 가장 하단에 적어줍니다. 이렇게 함으로써 페이지 로딩 속도를 높일 수 있습니다. 이유는 이 포스팅의 마지막 부분인 에서 알려드리겠습니다.

 

위와 같이 jqeury cdn 홈페이지로 접속하여 jqeury 3.x 버젼의 slim을 클릭하면, cdn주소를 제공해줍니다. 이를 복사하여 위의 js들의 가장 상위에 붙혀넣습니다.

 

 

2.3.2 글작성 template 작성

글 작성 모달창을 띄우는 간단한 버튼입니다.

- 먼저 class = "col-md-x" 는 bootstrap의 grid 지원 시스템입니다. 다음 링크를 참고해주세요. http://bootstrapk.com/css/#grid

- button의 class="btn btn-primary"는 위의 그림과 같이 버튼의 디자인을 만들어주는 class 입니다.

- data-toggle="modal"의 경우 bootstrap에서 지원하는 js입니다. 간단히 말씀드리면 modal창을 띄울 수 있도록 만들어주는 기능입니다.

- data-target="#savePostsModal"은 #뒤에 적힌 id값에 해당하는 컴포넌트를 modal창으로 띄워주는 역할을 합니다.

 

다음은 modal 창의 내용을 작성합니다. 앞서 만든 button으로 위의 modal창을 띄우기 위해 id를 savePostsModal로 맞춥니다. class="modal fade" 은 해당 div 안의 내용들을 modal창으로 인식하게 만듭니다.

 

결과 화면 입니다. 버튼을 누르면 방금 작성한 div안의 내용이 나타남을 볼 수 있습니다. 현재 등록 버튼에는 아무런 기능을 부여하지 않은 상태입니다. 등록 버튼의 기능을 만들기 위한 js를 만들겠습니다.

 

resources/static/js/app 하위에 main.js 파일을 생성합니다.

 

main.js에 위와같이 코드를 작성합니다. main이라는 객체에 2가지 함수를 변수로 가지게 했습니다.

init()

init() 함수의 경우 main.hbsbtn-save라는 id를 가지는 버튼에 리스너를 추가합니다. 해당 리스너가 호출할 함수는 아래에서 작성할 save() 함수입니다.

save()

save() 함수의 data변수에는 main.hbstitle, author, content라는 id를 가지는 컴포넌트의 값들을 각각 title, author, content라는 변수에 담습니다. 또, 이 data변수를 string으로 변환한 뒤 body에 담아 /posts에 요청을 보냅니다.

마지막으로 main.init()을 호출하여 이 js가 로딩될 때 init()메소드를 실행하여 버튼에 리스너를 등록하도록 했습니다. 각각의 함수를 main이라는 변수안에 따로 생성한 이유는 에서 설명 드리겠습니다.

 

방금 작성한 js를 추가해줍니다.

 

 

2.3.3 확인

application을 실행하고 글을 등록합니다.

 

h2 console에 접속하여 확인하면 ? 방금 기입한 데이터가 추가된것을 볼 수 있습니다.

 

 

 

 

1. Handlebars

1.1 Handlebars를 사용하면 좋은 이유

Springboot에서는 jsp, freemaker, velocity 등의 여타 template 엔진을 지양한다고 합니다. 업데이트가 거의 되지 않고 있기 때문입니다. 반면에 handlebars는 꾸준한 업데이트를 해오고 있다고 합니다. 또한, 아래의 이유 때문입니다.

- 문법이 간단하다

- 로직 코드를 사용할 수 없기 때문에 View의 역할, Server의 역할이 명확히 구분된다.

 

1.2 Handlebars Plugin

IDE로 intellij를 사용하고 계시다면, 위의 플러그인을 사용하시는 것을 추천합니다. 문법체크 등의 지원을 받을 수 있다고 합니다. (문법체크 참 중요합니다..)

 

2. CSS

bootstrap 프레임워크를 이용하는 방식은 CDN 방식, 라이브러리를 직접 다운로드하는 방식 두가지가 존재합니다. 제 포스팅에서는 cdn방식을 이용했습니다만, 실제 배포환경에서는 cdn을 거의 사용하지 않는다고 합니다. 어플리케이션이 cdn서버에 의존하게 되기 때문이라고 합니다.

 

3. html 작성 팁 (페이지 로딩속도 향상)

앞서 main.hbs에 bootstrap cdn코드와, jqeury cdn 코드의 위치를 나누어 작성한 것을 볼 수 있습니다. 왜그럴까요? 바로 페이지의 로딩속도를 향상시키기 위함입니다.

 

왜 위아래에 나누어 작성하는 경우 로딩속도가 향상될까요? html의 경우 위에서부터 차례로 코드가 실행되기 때문에, head의 로딩이 다 되지 않으면 웹 브라우저에서는 백지 화면만이 보이게 됩니다. 따라서 head에서 모든 로딩을 하게 된다면 그만큼 느려지게 됩니다.

 

css의 경우,

화면을 직접적으로 그리는데 필요한 역할(디자인) 이므로 head에서 로딩해오는 것이 맞습니다.

js의 경우,

기능적인 측면을 담당하기 때문에 화면이 그려진 후 불러오도록 해도 됩니다.

 

 

4. js 함수들을 또 변수안에 담는 이유

main.hbs에서 등록버튼에 기능을 추가하기 위해 main.js를 작성할 때, var main이라는 변수에 함수들을 담아서 사용했었습니다. 왜그럴까요? 하나의 js만을 불러사용하는 경우에는 문제가 되지 않지만 main.js에서 또다른 기능이 필요하여 a.js를 추가한 경우에 문제가 발생됩니다. 물론 특정상황입니다.

 

그 특정상황이란 다음과 같습니다. main.js에서 작성한 함수이름과 a.js의 함수이름이 같은 경우입니다. 브라우저는 scope을 공용으로 사용합니다. 따라서 여러개의 js에서 같은 이름의 함수를 사용하는 경우 가장 마지막에 불려진 js의 것을 사용하게 된다고합니다.

 


5. Handlebars template작성 예제

http://handlebarsjs.com/builtin_helpers.html