자바 웹 개발 워크북 - 예스24
아래내용은 ‘자바 웹 개발 워크북(구멍가게 코딩단)’ 책의 pp. 432 ~ 508 (5.3. Spring Data JPA ~ 5.4. 게시물 관리 완성하기)의 내용을 토대로 작성되었습니다.
JPA(Java Persistence API)는 자바 플랫폼에서 객체 관계 매핑(ORM, Object-Relational Mapping)을 위한 표준 인터페이스 API로, 프레임워크이다. JPA는 객체 지향 언어인 자바로 관계형 데이터베이스를 다룰 때, SQL 쿼리 대신 객체를 사용해 데이터베이스와 상호 작용할 수 있도록 도와준다. JPA 구현체에는 Hibernate, EclipseLink, Apache OpenJPA 등이 있다.
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
plugins {
id "java"
id "war"
id "org.springframework.boot" version "2.7.17"
id "io.spring.dependency-management" version "1.0.15.RELEASE"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java {
sourceCompatibility = "17"
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
implementation "org.springframework.boot:spring-boot-starter-web"
// querydsl 라이브러리
implementation "com.querydsl:querydsl-jpa"
implementation "com.querydsl:querydsl-apt"
implementation "com.querydsl:querydsl-core"
implementation "com.querydsl:querydsl-sql"
// modelMapper: DTO와 엔티티 간 변환 처리해주는 라이브러리
implementation "org.modelmapper:modelmapper:3.1.0"
// 타임리프로 LocalDateTime format 을 temporals 로 맞추기 위해 필요
implementation "org.thymeleaf.extras:thymeleaf-extras-java8time3"
compileOnly("org.projectlombok:lombok", "com.querydsl:querydsl-apt:${queryDslVersion}:jpa")
developmentOnly "org.springframework.boot:spring-boot-devtools"
runtimeOnly "org.mariadb.jdbc:mariadb-java-client"
// 기존 롬복 이외도, javax 와 querydsl 어노테이션 추가
annotationProcessor(
"org.projectlombok:lombok",
"javax.persistence:javax.persistence-api",
"javax.annotation:javax.annotation-api",
"com.querydsl:querydsl-apt:${queryDslVersion}:jpa");
providedRuntime "org.springframework.boot:spring-boot-starter-tomcat"
testImplementation "org.springframework.boot:spring-boot-starter-test"
// test junit 시에 lombok 추가
testCompileOnly "org.projectlombok:lombok"
testAnnotationProcessor "org.projectlombok:lombok"
}
tasks.named("bootBuildImage") {
builder = "paketobuildpacks/builder-jammy-base:latest"
}
tasks.named("test") {
useJUnitPlatform()
}
sourceSets {
main.java.srcDirs = ["$projectDir/src/main/java", "$projectDir/build/generated"]
}
💡 왜 그런지 모르겠는데 $projectDir 등의 gradle의 변수를 쓰려면 ‘작은 따옴표’는 안된다. “큰 따옴표”안에 써야 한다.
참고한 블로그: Spring Boot 3.0 이상 시 QueryDSL 설정
buildscript {
ext {
queryDslVersion = "5.0.0"
}
}
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.1.6'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
// 기본 라이브러리 ( spring initializer 로 추가하기)
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
// querydsl 라이브러리
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" // 기존에는 그냥 jpa, 3 버전 이상은 :jakarta 추가
implementation "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
// apt(annotation processing tool), Q도메인 생성. 컴파일 시에만 사용됨
implementation "com.querydsl:querydsl-core"
implementation "com.querydsl:querydsl-sql"
// modelMapper: DTO 와 엔티티 간 변환 처리해주는 라이브러리
implementation "org.modelmapper:modelmapper"
compileOnly("org.projectlombok:lombok", "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta") // 롬복 외에도 querydsl 어노테이션 추가
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
// 기존 롬복 이외도, jakarta 와 querydsl 어노테이션 추가 (spring boot 3.0 이상은 jakarta 대신 jakarta 사용)
annotationProcessor(
"org.projectlombok:lombok",
"jakarta.persistence:jakarta.persistence-api",
"jakarta.annotation:jakarta.annotation-api",
"com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"); // querydsl-apt:jpa -> querydsl-apt:jakarta
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('bootBuildImage') {
builder = 'paketobuildpacks/builder-jammy-base:latest'
}
tasks.named('test') {
useJUnitPlatform()
}
// 프로젝트의 소스 코드 및 리소스 디렉토리 구성
// 개발 시 작성하는 java 파일의 위치 (src/main/java)와 Q도메인이 저장되는 위치(build/generated)를 명시
// 기존 파일과 Q도메인이 gradle 빌드 시 자동 컴파일 되게 함
sourceSets {
main.java.srcDirs = ["$projectDir/src/main/java", "$projectDir/build/generated"]
}
application.properties
에 다음과 같이 설정해주어야 한다.
spring.jpa.hibernate.ddl-auto
: 엔티티 객체를 만들면 알아서 엔티티에 해당하는 테이블이 만들어진다.spring.jpa.properties.hibernate.format_sql
: Hibernate 실행 시 SQL 쿼리를 개행, 들여쓰기 등을 사용해 보기 쉽게 바꿔줌spring.jpa.show-sql
: JPA(Hibernate) 실행 시 해당 SQL 쿼리를 콘솔에 출력spring.jpa.hibernate.naming.physical-strategy
: 엔티티 클래스의 카멜케이스 필드명을 데이터베이스의 스네이크 케이스 컬럼명으로 자동 매핑해줌.server.port=8080
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/springData
spring.datasource.username=root
spring.datasource.password=1234
logging.level.org.springframework=info
logging.level.com.shop=debug
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.servlet.multipart.enabled=true
spring.servlet.multipart.location=C:\\upload
spring.servlet.multipart.max-request-size=30MB
spring.servlet.multipart.max-file-size=10MB
com.springData.upload.path=C:\\upload
JPQL에서 Q도메인이 중복 build되어 오류가 발생하는 것을 방지한다.
위의 설정을 하지 않는다면 build를 하기 전에 반드시 터미널에 아래 코드를 입력한다.
./gradlew clean
@Entity
: 테이블과 매핑되는 자바의 객체 클래스@Table
: 엔티티 클래스와 매핑할 테이블 정보@Id
: 테이블 클래스의 필드(식별자 필드)를 기본 키(Primary Key)에 매핑.@Column
: 필드를 컬럼에 매핑@Column
을 사용해야 대소문자를 신경쓰지 않을 수 있다.@GeneratedValue
: 해당 컬럼의 값 생성 전략으로, 주로 PK(기본키)를 생성하는데 사용된다.Identity
: 데이터베이스가 자동 생성하도록 하는 것. MySQL 또는 MariaDB에서 AUTO_INCREMENT
와 같다.@SequenceGenerator
필요@TableGenerator
필요package com.shop.domain;
import lombok.*;
import javax.persistence.*;
@Entity
public class Board {
// 공통 속성이 들어가는 경우 public class Board extends BaseEntity로 바꿔주어야 한다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long bno;
@Column(length = 500, nullable = false) //컬럼의 길이와 null허용여부
private String title;
@Column(length = 2000, nullable = false)
private String content;
@Column(length = 50, nullable = false)
private String writer;
}
기존의 클래스는 BaseEntity 클래스를 상속하도록 변경한다.
package com.shop.domain;
import lombok.*;
import javax.persistence.*;
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Board extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long bno;
@Column(length = 500, nullable = false) //컬럼의 길이와 null허용여부
private String title;
@Column(length = 2000, nullable = false)
private String content;
@Column(length = 50, nullable = false)
private String writer;
public void change(String title, String content){
this.title = title;
this.content = content;
}
}
@MappedSuperclass
: 특정 클래스를 엔티티 클래스의 부모 클래스로 지정@EntityListeners(value = {AuditingEntityListener.class})
: 엔티티가 데이터베이스에 추가되거나 변경될 때 자동으로 시간 값을 지정한다. 이를 활성화하기 위해서는 프로젝트 설정에 @EnableJpaAudititng
을 추가해야 한다.@CreatedDate
: 엔티티가 최초로 생성될 때 일시 기록@LastModifiedDate
: 엔티티가 업데이트될 때마다의 시간 정보 저장package com.shop.domain;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
@EntityListeners(value = { AuditingEntityListener.class })
@Getter
abstract class BaseEntity {
@CreatedDate
@Column(name = "regdate", updatable = false)
private LocalDateTime regDate;
@LastModifiedDate
@Column(name ="moddate" )
private LocalDateTime modDate;
}
EnableJpaAuditing
: [src - main - java - 홈페이지]에 있는 프로젝트 이름의 자바파일, 즉 프로젝트 설정에 이 어노테이션을 추가한다.package com.shop;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication
@EnableJpaAuditing
public class B01Application {
public static void main(String[] args) {
SpringApplication.run(B01Application.class, args);
}
}