origoni's Blog from Millky

origoni의 스프링 블로그 입니다.

[블로그개발_08] 블로그 글 저장 및 표시 해보기 (Spring Boot + Spring Data JPA + H2)

블로그개발 시리즈 - 다른글 : http://millky.com/@origoni/folder/30/post/list

라이브 데모 : http://blog.millky.com/post/list

자바 웹 개발 시작하기 : http://www.slideshare.net/origoni/presentations




이번 시간에는. 기본적인 데이터 입출력을 진행해보도록 하겠다.
블로그에 글을 쓰고, 읽고, 목록을 표시해 볼 것이다.

지난번에 벌써 얼렁뚱땅 넘어 가긴 했지만...
[블로그개발_02] Spring Boot 와 Spring Data (JPA) 를 이용한 간단한 DB 입출력

...

간단하다고만 써놓았는데 오늘 왜 간단한지 조금..만 더 알아보자.



H2 사용에 대한 변..


이 [블로글개발_??] 시리즈 글을 쓰는 동안에는 DB를 H2를 사용할 생각이다.

자바(스프링부트)로 블로그를 만들면서 웹 프로그래밍을 배워보자는 취지의 글들이어서 DB세팅이나 기타부분은 배제할 생각이다.


H2는 HSQLDB 개발자가 새로 만든 데이터베이스다. (HSQLDB 2 라고 생각하면 된다고 한다 ㅎ)

홈페이지 (http://h2database.com/) 에 가면 장점들이 나오는데.. 빠르고 오픈소스고 내장가능하고 웹브라우저로 확인 가능한 콘솔도 있고 사이즈가 매우 작다고 한다.

그리고 결정적으로 스프링 부트에서 별다른 설정 없이도 그냥! 사용할 수 있다(?!)


그.. 그래서 H2 사용하겠다 ^^; (설득력이 떨어지더라도 이해해주자.)



메이븐으로 설정


그럼 이제 빌드 설정부터 보자. (사실 이전글에 설정 부분이 있는데.. 시리즈 글 처음 쓸 당시 Gradle로 진행하고 있었다가 중간에 Maven으로 바뀌어서 다시 한번 적는다.)


pom.xml에 아래와 같이 dependency를 추가하자.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>


오잉? 이전 글에는 

compile("org.springframework.boot:spring-boot-starter-jdbc")
==
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

부분도 있었는데.. 어디다 빼먹은걸까? 라고 생각하시는 분이 계실수 있겠다.(라고 생각하지만 거기까지 생각하시는 분은 멀써 메이븐 dependency 에 대해 이해하고 계시고 빼도 된다는것을 알고 계신분이겠지...)


왜 생략이 가능한가?



위 처럼 spring-boot-starter-data-jpa가 spring-boot-starter-jdbc를 사용하고 있어서 부트로 Spring Data Jpa를 사용하게 되면 의존성 설정에 의해 jdbc가 자동적으로 들어가게 된다.

깔끔한것이 좋지 않을까? JPA를 사용한다고 하면 DB관련이니 JDBC를 이미 사용중일 것이라고 생각 가능하다.

디펜던시 관리하다보면 특히 메이븐은 빌드 파일이 주저리주저리 너무 길어진다 ㅠㅠ (그래서 그래들로 ㅠㅠ) 이렇게 줄여보는것도 가독성에 도움을 줄 수 있을 것이라 생각한다. (그리고 이클립스가 이쁘게 표시해 주니까 ^^)


그리고 한가지 더 보면 H2 dependency 설정 부분에 버전이 없다.

여기서 스프링 부트의 편리함을 발견해보자.

http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/htmlsingle/#appendix-dependency-versions


라이브러리 버전 관리를 해준다.

우리가 자바로 프로젝트를 하다보면. 정말 많은 주옥같은! 라이브러리 들이 많이 있다. (그래서 자바가 아직도 성장하고 있는거겠지?)

그래도 다른 언어(ㄹ.. 아 아니다..) 보다는 나은 편이긴 하지만. 가끔 라이브러리들끼리 호환이 안된다던지 하는 이슈가 발생한다.

음.. 그래서 라이브러리 버전 관리하는것도 참 일인데.

스프링 부트가 그걸 해준다.

저 위에 명시된 버전들은 일단 기본적으로 호환성 테스트가 된 것들이고. 설사 문제가 있다고 하더라도 많은 스프링 부트를 사용하는 개발자들이 리포트 해줄 것이고 수정해 줄 것이다. (우와 대박!)


이제 곧(오늘로 예정되어있다.) 스프링 부트 1.2.4 가 릴리즈 될 것이다.

https://github.com/spring-projects/spring-boot/milestones



사실 오늘 새벽 일어나서 봤을때 아래처럼... 열려있는 이슈가 많아서...


Due date 를 지킬 수 있을까 걱정했는데. 몇가지 이슈를 1.2.5로 넘기면서 오늘 릴리즈 될 수 있을것 같다 ㅎㅎ


https://github.com/spring-projects/spring-boot/milestones/1.2.4



https://github.com/spring-projects/spring-boot/milestones/1.2.5



여기서 있는 것들은 알려진 버그 들이니 혹시 스프링 부트 사용하다가 이상한 부분이 있으면 먼저 검색해보고 없으면 이슈를 생성해주면 되겠다. (아직 이슈 생성해본적은 없고.. 이상해서 가보니.. 이미 이슈가 발행된 적이 있었다 ^^ 그 글에 임시 해결책도 적혀있어서~ 잘 적용했던 기억이~~ 그런데 뭐더라?)


아.. 잡설... 이렇게 해서 메이븐 설정이 끝났다.



DB 기본 설정


스프링 부트는 설정을 위해 application.yml 파일을 수정해 주면 된다.

음 그런데 이번 DB사용을 때문에 손댈 필요는 없다. 위에 적은것처럼 스프링 부트에서 H2를 기본으로 사용 가능하다!


여기서 스프링 부트의 편리함을 다시 발견해보자.

http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/htmlsingle/#common-application-properties


어 스프링 부트 기본 설정에 비어있는데?

해당 부분은 자동 설정으로 아래 부분에 정의되어있다. 우리가 위에 H2라이브러리를 로드 했다~

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/EmbeddedDatabaseConnection.java

H2(EmbeddedDatabaseType.H2, "org.h2.Driver", "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE")
  (EmbeddedDatabaseType type, String driverClass, String url)


결론은 그래서 설정파일을 수정하지 않으면.

#    jpa:
#        database: H2
#    datasource:
#        url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
#        username: sa
#        password: 
#        driverClassName: org.h2.Driver

이렇게 자동 설정이 된다!


필요한 사항이 있으면 나중에 다시 정의하기로 하고 이번에는 기본값을 사용한다. (참고로 난 기본값을 좋아한다. 기본값은 보통 개발자들이 한참 고민해서 선택된 값이기 때문이다.)



콘솔 보여주기


아까 H2장점 설명하면서 "웹브라우저로 확인 가능한 콘솔도 있고"라고 한 적이 있다.


아래와 같이 설정하면 사용 가능하다!

import org.h2.server.web.WebServlet;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BlogConfig {
@Bean
public ServletRegistrationBean h2servletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new WebServlet());
registration.addUrlMappings("/console/*");
return registration;
}
}


