카테고리 없음

231215_점프 투 스프링부트, JPA (1)

Seungyeon.Jung 2023. 12. 15. 16:43

점프 투 스트링부트

 

점프 투 스프링부트

점프 투 스프링부트는 Spring Boot Board(SBB)라는 이름의 게시판 서비스를 만들어가는 과정을 설명한 스프링부트 입문서이다. 자바 설치부터 시작하여 서비스 운…

wikidocs.net


데이타베이스를 사용하려면 SQL 쿼리로 구조화된 질의를 작성하고 실행하는 과정이 필요하다. 이 때 ORM을 ㅣㅇ용하면 자바 문법으로 데이터베이스를 다룰 수 있는데, ORM을 이용해서 쿼리를 작성하지 않아도 데이터베이스의 데이터를 처리할 수 있다.

ORM은 데이터베이스에 데이터를 저장하는 테이블을 자바 클래스로 만들어 관리하는 기술이다. 

DB에는 이런걸 해야 하는데 백 앤드를 개발하는 사람이 DB와 SQ:까지 다 공부하기엔 부담스럽다는 것. 그래서 ORM이라는 기술을 이용하면 SQL구문을 쓰지 않고도 작성할 수 있다. ORM을 이용하면 데이터베이스 종류에 상관 없이 일관된 코드를 유지할 수 있어서 프로그램을 유지·보수하기가 편리하다. 또한 내부에서 안전한 SQL 쿼리를 자동으로 생성해 주므로 오류 발생률도 적다.

//테이블에 새로운 데이터를 삽입하는 쿼리는 보통 다음처럼 작성한다.
insert into question (subject, content) values ('안녕하세요', '가입 인사드립니다 ^^');
insert into question (subject, content) values ('질문 있습니다', 'ORM이 궁금합니다');

//ORM을 사용하면 쿼리 대신 자바 코드로 다음처럼 작성할 수 있다.
Question q1 = new Question();
q1.setSubject("안녕하세요");
q1.setContent("가입 인사드립니다 ^^");
this.questionRepository.save(q1);

Question q2 = new Question();
q2.setSubject("질문 있습니다");
q2.setContent("ORM이 궁금합니다");
this.questionRepository.save(q2);

 

JPA 란?

스프링부트는 JPA(Java Persistence API)를 사용하여 데이터베이스를 처리한다. JPA는 자바 진영에서 ORM(Object-Relational Mapping)의 기술 표준으로 사용하는 인터페이스의 모음이다. 

JPA는 자바에서 사용하는 ORM의 한 종류

PRM이라는건 SQL을 내가 몰라도 랭귀지 API측면에서 데이타베이스를 다룰 수 있는 기술을 총칭해서 ORM이라고 하는 것이다. 이 기술을 자바에서도 지원하기 시작했는데, 자바에서 제공하기 시작한 이것의 이름이 JAP이다.


스프링부트란?

스프링부트(Spring Boot)는 자바의 웹 프레임워크로 기존 스프링 프레임워크(Spring Framework)에 서버를 내장하고 편의 기능을 추가한 프레임워크. 즉, 스프링부트는 웹 프로그램을 쉽게 만들어주는 웹 프레임워크다. 

 

웹 프레임워크란?

웹프로그램을 만들기 위해서는 쿠키나 세션 처리 등 많은 기능을 만들어야 하는데, 웹 프레임워크를 사용하면 그런 기능들이 이미 만들어져 있기 때문에 일일이 만들 필요가 없다. 결국 웹 프레임워크는 웹 프로그램을 만들기 위한 스타터 키트라고 생각하면 된다. 그리고 자바로 만들어진 웹 프레임워크 중 하나가 바로 스프링부트이다.

스프링부트는 SQL 인젝션, XSS(cross-site scripting), CSRF(cross-site request forgery), 클릭재킹(clickjacking)과 같은 보안 공격을 기본으로 막아 주며, 2012년에 등장하여 10년 이상의 세월을 감내한 안정화 된 웹 프레임워크이다.

스프링부트 대신 스프링만 사용하여 웹 애플리케이션을 개발한다면 웹 애플리케이션을 실행할 수 있는 톰캣과 같은 WAS(Web Application Server)가 필요하다. 하지만 스프링부트에는 톰캣 서버가 내장되어 있고 설정도 자동 적용되기 때문에 여러분은 WAS에 대해서 전혀 신경쓸 필요가 없다. 심지어 배포되는 jar 파일에도 톰캣서버가 내장되어 실행되므로 서로 다른 WAS들로 인해 발생되는 문제들도 사라진다. 

 

