build.gradle 설정

// querydsl 추가
buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'org.springframework.boot' version '2.6.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    
    //querydsl 플러그인 추가
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"

    id 'java'
}

group = 'com.study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
    annotationProcessor 'org.projectlombok:lombok'

    implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'

    //querydsl 추가
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
    implementation "com.querydsl:querydsl-apt:${queryDslVersion}"

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}


tasks.named('test') {
    useJUnitPlatform()
}

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}
sourceSets {
    main.java.srcDir querydslDir
}
compileQuerydsl{
    options.annotationProcessorPath = configurations.querydsl
}
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    querydsl.extendsFrom compileClasspath
}
//querydsl 추가 끝

 

persistence.xml 설정

resources 디렉토리 밑에 META-INF 디렉토리를 생성하고 그 안에 persistence.xml을 만든 다음 아래 내용을 자신의 개발 환경에 맞게 세팅하시면 됩니다.

 

<?xml version="1.0" encoding="UTF-8" ?>
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/">
    
    <!-- EntityManagerFactory 생성 시 unit name과 일치해야 합니다 -->
    <persistence-unit name="hello">
        <properties>
            <!-- 필수 속성 -->
            <!-- DB Driver -->
            <property name="javax.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/>
            
            <!-- DB user info -->
            <property name="javax.persistence.jdbc.user" value="user"/>
            <property name="javax.persistence.jdbc.password" value="password"/>
            
            <!-- DB url -->
            <property name="javax.persistence.jdbc.url" value="jdbc:mariadb://localhost:3306/schema"/>
            
            <!-- DB Dialect 설정 -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MariaDB103Dialect"/>
            
            <!-- 옵션 -->
            <!-- SQL show -->
            <property name="hibernate.show_sql" value="true"/>
            
            <!-- SQL 정렬 -->
            <property name="hibernate.format_sql" value="true"/>
            
            <!-- SQL에 관한 주석 처리 -->
            <property name="hibernate.use_sql_comments" value="true"/>
            
            <!-- application 실행 시 ddl 전략 -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>
        </properties>
        
    </persistence-unit>
</persistence>

우선, JPA의 관계 매핑을 알아보기 전에 객체의 연관 관계와 테이블의 연관 관계의 차이를 알아봅시다.

 

테이블 : 외래키로 조인하여 연관된 테이블을 찾습니다.

객체 : 객체를 참조하여 연관된 객체를 찾습니다.

 

테이블은 조인을 통해 양방향 연관 관계 설정이 가능하지만 객체에는 양방향 연관 관계 설정이 없으므로 다른 두 객체에 각각 단방향 연관 관계를 설정해야 합니다.

 

게시판 예제를 통해 확인해봅시다.

 

Article

@Entity
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    
    private String content;

    ...
}

Member

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String memberId;

    private String memberPass;
    
    ...
}

 

게시판 객체와 회원 객체가 있을 때 게시판 객체에서는 회원 정보를 얻고 반대로 회원 객체에서는 회원이 작성한 모든 글을 가지고 오고 싶습니다.

 

@ManyToOne과 OneToMany

두 객체를 연결하기 위해 Article 객체 필드에 Member 객체를 만들었고, Member 객체 필드에는 List 타입의 Articles라는 필드를 만든 후 각각 @ManyToOne과 @OneToMany를 붙여줬습니다.

 

@ManyToOne : 다대일, 한 명의 회원이 여러 게시글을 작성할 수 있으므로 게시글(Article) 기준으로 @ManyToOne을 선언합니다.

@OneToMany : 일대다, 회원 한 명이 게시글을 여러 개 작성할 수 있으므로 회원(Member) 기준으로 @OneToMany를 선언합니다.

 

@Entity
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    
    private String content;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

    ...
}


@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String memberId;

    private String memberPass;
    
    @OneToMany(mappedby = "member")
    private List<Article> articles = new ArrayList<Article>();
    
    ...
}

 

@ManyToOne(fetch = FetchType.LAZY) : fetch로 로딩 전략을 설정합니다. FetchType.LAZY는 지연 로딩을 의미합니다.

@OneToMany(mappedby = "member") : 일대다 관계를 연결할 상대 객체의 @JoinColumn이 선언된 필드값을 적습니다.

 