URL과 User Name는 위의 이미지 및 DB설정을 참고하면 된다.


구글의 도움으로 아래의 사이트를 검색해 참고 하였다. (다음엔 다음의 도움을 받을 수 있기를... ㅠㅠ)

http://stackoverflow.com/questions/24655684/spring-boot-default-h2-jdbc-connection-and-h2-console



Post Entity 만들기


드디어! 블로그 개발을 해보자. 우선 기본적인 구성요소로 가보자.

id, subject, content, regDate 요렇게 


import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Post {
@Id
@GeneratedValue
int id;
String subject;

@Column(length = 100000000)
String content;

Date regDate;
//... Getter, Setter (lombok은 다음번에 나오니 걱정말자 ㅋ)
}


DB가 MySQL로 하나만 사용할 것이라면 이런식으로 정의가 가능하다. 

@Column(columnDefinition = "text")

String content;


그냥 큰 값으로 써주면 알아서... DB에 맞는 타입으로 정의 해준다. (이부분은 나중에 다시 이야기 해볼 시간이 있기를...)

이렇게 Entity를 만들었으니 프로젝트를 돌려서 DB 테이블이 잘 생성되었는지 확인해보자.


잘 생겼다 ㅎㅎ 



PostDao를 만들자


DAO는 일반적으로 Data Access Objects 라는 의미로 DB 연결을 담당하는 객체를 말한다.

우선 스프링 데이터 JPA를 사용하기 위해 JpaRepository 상속받아 만들자.


import org.springframework.data.jpa.repository.JpaRepository;
import com.millky.blog.domain.model.entity.Post;
public interface PostDao extends JpaRepository<Post, Integer> {
}


나중에.. Repository 부분도 추가 될것이다. 우선은 요렇게 간단하게 해보자.

(이부분도 자세한 이야기는 나중에 다시 해야 할 듯 하다. DDD도 이야기 해야겠고..........)




컨트롤러를 만들자 


컨트롤러는 많이들 아실 것이라 생각한다.

우선 아래와 같이 최대한 단순하게 만들어 보자. (버전업 할꺼니 조금 이상해도 참자!)


import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.millky.blog.domain.model.entity.Post;
import com.millky.blog.infrastructure.dao.PostDao;
@Controller
@RequestMapping("/post")
public class PostController {
@Autowired
private PostDao postDao;
@RequestMapping("/write")
public String write(Post post) {
post.setRegDate(new Date());
return "redirect:/post/" + postDao.save(post).getId();
}
@RequestMapping("/list")
public String list(Model model) {
List<Post> postList = postDao.findAll();
model.addAttribute("postList", postList);
return "blog";
}
@RequestMapping("/{id}")
public String view(Model model, @PathVariable int id) {
Post post = postDao.findOne(id);
model.addAttribute("post", post);
return "post";
}
}