스프링부트는 설정이 쉽다. 스프링부트 이전에 스프링만을 사용하여 웹 애플리케이션을 만들어 보았다면 상당히 복잡한 설정들로 인해 많은 어려움을 겪었을 것이다.  하지만 스프링부트는 스프링의 복잡한 설정을 자동화하고 단순화 하여 누구나 스프링을 쉽게 사용할 수 있게 만들었다. 


1-02 자바 설치하기

JDK 설치

 

Download the Latest Java LTS Free

Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.

www.oracle.com

깔려있는 JDK 확인
자바 버전 확인

새로운 스프링부트 프로젝트 sbb를 생성하고, helloController.java 클래스를 만들었다. 이후 HelloWorld 를 출력하기 위해 아래와 같이 작성했다, 

package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello World";
    }
}

get 방식은 더 많은 데이터를 보낼 수 잇고, post 는 내부에 데이터를 넣어서 보내기 때문에 길이 제한이 있을 수 있다. 

클래스명 위에 적용된 @Controller 애너테이션은 HelloController 클래스가 컨트롤러의 기능을 수행한다는 의미이다. 이 애너테이션이 있어야 스프링부트 프레임워크가 컨트롤러로 인식한다. hello 메서드에 적용된 @GetMapping("/hello") 애너테이션은  http://localhost:8080/hello URL 요청이 발생하면 hello 메서드가 실행됨을 의미한다. 즉, /hello URL과 hello 메서드를 매핑하는 역할을 한다.

 

  • URL명과 메서드명은 동일할 필요는 없다. 즉 /hello URL일 때 메서드명을 hello가 아닌 hello2와 같이 해도 상관없다.
  • Get 방식의 URL 요청은 GetMapping을 사용하고 Post 방식의 URL 요청은 PostMapping을 사용한다.

 

그리고 @ResponseBody 애너테이션은 hello 메서드의 응답 결과가 문자열 그 자체임을 나타낸다. hello 메서드는 "Hello World" 라는 문자열을 리턴하므로 출력으로 "Hello World" 문자열이 나갈 것이다.

서버가 실행되었으니 이제 HelloController의 동작을 확인해 보자. 브라우저를 실행하고 주소에 http://localhost:8080/hello라고 입력해 로컬 서버를 확인해보자.

 

로컬서버는 디폴트로 8080 포트로 실행된다.

 

로컬서버 동작 결과


Spring Boot Devtools

이전 장에서 작성했던 HelloController를 다음과 같이 수정한다.

출력하는 문자열을 "Hello World"에서 "Hello SBB"로 변경했다. 하지만 이렇게 수정하고 http://localhost:8080/hello URL을 호출하더라도 여전히 "Hello World" 문자열이 출력된다. 프로그램이 변경되더라도 로컬서버가 변경된 클래스를 리로딩하지 않기 때문이다. Spring Boot Devtools는 스프링부트 개발시 도움을 주는 도구로, 클래스 변경시 서버 재시작 없이도  서버가 자동으로 재기동 된다.

package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello SBB";
    }
}

Spring Boot Devtools를 사용하기 위해서는 그레이들(Gradle)로 설치해야 한다. build.gradle 파일을 아래와 같이 수정했다.

[파일명: /sbb/build.gradle]

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
}

build.gradle 파일의 내용을 적용하려면 다음처럼 build.gradle 파일을 선택한후 오른쪽 마우스 버튼을 눌러 [Gradle -> Refresh Gradle Project]를 선택하여 필요한 라이브러리를 다운로드해야 한다. 설치가 완료되면 다음과 같이 Boot Dashboard의 서버명이 sbb에서 sbb[devtools]로 바뀌고, 서버를 재시작 하면 "Hello SBB" 라는 문자열이 출력된다.

이제 Spring Boot Devtools가 적용되었으니 브라우저에서 다시 http://localhost:8080/hello URL을 호출해 보자. 서버를 재시작 했기 때문에 "Hello SBB" 라는 문자열이 출력될 것이다. 서버 재시작 없이도 변경사항이 적용되는지 확인하기 위해 출력 문자열을 다음과 같이 다시 변경한다.

package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello Spring Boot Board";
    }
}


Live Reload

Live Reload 설치

 

LiveReload++

Watches a port and reloads the page if needed.

