2-01 스프링 부트 프로젝트의 구조 이해하기
1) src->main->java 디렉터리
- 자바 파일을 저장하는 공간이다
- com.example.sbb : SBB의 자바 파일을 저장하는 공간이다
- 컨트롤러는 URL 요청 처리하고, 폼은 사용자 입력에대해 검증을한다.
- SbbApplication.java 파일 : 프로그램의 시작을 담당하는 파일
2) src->main->resources 디렉터리
- 자바 파일을 제외한 HTML, CSS, 자바스크립트, 환경 파일 등 저장함
- templates 디렉터리 : 템플릿 파일을 저장
- 템플릿 파일 : 자바 코드를 삽입할 수 있는 HTML 형식의 파일로, 스프링 부트에서 생성한 자바 객체를 HTML 형태로 출력
- static 디렉터리 : css파일, js파일, 이미지 파일 등을 저장
- application.properties 파일 : sbb 프로젝트의 환경 설정 (변수,db 설정 예를 들어server.port=8088 설정 등)
3) src/test/java 디렉터리
- sbb 프로젝트에서 작성한 파일을 테스트하는 코드를 저장하는 공간
- build.gradle 파일 : 그레들이 사용하는 환경 파일, 프로젝트에 필요한 플러그인과 라이브러리를 설치하기 위한 내용 작성
- 그레들 : 그루비(Groovy)를 기반으로 한 빌드 도구로 Ant, Maven과 같은 이전 세대의 단점을 보완하고 장점을 취합하여 만듦
2-02 간단한 웹 프로그램 만들기
1) URL 매핑과 컨트롤러 이해하기
- URL 매핑 : URL과 컨트롤러의 메서드를 일대일로 연결하는 것 (일치 시키는것)
- 브라우저와 같은 클라이언트의 페이지 요청이 발생하면 스프링 부트는 가장 먼저 컨트롤러에 등록된 URL 매핑을 찾고, 해당 URL 매핑을 발견하면 URL 매핑과 연결된 메서드를 실행
package com.example.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";
}
}
- @Controller : 시작점
- @GetMapping : 요청된 URL(/sbb)과의 매핑을 담당
- @ResponseBody : URL 요청에 대한 응답으로 문자열을 리턴하라는 의미
2-03 JPA로 데이터베이스 사용하기
- 데이터베이스(database, DB) : 데이터를 모으고 관리하는 저장소
- ORM(Object Relational Mapping)
- SQL을 사용하지 않고 데이터베이스를 관리할 수 있는 도구
- DBMS(database management system) : 데이터베이스를 관리하는 소프트웨어
- JPA(Java Persistence API) : 인터페이스(서로 다른 시스템이나 요소들이 함께 작동할 수 있도록 연결는것) 모음이므로, 이 인터페이스를 구현한 실제 클래스가 필요
- 하이버네이트(Hibernate) : JPA의 인터페이스를 구현한 실제 클래스이자 자바의 ORM 프레임워크
1) H2 데이터베이스 설치하기
spring.h2.console.enabled=true
// h2 콘솔에 접속 여부 묻는 항목.
// h2 콘솔 = h2 데이터베이스를 웹 UI로 보여준다
spring.h2.console.path=/h2-console
// h2 콘솔로 접속하기 위한 경로
spring.datasource.url=jdbc:h2:~/local
// DB 접속 경로
spring.datasource.driverClassName=org.h2.Driver
// DB 접속할 때 쓰는 드라이버 클래스명
spring.datasource.username=sa
// DB 사용자 명
spring.datasource.password=
// DB 비밀번호
2) JPA 환경 설정하기
- JPA 라이브러리 설치
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 추가
- implementation : 필요한 라이브러리 설치를 위해 가장 일반적으로 사용하는 설정
- 특징 : 해당 라이브러리가 변경되더라도 이 라이브러리와 연관된 모든 모듈을 컴파일하지 않고 변경된 내용과 관련이 있는 모듈만 컴파일하므로 프로젝트를 리빌드(rebuild)하는 속도가 빠르다.
- application.properties 파일 수정
# JPA
// 스프링부트와 하이버네이트를 함께 사용할 때 필요한 설정 항목
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
// 엔티티를 기준으로 데이터의 테이블을 생성하는 규칙 설정
spring.jpa.hibernate.ddl-auto=update
2-04 엔티티로 테이블 매핑하기
- 기본키(primary key) : 테이블의 데이터가 중복되어 저장되지 않게 한다. 어떤 열을 기본키로 설정하면 해당 열에는 동일한 값을 저장하지 못한다.
- 엔티티(entity)(=모델,도메인 모델) : 데이터베이스 테이블과 매핑되는 자바 클래스
즉 자바에서의 테이블
ex) 질문과 답변 데이터를 저장할 데이터베이스 테이블과 매핑되는 질문과 답변 엔티티
1) 질문 엔티티 만들기
package com.example.sbb;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
@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 : 스프링 부트가 클래스를 엔티티로 인식
- @Getter와 @Setter : 롬복의 기능으로 Getter, Setter 메서드를 자동으로 생성
- @Id : id 속성을 기본키로 지정
- @GeneratedValue : 데이터를 저장할 때 해당 속성에 값을 일일이 입력하지 않아도 자동으로 1씩 증가하여 저장
- strategy = GenerationType.IDENTITY : 고유한 번호를 생성하는 방법을 지정하는 부분, 해당 속성만 별도로 번호가 차례대로 늘어나도록 할 때 사용
- strategy 생략시, 순서가 일정한 고유 번호를 가질 수 없다 즉 순서가 달라질수 있다 .
- 왜? @GeneratedValue 에 지정된 모든 속성에 번호를 차례대로 지정하므로
- @Column : 열의 세부 설정
- 엔티티의 속성은 테이블의 열 이름과 일치
- length : 열의 길이
- columnDefinition : 열 데이터의 유형이나 성격을 정의
- TEXT : 열 데이터 ‘텍스트’, 글자 수 제한 X
- @Transient : 엔티티의 속성을 테이블의 열로 만들지 않고 클래스의 속성 기능으로만 사용
즉, @Transient를 사용하면 해당 속성은 데이터베이스 테이블에 영향을 주지 않고 엔티티 클래스의 일부로만 유지됩니다.
- 엔티티에서 카멜표기법으로 속성의 이름을 쓰면, DB 테이블에서 언더바로 구분되어 열 이름으로 변환된다
EX) createDate(java) > create_date(DB)
- 엔티티를 만들때, Setter 메서드는 권장하지 않는다
Setter는 DB와 바로 연결되므로 데이터를 자유롭게 변경할 수 있는 Setter 메서드를 허용하는 것은 안전하지 않다
2) 질문 엔티티 만들기
package com.example.sbb;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.List;
@Getter
@Setter
@Entity
public class Answer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(columnDefinition = "TEXT")
private String content;
private LocalDateTime createDate;
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
private List<Answer> answerList;
}
- question : 질문 엔티티 참조
- @ManyToOne
- N(답변):1(질문) 관계에 사용
- question 속성에 추가하여 질문 엔티티와 연결
- 질문 엔티티와 연결된 속성이라는 것을 답변 엔티티에 표시하는 역할
- 부모 자식 관계를 갖는 구조에서 사용
-부모 Question, 자식 Answer
- @OneToMany
- mappedBy : 참조 엔티티의 속성명
- Answer 엔티티에서 Question 엔티티를 참조한 속성인 question을 mappedBy에 전달
- CascadeType.REMOVE : 질문을 삭제하면 그에 달린 답변도 모두 삭제되도록 하는 기능