본문 바로가기

SpringBoot

[Do it] 2장 스프링 부트 기본 기능 익히기 (1)

1. 스프링 부트 프로젝트의 구조 이해하기 

 

 

1) src/main/java 디렉터리

 

- 자바 파일을 저장하는 공간 

 

com.example.demo 패키지 

 

- SBB의 자바 파일을 저장하는 공간

- 스프링부트의 컨트롤러, 폼과 DTO, 데이터베이스 처리를 위한 엔티티, 서비스 등의 자바 파일이 이 곳에 위치함 

 

SbbApplication.java 파일

 

- '프로젝트명' + Application.java' 파일 

- 스프링 부트 프로젝트의 시작을 담당하는 파일 

- Application 클래스에는 반드시 @SpringBootApplication 애너테이션이 적용되어 있어야 함 

 

 

 

2) src/main.resources 디렉터리 

 

- 자바 파일을 제외한 HTML, CSS, 자바스크립트, 환경 파일 등을 저장하는 공간 

 

templates 디렉터리 

 

- 템플릿 파일을 저장 

- 템플릿 파일은 자바 코드를 삽입할 수 있는 HTML 형식의 파일

- 스프링 부트에서 생성한 자바 객체를 HTML 형태로 출력 가능 

 

static 디렉터리 

 

- sbb 프로젝트의 스타일시트(css 파일), 자바스크립트(js 파일) 그리고 이미지 파일(jpg 파일, png 파일 등)을 저장 

 

application.properties 파일 

 

- sbb 프로젝트의 환경을 설정

- sbb 프로젝트의 환경 변수, 데이터베이스 등의 설정을 이 파일에 저장 

 

 

3) src/test/java 디렉터리 

 

- JUnit과 스프링 부트의 테스트 도구를 사용하여 서버를 실행하지 않은 상태에서 src/main/java 디렉터리에 작성한 코드를 테스트 

 

 

4) build.gradle 파일 

 

- 그레이들이 사용하는 환경 파일

- 그레이들(Gradle)

  -> 그루비(Groovy)를 기반으로 한 빌드 도구로, Ant,Maven과 이전 세대의 단점을 보완하고 장점을 취합하여 만듬 

- 프로젝트에 필요한 플러그인과 라이브러리를 설치하기 위한 내용을 작성 

 

빌드도구 

 - 소스 코드를 컴파일하고 필요한 라이브러리를 내려받을 때 사용 

 - SBB 프로젝트를 완성하면 단 한개의 jar 파일로 패키징하여 서버에 배포할 수 있는데 이때에도 빌드 도구를 사용 

 

 

2. 간단한 웹 프로그램 만들기 

 

1) URL 매핑과 컨트롤러 

 

URL 매핑

 

- URL과 컨트롤러의 메서드를 일대일로 연결하는 것

 

- 브라우저와 같은 클라이언트의 페이지 요청이 발생하면 스프링 부트는 가장 먼저 컨트롤러에 등록된 URL 매핑을 찾고, 해당 URL 매핑을 발견한다면 URL 매핑과 연결된 메서드를 실행 

 

- URL과 매핑된 메서드는 결괏값을 리턴해야 함 

 

@Controller - MainController 클래스는 스프링 부트의 컨트롤러가 됨
@GetMapping - 요청된 URL(/sbb)과의 매핑을 담당
@ResponseBody - URL 요청에 대한 응답으로 문자열을 리턴 

 

 

 

 

 

3. JPA로 데이터베이스 사용

 

- 대부분의 웹 서비스들은 생성되는 데이터를 관리하고 처리하기 위해 데이터베이스를 사용 

- 데이터베이스(database) = 데이터를 모으고 관리하는 저장소 

- ORM(Object Relational Mapping)를 이용하면 개발자는 SQL을 직접 작성하지 않아도 데이터베이스의 데이터를 처리할 수 있음 

 

1) ORM

 

- ORM은 데이터베이스의 테이블을 자바 클래스로 만들어 관리할 수 있음

- 엔티티(entity)

 - 데이터를 관리하는데 사용하는 ORM의 자바 클래스 

 

ex) 'question'이란 이름의 테이블에 데이터를 입력

 

id subject content
1 안녕하세요 가입 인사드립니다
2 질문 있습니다. ORM이 궁금합니다

 

SQL 쿼리문

insert into question(id,subject,content) values (1, '안녕하세요', '가입인사드립니다.');
insert into question(id,subject,content) values (2, '질문 있습니다.', 'ORM이 궁급합니다.');

 

ORM 이용 

Quesition q1 = new Question(); //자바 클래스이자 엔티티
q1.setId(1);
q1.setSubject("안녕하세요");
q1.setContent("가입 인사드립니다.");
q1.questionRepository.save(q1);

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

 

 

2) JPA

 

- 스프링 부트는 JPA(Java Persistence API)를 사용하여 데이터베이스를 관리 

- 스프링 부트는 JPA를 ORM의 기술 표준으로 작성 

 

- JPA는 인터페이스 모음이므로 이 인터페이스를 구현한 실제 클래스가 필요 

 ex) 하이버네이트 

 

- 하이버네이트(Hibernate)

 - JPA의 인터페이스를 구현한 실제 클래스이자 자바의 ORM 프레임워크로 스프링 부트에서 데이터베이스를 관리하기 쉽게 도와줌 

 

 

3) H2 데이터 베이스 

 

- 주로 개발 환경에서 사용하는 자바 기반의 경량 DBMS

- 개발 시에는 H2 데이터베이스를 사용하여 빠르게 개발하고 실제 운영 시스템에서는 좀 더 규모있는 DBMS(MySql, 오라클 DB 등)를 사용 

 

<설치 과정>

 