chrome.google.com

 

STS에서 프로그램을 수정하면 서버는 물론 브라우저도 리로딩되어 변경된 내용을 추가 작업 없이 즉시 확인할 수 있다.


lombok

자바 클래스에 Getter, Setter, 생성자 등을 자동으로 만들어 주는 도구이다. SBB 프로젝트를 진행하면서 데이터를 처리하기 위한 엔티티 클래스나 DTO 클래스등을 사용해야 하는데 롬복(lombok)을 사용하면 좀 더 깔끔한 소스코드를 만들수 있다.

lombok 설치

본인은 STS가 아닌 이클립스에 톰겟을 사용할 예정으로 설치 시 아래 블로그를 참고했다.

https://cocococo.tistory.com/37

 

[Spring Boot] 이클립스(Eclipse) 롬복(LOMBOK) 설치 및 어노테이션 (Annotation) 사용 방법

Lombok 롬복 라이브러리를 이용하면 getter, setter, builder, constructor를 작성하는데 시간을 소모할 필요가 없다. 롬복이 제공하는 어노테이션 프로세스가 자동으로 작성해 준다. 1. Lombok 설치 방법 1-1) h

cocococo.tistory.com

 

내가 사용하고 있는 eclipse 경로에 롬켓을 이동한 뒤, 이클립스가 자동으로 잡힌다면 Install 받고, IDEs를 찾지 못한다면 Specify locaion을 선택하여 Eclipse.exe파일을 선택한 후 Install 받는다.

프로젝트 우클릭 → Properties 클릭

이후 어노테이션 프로세서를 설정한다. 이후 Eclipse 다시 시작한후 build.gradle 파일을 다음과 같이 수정한다. build.gradle 파일을 수정한 후에는 반드시 [Gradle -> Refresh Gradle Project]를 선택하여 라이브러리를 다운로드 해야 한다.

(... 생략 ...)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

(... 생략 ...)

Getter, Setter

다음처럼 HelloLombok 클래스를 작성하여 롬복이 정상적으로 동작하는지 확인해 보자. 아래 코드 작성시 오류가 없어야 한다. 

[파일명:/sbb/src/main/java/com/mysite/sbb/HelloLombok.java]

package com.mysite.sbb;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class HelloLombok {

    private String hello;
    private int lombok;

    public static void main(String[] args) {
        HelloLombok helloLombok = new HelloLombok();
        helloLombok.setHello("헬로");
        helloLombok.setLombok(5);

        System.out.println(helloLombok.getHello());
        System.out.println(helloLombok.getLombok());
    }
}

HelloLombok 클래스에 hello, lombok 2개의 속성을 추가한 후 클래스명 바로 위에 @Getter, @Setter라는 애너테이션을 적용했더니 Getter, Setter 메서드를 추가하지 않아도 setHello, setLombok, getHello, getLombok 등의 메서드를 사용할수 있게 되었다.


RequiredArgsConstructor

이번에는 HelloLombok 클래스를 다음과 같이 수정해 보자.

package com.mysite.sbb;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
@Setter
public class HelloLombok {

    private final String hello;
    private final int lombok;

    public static void main(String[] args) {
        HelloLombok helloLombok = new HelloLombok("헬로", 5);
        System.out.println(helloLombok.getHello());
        System.out.println(helloLombok.getLombok());
    }
}

hello, lombok 속성에 final을 적용하고 롬복의 @RequiredArgsConstructor 애너테이션을 적용하면 해당 속성을 필요로하는 생성자가 롬복에 의해 자동으로 생성된다


2-01 스프링부트 프로젝트의 구조

src/main/java 디렉터리

src/main/java 디렉터리의 com.mysite.sbb 패키지는 자바 파일을 작성하는 공간이다. 자바 파일로는 HelloController와 같은 스프링부트의 컨트롤러, 폼과 DTO, 데이터 베이스 처리를 위한 엔티티, 서비스 파일등이 있다.

SbbApplication.java 파일

모든 프로그램에는 시작을 담당하는 파일이 있다. 스프링부트 애플리케이션에도 시작을 담당하는 파일이 있는데 그 파일이 바로 <프로젝트명> + Application.java 파일이다. 스프링부트 프로젝트를 생성할때 "Sbb"라는 이름을 사용하면 다음과 같은 SbbApplication.java 파일이 자동으로 생성된다.

src/main/resources 디렉터리