mappedby란?

JPA로 연관 관계를 설정할 때 가장 혼동하기 쉬운 부분인데 mappedby는 연관 관계 객체의 반대 객체에 선언합니다.

 

연관 관계 주인 : 외래키가 있는 객체

* 예시에서는 외래키가 Article에 있으므로 Article이 연관 관계의 주인

 

즉, 위 예시에서는 Article과 Member 중에서 Article이 외래키 member_id 라는 컬럼에 해당하는 member를 갖고 있으므로 Article이 연관 관계의 주인입니다.

 

따라서 연관 관계 주인 Article과 연관 관계로 설정된 Member 객체의 articles 필드 위 @OneToMany 안에 (mappedby를 넣고 연관 관계 주인 객체의 연결 필드명 "member"를 넣어주시면 됩니다.

 

처음 해보시면 되게 혼란스러우실 수 있는데 우리나라 JPA 최고 권위자이신 김영한 선생님의 강의 영상 첨부하니 확인해보세요!

 

'Java Web > JPA' 카테고리의 다른 글

[JPA] persistence.xml 작성 예시  (0) 2022.03.02
[JPA] 연관 관계 편의 메소드  (0) 2022.02.28
[JPA] Auditing 정리  (0) 2022.02.14
[JPA] findAll 정렬  (0) 2021.07.23
[JPA] JPA란?  (0) 2021.05.13

 

스프링부트 게시판 무작정 따라하기!

 

이 강의는 자바를 이용한 웹 개발 기초 지식, 프레임워크에 관한 지식이 없으신 분도 따라하기만 하면 게시판을 만들 수 있게 구성하였습니다. 물론 완벽하게 이해하시기는 힘드시겠지만 강의 통해 웹 개발에 흥미를 가지셨으면 좋겠습니다.

 

스프링 부트와 JPA, Thymeleaf를 이용한 게시판 개발

 

본 개발에서 프레임워크는 스프링 부트(Spring Boot)를 사용할 것이고, DB 접근 기술로는 Mybatis 가 아닌 JPA(Java Persistence API)를 사용할 것이며, View를 담당하는 View 템플릿은 타임리프(Thymeleaf)를 사용할 것입니다. 스프링 부트를 통해 MVC 구조를 파악할 수 있고, JPA를 통해 Mybatis와는 다른 DB 접근 방법을 익힐 수 있으며, 타임리프를 통해 사용자에게 데이터를 어떻게 보여줄 수 있는가 학습해 봅시다.

 

이 부분도 너무 어렵게 받아들이지 마시고 이런 것들이 쓰였구나 정도로 이해해주시면 됩니다.

 

개발환경

 

IDE(통합개발환경) : 인텔리제이 커뮤니티

 

개발 언어 : Java 1.8.0

 

프레임워크 : Spring Boot 2.5.3

 

빌드 : Gradle

 

DB(데이터베이스) : MariaDB 10.3.30

 

DB 접근 기술 : JPA

 

View 템플릿 : Thymeleaf

 

 

강의 영상

1) 강의 소개

 

 

2) 인텔리제이 설치

 

 

3) MariaDB 설치

 

 

4) MySQL Workbench 설치

 

 

5) 프로젝트 생성

 

 

6) DB에 테이블 생성

 

 

7) 게시글 작성폼 생성

 

 

8) 글 작성 처리

 

 

9) 게시글 리스트

 

 

10) 게시글 상세페이지

 

 

11) 게시글 삭제

 

 

12) 게시글 수정

 

 

13) 메시지 띄우기

 

 

14) 파일 업로드

 

 

강의자료

application.properties 설정

spring.datasource.driverClassName=org.mariadb.jdbc.Driver

spring.datasource.url=jdbc:mariadb://localhost:3306/board

spring.datasource.username=스키마계정

spring.datasource.password=비밀번호

 

테스트 데이터 프로시저 생성

DELIMITER $$

CREATE PROCEDURE testDataInsert()
BEGIN
    DECLARE i INT DEFAULT 1;

    WHILE i <= 120 DO
        INSERT INTO board(title, content)
          VALUES(concat('제목',i), concat('내용',i));
        SET i = i + 1;
    END WHILE;
END$$
DELIMITER $$

+ Recent posts