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
-> 게시판에서 질문을 삭제하면 그에 달린 답변들도 함께 삭제
완성된 테이블
'SpringBoot' 카테고리의 다른 글
[Do it] 2장 스프링 부트 기본 기능 익히기(5) (0) | 2024.01.21 |
---|---|
[Do it] 2장 스프링 부트 기본 기능 익히기 (4) (0) | 2024.01.21 |
[Do it] 2장 스프링 부트 기본 익히기(3) (0) | 2024.01.19 |
[Do it] 2장 스프링 부트 기본 기능 익히기(2) (1) | 2024.01.19 |
[Do it] 1장 스프링 부트 개발 준비하기 (1) | 2024.01.18 |