- build.gradle

- runtimeOnly : 해당 라이브러리가 런타임 시에만 사용됨을 의미 

 

- src/main/resources 디렉터리의 application.properties 파일에 새로운 설정 추가 

 

spring.h2.console.enabled H2 콘솔에 접속할 것인지 묻는 항목
spring.h2.console.path H2 콘솔로 접속하기 위한 URL 경로
spring.datasource.url 데이터베이스에 접속하기 위한 경로 
spring.datasource.driverClassName 데이터베이스에 접속할 때 사용하는 드라이버 클래스명
spring.datasource.username 데이터베이스의 사용자명
spring.datasource.password 데이터베이스의 비밀번호 

 

 

- spring.datasource.url에 설정한 경로에 해당하는 데이터베이스 파일을 만들어야 함 

- 사용자의 홈 디렉터리(코드에서 ~에 해당하는 경로) 아래에 H2 데이터베이스 파일로 local.mv.db라는 파일을 생성해야 함 

 

- 홈 디렉터리에서 새로 만들어진 local.mv.db 확인 

 

- JDBC URL 경로를 application.properties 파일에 설정한 데이터베이스 연결 주소인 jdbc:h2:~/local로 변경하고 연결 버튼 클릭

 

 

 

4) JPA 환경 설정

 

- 이제 자바 프로그램에서 H2 데이터베이스를 사용할 수 있게 해야 함 

- 자바 프로그램에서 데이터베이스에 데이터를 저장하거나 조회하려면 JPA를 사용해야 함

 

- build.gradle

 

 

- application.properties 파일 수정 

spring.jpa.properties.hibernate.dialect - 스프링 부트와 하이버네이트를 함께 사용할 때 필요한 설정 항목
- 표준 SQL이 아닌 하이버네이트만의 SQL을 사용할 때 필요한 항목 
- 하이버네이트의 org.hibernate.dialect.H2Dialect 클래스를 설정
spring.jpa.hibernate.ddl-auto 엔티티를 기준으로 데이터의 테이블을 생성하는 규칙 설정 

 

 

 

4. 엔티티로 테이블 매핑하기 

 

1) 질문 엔티티 

 

- 질문 엔티티 속성

속성 이름 설명
id 질문 데이터의 고유 번호
subject 질문 데이터의 제목
content 질문 데이터의 내용
createDate 질문 데이터를 작성한 일시 

 

 

Quesition.java

package com.example.demo;

import java.time.LocalDateTime;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
public class Question {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	
	@Column(length=200)
	private String subject;
	
	@Column(columnDefinition="TEXT")
	private String content;
	
	private LocalDateTime createDate;
}

 

@Entity

 

- 스프링 부트가 Question 클래스를 엔티티로 인식 

 

@Id

 

- id 속성을 기본키로 지정 

- id 속성을 기본키로 지정한 이유는 id 속성의 고유 번호들은 엔티티에서 각 데이터들을 구분하는 유효한 값으로, 중복되면 안 되기 때문

 

@GeneratedValue

 

- 데이터를 저장할 때 해당 속성에 값을 일일이 입력하지 않아도 자동으로 1씩 증가하여 저장 

 

@Column

 

- 엔티티의 속성 = 테이블의 열 이름 

- length는 열의 길이를 설정할 때 사용

- columnDefinition은 열 데이터의 유형이나 성격을 정의할 때 사용 

 

 

2) 답변 엔티티 만들기 

 

- 답변 엔티티 속성 

속성 이름 설명
id 답변 데이터의 고유 번호
question 질문 데이터 
content 답변 데이터의 내용
createDate 답변 데이터를 작성한 일시 

 

- 답변을 통해 질문의 제목을 알고 싶다면 질문 엔티티와 연결된 속성이라는 것을 답변 엔티티에 표시해야함 

- Answer 엔티티의 qustion 속성에 @ManyToOne 애너테이션을 추가해 질문 엔티티와 연결

 

Answer.java

package com.example.demo;

import java.time.LocalDateTime;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne; //다대일 관계

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
public class Answer {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	
	@Column(columnDefinition="TEXT")
	private String content;
	private LocalDateTime createDate;
	
	@ManyToOne
	private Question question;
	
	
}

 

- 게시판 서비스엔서는 하나의 질문에 답변은 여러 개가 달릴 수 있음 

 -> 답변은 Many , 질문은 One

 

@ManyToOne

 

- N:1 관계를 나타냄 

- Answer(답변) 엔티티의 question 속성과 Qustion(질문) 엔티티가 서로 연결

- 실제 데이터베이스에서는 외래키(foreign key) 생성 

 

 

@OneToMany

 

- 1:N 관계를 나타냄

- 질문에서 답변을 참조 

- mappedBy는 참조 엔티티의 속성명을 정의 

 

Question.java

package com.example.demo;

import java.time.LocalDateTime;
import java.util.List;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
public class Question {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	
	@Column(length=200)
	private String subject;
	
	@Column(columnDefinition="TEXT")
	private String content;
	
	private LocalDateTime createDate;
	
	@OneToMany(mappedBy="question", cascade=CascadeType.REMOVE)
	private List<Answer> answerList;
}

 

- 질문 하나에 답변은 여러 개이므로 Question 엔티티에 추가할 Answer 속성은 List 형태로 구성해야 함

- Answer 객체들로 구성된 answerList를 Question 엔티티의 속성으로 추가하고 @OneToMany 애너테이션을 설정 

- Answer 엔티티에서 Question 엔티티를 참조한 속성인 question을 mappedBy에 전달 

- CascadeType.REMOVE

-> 게시판에서 질문을 삭제하면 그에 달린 답변들도 함께 삭제 

 

 

완성된 테이블