src/main/resources 디렉터리는 자바 파일을 제외한 HTML, CSS, Javascript, 환경파일 등을 작성하는 공간이다.

templates 디렉터리

src/main/resources 디렉터리의 하위 디렉터리인 templates 디렉터리에는 템플릿 파일을 저장한다. 템플릿 파일은 HTML 파일 형태로 자바 객체와 연동되는 파일이다. templates 디렉터리에는 SBB의 질문 목록, 질문 상세 등의 HTML 파일을 저장한다.

static 디렉터리

static 디렉터리는 SBB 프로젝트의 스타일시트(.css), 자바스크립트(.js) 그리고 이미지 파일(.jpg, .png) 등을 저장하는 공간이다.

application.properties 파일

application.properties 파일은 SBB 프로젝트의 환경을 설정한다. SBB 프로젝트의 환경, 데이터베이스 등의 설정을 이 파일에 저장한다.

src/test/java 디렉터리

src/test/java 디렉터리는 SBB 프로젝트에서 작성한 파일을 테스트하기 위한 테스트 코드를 작성하는 공간이다. JUnit과 스프링부트의 테스팅 도구를 사용하여 서버를 실행하지 않은 상태에서 src/main/java 디렉터리에 작성한 코드를 테스트할 수 있다.

build.gradle 파일

그레이들(Gradle)이 사용하는 환경 파일이다. 그레이들은 그루비(Groovy)를 기반으로 한 빌드 도구로 Ant, Maven과 같은 이전 세대 빌드 도구의 단점을 보완하고 장점을 취합하여 만든 빌드 도구이다. build.gradle 파일에는 프로젝트를 위해 필요한 플러그인과 라이브러리 등을 기술한다.


2-02 컨트롤러

URL 매핑

브라우저에서 http://localhost:8080/sbb 페이지를 요청했을 때 "안녕하세요 sbb에 오신것을 환영합니다."라는 문자열을 출력하도록 만들어 보자.  Boot Dashboard의 시작 버튼을 눌러 로컬서버를 먼저 구동하자.

404 오류는 브라우저가 요청한 페이지를 찾을 수 없을 경우에 발생한다.

오류가 발생한 원인은 스프링부트 서버가 http://localhost:8080/sbb라는 요청을 해석할 수 없기 때문이다. 그렇다면 오류를 해결하기 위해 컨트롤러를 작성하고 /sbb URL에 대한 매핑을 추가해서 페이지 요청이 발생하면 스프링부트는 가장 먼저 컨트롤러에 요청된 페이지의 URL 매핑이 있는지를 조사하게 만든다.

 

컨트롤러

URL 매핑을 추가하기 위해 MainController 클래스를 생성해 아래와 같이 작성하고, URL을 호출했다.

package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MainController {

    @GetMapping("/sbb")
    public void index() {
        System.out.println("index");
    }
}

MainController 클래스에 @Controller 애너테이션을 적용하면 MainController 클래스는 스프링부트의 컨트롤러가 된다. 그리고 메서드의 @GetMapping 애너테이션은 요청된 URL과의 매핑을 담당한다. 서버에 요청이 발생하면 스프링부트는 요청 페이지와 매핑되는 메서드를 컨트롤러를 대상으로 찾는다. 즉, 스프링부트는 http://localhost:8080/sbb 요청이 발생하면 /sbb URL과 매핑되는 index 메서드를 MainController 클래스에서 찾아 실행한다.

 

@GetMapping에 http://localhost:8080 과 같은 도메인명과 포트는 적지 않는다. 왜냐하면 도메인명과 포트는 서버 설정에 따라 변하기 때문이다.

 

500 오류코드는&nbsp; 호출시 MainController의 index 함수는 호출되었지만 오류가 발생한 것. 즉, 함수가 잘못 작동 했다는 뜻이다.

이번에도 오류가 발생한다. 하지만 404 오류가 아닌 500 오류코드로 바뀐것을 확인할 수 있다. http://localhost:8080/sbb 호출시 MainController의 index 함수는 호출되었지만 오류가 발생한 것이다. URL과 매핑된 함수는 결괏값을 리턴해야 하는데 아무런 값도 리턴하지 않기 때문에 오류가 발생한 것이다. 오류를 해결하려면 클라이언트(브라우저)로 응답을 리턴해야 한다. 오류코드 목록은 아래를 참고할 것.

오류코드 목록

 

HTTP 상태 코드 - HTTP | MDN