접근 주소는


/post/write 글 쓰기

/post/list 글 리스트 보기

/post/{id} 글 하나 보기 


요렇게 구성되어 있다.



JSP 파일을 수정하자!


우선 지난시간에 만든 두개의 파일 (blog.jsp와 post.jsp)을 열어서 아래와 같이 수정한다.


blog.jsp

<!-- Main Content -->
<div class="container">
    <div class="row">
        <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
        
<c:forEach var="post" items="${postList}">
<div class="post-preview">
                <a href="/post/${post.id}">
                    <h2 class="post-title">
                        ${post.subject}
                    </h2>
                </a>
                <p class="post-meta">Posted by <a href="#">Origoni</a> on ${post.regDate}</p>
            </div>
            <hr>
</c:forEach>

            <!-- Pager -->
            <ul class="pager">
                <li class="next">
                    <a href="#">Older Posts &rarr;</a>
                </li>
            </ul>
        </div>
    </div>
</div>


post.jsp

<!-- Page Header -->
<!-- Set your background image for this header on the line below. -->
<header class="intro-header" style="background-image: url('http://ironsummitmedia.github.io/startbootstrap-clean-blog/img/post-bg.jpg')">
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <div class="post-heading">
                    <h1>${post.subject}</h1>
                    <h2 class="subheading">부제목</h2>
                    <span class="meta">Posted by <a href="#">Origoni</a> on ${post.regDate}</span>
                </div>
            </div>
        </div>
    </div>
</header>
<!-- Post Content -->
<article>
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                ${post.content}
            </div>
        </div>
    </div>
</article>


뷰 부분에 대해서는 지난번에 간단하게 설명을 하였기에. 우선은 넘어간다.

[블로그개발_04] 스프링 부트(Spring Boot)의 세가지 뷰 (JSP, Velocity, Thymeleaf)

그리고 앞으로도 지속적으로 개선해 갈 것이다.



테스트!


이렇게 수정이 완료되었으면 프로젝트를 실행시키고... 결과가 잘 나오는지 확인을 해보자!


우선 아래의 주소로 접속하여 글을 인서트 해보자.

아직은 글쓰기 폼이 따로 없다.. (역시 다음 시간에...)

http://localhost:8080/post/write?subject=test&content=test



http://localhost:8080/post/1

이렇게 나왔으면 성공이다.


글을 한번 더 쓰고(/post/write?subject=test&content=test) 리스트에도 가보자.


http://localhost:8080/post/list



잘 나온다 ^^


마지막으로 DB에 값이 잘 저장되어있는지 보고 마무리 하자.


해당 DB는 메모리모드로 설정되어있어서 프로젝트를 다시 시작하면 날아간다.

개발 시작단계에서는 이게 더 편할 수도 있다.

나중에 초기화 하는 방법도 알아보도록 하자.


DB 입출력을 진행하는데.. 한줄의 SQL도 없다.

Spring Boot 와 Spring Data JPA 를 사용하면. 정말. 잡다한것 신경쓰지 않고 비지니스 로직만 고민하면서 개발을 진행할 수 있다.



오늘 작업한 코드는 아래를 참고 바란다.

https://github.com/origoni/Spring-Blog/tree/v0.0.8


고생하셨습니다.


역시 오늘도 코드 개발부분은 코딱지(?) 만큼 있고 잡설이 길어진것 같다.

하지만 이 잡설들이 더 중요할 수 있다고 생각한다. 오늘 나름 많이 적었는데 생략한 부분이 더 많을 정도로 아직도 할말이 많다 ㅠㅠ 사실 파고파도 끝은 없을 것이다. 우선은 눈에 보이는 부분부터 하나씩 파보도록 하자.

책도 봐야 하지만 실제 프로토타이핑은 꼭 필요하다고 생각한다. 


오래전에. 지금보다도 더 모를때... 만들었던 PPT가 있다.

http://www.slideshare.net/origoni/java-web-dev0


그때도 하향식으로 접근했다. (응용에서 코어로..)

이번 자바 블로그 개발 시리즈가. 어디까지 파고 갈지는 모르겠지만. 시작했으니... 


일단 오늘은 끝!



글 다쓰고 보니. ㅠㅠ




스프링 부트 공식 문서 : http://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html

프로젝트 시작하는 방법은(for Windows User)? http://millky.com/@origoni/post/1145

블로그개발 시리즈 - 다른글 : http://millky.com/@origoni/folder/30/post/list



wow1514 2016-03-22 16:30:03

현재 글순서가 엉킨건가요?
포스팅 순서대로 따라가고 있는데 post.jsp를 만든적이 없는데 post.jsp를 열라고 하시는군요... 일단 깃에서 받은 코드들을 보면서 따라가고 있기는 한데 이게 항상 최신버전으로만 있으니 포스팅 진도와는 달라서 약간? 이해하기가 어렵네욥

testho 2018-05-29 14:14:13

코드가 오류도 많고 .. 동작 안하고 .. 이상하네요

joowon 2018-08-24 15:00:50

블로그 잘 참고하고 있습니다~~감사해요
back to top