HTTP 응답 상태 코드는 특정 HTTP 요청이 성공적으로 완료되었는지 알려줍니다. 응답은 5개의 그룹으로 나누어집니다: 정보를 제공하는 응답, 성공적인 응답, 리다이렉트, 클라이언트 에러, 그리고

developer.mozilla.org

 

콘솔 로그를 보면 index 메스드에서 실행한 System.out.println("index");가 실행되어 "index"라는 문자열이 출력된 것을 확인할 수 있다. 다음과 같이 MainController를 수정하자.

 

package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MainController {

    @GetMapping("/sbb")
    @ResponseBody
    public String index() {
        return "index";
    }
}

응답으로 "index"라는 문자열을 브라우저에 출력하기 위해 index 함수의 리턴값을 String으로 변경하고 "index"라는 문자열을 리턴했다. @ResponseBody 애너테이션은 URL 요청에 대한 응답으로 문자열을 리턴하라는 의미이다. 

MainController의 출력 문자열 "index"를 "안녕하세요 sbb에 오신것을 환영합니다."로 바꾸어보자. Spring Boot Devtools와 Live Reload 기능에 의해 서버는 물론 브라우저도 리로딩되어 변경된 사항을 추가 작업 없이 즉시 확인할 수 있다.

package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MainController {

    @GetMapping("/sbb")
    @ResponseBody
    public String index() {
        return "안녕하세요 sbb에 오신것을 환영합니다.";
    }
}


2-03 JPA

JPA 란?

스프링부트는 JPA(Java Persistence API)를 사용하여 데이터베이스를 처리한다.

H2 데이터베이스

JPA를 사용하기 전에 데이터를 저장할 데이터베이스를 설치해 보자. 개발시에는 Oracle, MSSQL 등의 굵직한 데이터베이스 보다는 설치도 쉽고 사용도 편리한 H2 데이터베이스를 많이 사용한다. build.gradle 에 다음과 같이 H2 데이터베이스를 설치하자. 그리고 "Refresh Gradle Project"를 실행하여 필요한 라이브러리를 설치하자.

[파일명: /sbb/build.gradle]

(... 생략 ...)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
}

(... 생략 ...)

설치한 H2 데이터베이스를 사용하기 위해서는 설정을 해야 한다. 현재 비어있는 application.properties 파일을 아래와 같이 수정한다.

[파일명: /sbb/src/main/resources/application.properties]

# DATABASE
spring.h2.console.enabled=true //H2 콘솔의 접속을 허용할지의 여부
spring.h2.console.path=/h2-console //콘솔 접속을 위한 URL 경로
spring.datasource.url=jdbc:h2:~/local //데이터베이스 접속을 위한 경로
spring.datasource.driverClassName=org.h2.Driver //데이터베이스 접속시 사용하는 드라이버
spring.datasource.username=sa //데이터베이스의 사용자명
spring.datasource.password= //데이터베이스의 패스워드

그리고 spring.datasource.url에 설정한 경로에 해당하는 데이터베이스 파일을 만들어야 한다. 위에서 spring.datasource.url jdbc:h2:~/local 로 설정했기 때문에 사용자의 홈디렉터리(~ 에 해당하는 경로) 밑에 local.mv.db 라는 파일을 생성해야 한다. 만약 jdbc:h2:~/test라고 설정했다면 test.mv.db 라는 파일을 생성해야 한다.

이전 Java 수업에서 H2 콘솔을 통해 데이터베이스에 접속을 했었으므로 이미 프로그램은 깔려 있었다. 기존에는 jwbook 이라는 사용자 명으로 작업했으나, 스프링부트 JAP 에서는 새로운 계정이 필요하므로 아래와 같이 설정과 UPL, 사용자 명을 변경하고 연결했다. 

접속된 화면
홈 디렉터리에 만들어진&nbsp; local.mv.db 파일

 


JPA 환경설정

 자바 프로그램에서 데이터베이스에 데이터를 저장하거나 조회하려면 JPA를 사용해야 한다. 하지만 JPA를 사용하기 전에 JPA를 사용하기 위한 준비 작업이 필요하다. build.gradle 파일을 수정하고, Refresh Gradle Project 해서 변경사항을 적용한다.

[파일명: /sbb/build.gradle]

(... 생략 ...)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

(... 생략 ...)

JPA 설정을 위해 application.properties 파일을 수정한다.

[파일명: /sbb/src/main/resources/application.properties]

# DATABASE
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:~/local
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# JPA
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update