CRUD JPA

DEVELOPERS_Ivan ㅣ 2023. 10. 16. 15:28


Java Persistence API (JPA)는 자바에서 관계형 데이터베이스와 상호 작용하는데 사용되는 자바 표준 ORM (Object-Relational Mapping) 기술입니다. JPA는 개발자가 객체 지향 프로그래밍 방식으로 데이터베이스를 다룰 수 있게 해주며, 데이터베이스 스키마와 자바 객체 간의 매핑을 단순화하는데 도움을 줍니다. 
새 프로젝트 생성
추가된 종속성 : Spring Boot DevTools, Lombok, Spring Web, Spring Data JPA, Oracle Driver
파일 인코딩 : UTF-8

빌드 완료

 


 

build.gradle 환경 추가
오라클 라이브러리( 19c ), logback , log4jdbc 설정

build.gradle
0.00MB

 

더보기
dependencies {
//  TODO : 오라클 라이브러리( 19c )
    implementation 'com.oracle.database.jdbc:ucp:19.14.0.0'
    implementation 'com.oracle.database.security:oraclepki:19.14.0.0'
    implementation 'com.oracle.database.security:osdt_cert:19.14.0.0'
    implementation 'com.oracle.database.security:osdt_core:19.14.0.0'

//  TODO : logback , log4jdbc 설정
    implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
    implementation 'ch.qos.logback:logback-classic:1.2.11'
    implementation 'org.slf4j:slf4j-api:1.7.36'
    implementation 'org.slf4j:jcl-over-slf4j:1.7.36'

//  TODO : JPA 라이브러리
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

 


 

application.properties
환경 설정 추가

gradle-wrapper.properties
0.00MB

 

더보기
# 서버 포트
server.port=8000

# todo: docker db 설정
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# todo: spring.datasource.url=jdbc:log4jdbc:oracle:thin:@ip주소:db포트번호/db이름
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xepdb1
spring.datasource.username=scott
spring.datasource.password=!Ds1234567890

# todo: jpa 설정
# todo: ddl-auto - create(모든 테이블 재생성)/update(수정된 테이블만 생성)/none(안함)
spring.jpa.hibernate.ddl-auto=create
#spring.jpa.hibernate.ddl-auto=update
#spring.jpa.hibernate.ddl-auto=none
# todo: db 제품 연결 ( oracle 12이상 : Oracle12cDialect )
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
# todo: generate-ddl=true (테이블 자동 생성 옵션)
spring.jpa.generate-ddl=true
# todo: sql log 보기 (true/false)
spring.jpa.show-sql=true
# 1) resource/data.sql 자동 실행 ( DML 실행 )
#  -> data.sql ( dml 실행 ), schema.sql ( ddl 실행 )
# todo: dml, ddl 스크립트 (실습용 샘플 테이블 ) 실행을 위한 옵션
spring.jpa.defer-datasource-initialization=true
# todo: sql log 이쁘게 보여주기
spring.jpa.properties.hibernate.format_sql=true
# todo: 로깅 레벨 : error < info < debug < trace (정보 많은 순)
logging.level.org.hibernate=info


# 2)  resource/data.sql 자동 실행 ( DML 실행 )
#  -> data.sql ( dml 실행 ), schema.sql ( ddl 실행 )
spring.sql.init.mode=always
# sql 에러 무시하고 스프링 서버 로딩
spring.sql.init.continue-on-error=true


# 자바 소스 변경시 스프링 서버 자동 재시작
spring.devtools.restart.enabled=true

# PUT , DELETE 방식도 form 에서 사용할 수 있게 만들어줌 : jsp 사용
spring.mvc.hiddenmethod.filter.enabled=true

 


 

실습용 테이블 파일 추가

data.sql
0.00MB
log4jdbc.log4j2.properties
0.00MB
logback-spring.xml
0.00MB
schema.sql
0.00MB

 

RUN 실행하여 확인


폴더 생성
- model: 모델은 데이터와 데이터의 처리를 나타내는 부분입니다.
애플리케이션의 핵심 로직과 데이터베이스와의 상호 작용을 처리합니다.
이 데이터는 주로 엔터티, 객체 또는 데이터 구조로 표현됩니다.

- service: 서비스는 비즈니스 로직을 구현하고 제공하는 부분입니다.
서비스는 모델과 컨트롤러 간의 중간 계층 역할을 하며, 데이터 처리와 관련된 작업을 수행합니다

- controller: 컨트롤러는 사용자의 입력을 받고 처리하는 부분입니다.
사용자 인터페이스와 모델 간의 상호 작용을 조정하며 모델의 데이터를 업데이트하거나 뷰를 업데이트하는 역할을 합니다.

- repository: 리포지토리는 데이터베이스와 상호 작용하는 인터페이스 레이어를 나타냅니다
주로 데이터베이스에서 데이터를 가져오거나 저장하기 위한 메서드를 제공합니다.

- dto (Data Transfer Object): DTO는 데이터 전송 객체로, 데이터를 다른 시스템 또는 계층 간에 전달하는 데 사용됩니다. 일반적으로 데이터베이스에서 가져온 데이터를 표현하는 데 사용되며, 뷰에서 모델로 데이터를 전달할 때 데이터의 구조를 정의하는 데 도움을 줍니다.


model 폴더
BaseTimeEntity(인터페이스) : JPA 에서 자동으로 생성일자/수정일자를 만들어 주는 클래스
더보기
package com.example.jpaexam.model;

import lombok.Getter;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * packageName : com.example.jpaexam.model
 * fileName : BaseTimeEntity
 * author : L.DH
 * date : 2023-10-16
 * description : JPA 에서 자동으로 생성일자/수정일자를 만들어 주는 클래스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * ———————————————————————————————
 * 2023-10-16         L.DH         최초 생성
 */
@Getter
// TODO : 자동으로 생성일자/수정일자 컬럼을 sql 문에 추가 시키는 어노테이션 2개
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
    // TODO 공통 속성 : yyyy-MM-dd HH:mm:ss 아니고 기본 패턴으로 보이므로 공통 속성을 패턴으로 저장해줌
    private String insertTime;

    private String updateTime;

    // TODO : 해당 테이블에 데이터가 만들어 질 때 실행되는 이벤트 함수
    @PrePersist
    void onPrePersist() {
        this.insertTime
                = LocalDateTime.now()
                .format(DateTimeFormatter
                        .ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    // TODO : 해당 테이블에 데이터가 수정될 때 (update 문) 실행되는 이벤트 함수
    @PostUpdate
    void OnPreUpdate() {
        this.updateTime
                = LocalDateTime.now()
                .format(DateTimeFormatter
                        .ofPattern("yyyy-MM-dd HH:mm:ss"));

        this.insertTime = this.updateTime;  // TODO : 생성일시 == 수정일시 동일하게 처리
    }

}

 


 

model 폴더
부서 모델 클래스( 엔티티(entity) )
더보기
package com.example.jpaexam.model;

import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

/**
 * packageName : com.example.jpaexam.model
 * fileName : Dept
 * author : L.DH
 * date : 2023-10-16
 * description : 부서 모델 클래스( 엔티티(entity) )
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * ———————————————————————————————
 * 2023-10-16         L.DH         최초 생성
 */
// TODO : @Entity - JPA 기능을 클래스에 부여하는 어노테이션
@Entity
// TODO : @Table(name = "생성될테이블명")
//  생략시 클래스명(대소문자)으로 만들어지기 떄문에 관례(대문자)로 별도 지정해 준다.
@Table(name = "TB_DEPT")
// TODO : @SequenceGenerator(
//        name = "시퀀스함수이름"
//        , sequenceName = "DB에생성된시퀀스이름"
//        , initialValue = 시작값
//        , allocationSize = jpa에서관리용숫자(성능지표)

@SequenceGenerator(
                    name = "SQ_DEPT_GENERATOR"
                    , sequenceName = "SQ_DEPT"
                    , initialValue = 1
                    , allocationSize = 1
                    )

// Lombok lib
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor

// TODO : JPA 어노테이션 SQL 자동 생성시 null 값 컬럼은 제외하고 생성하는 어노테이션
//  예) insert into 테이블명(컬럼1, 컬럼2, 컬럼3) values(1, 2, null);
//   => insert into 테이블명(컬럼1, 컬럼2) values(1, 2);
@DynamicInsert
@DynamicUpdate

public class Dept extends BaseTimeEntity {
    @Id
//  TODO :     @GeneratedValue(strategy = GenerationType.SEQUENCE
//            , generator = "시퀀스함수이름"
//    )

    @GeneratedValue(strategy = GenerationType.SEQUENCE
            , generator = "SQ_DEPT_GENERATOR"
    )
// TODO : @Column(co
    @Column(columnDefinition = "NUMBER")
    private Integer dno;    // 부서번호(기본키)

    @Column(columnDefinition = "VARCHAR2(225)")
    private String dname;   // 부서명

    @Column(columnDefinition = "VARCHAR2(225)")
    private String loc;     // 부서위치


}

 


 

repository 폴더
JPA 레포지토리 인터페이스 ( DB 접속 함수들(CRUD) 있음) == DAO 비슷함
더보기
package com.example.jpaexam.repository;

import com.example.jpaexam.model.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * packageName : com.example.jpaexam.repository
 * fileName : DeptRepository
 * author : L.DH
 * date : 2023-10-16
 * description : JPA 레포지토리 인터페이스 ( DB 접속 함수들(CRUD) 있음)
 *  *               == DAO 비슷함
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * ———————————————————————————————
 * 2023-10-16         L.DH         최초 생성
 */
// todo: @Repository - 클래스 위에 붙이고, 스프링서버가 실행될때 자동으로
//      객체 1개를 만들어줌 ( IOC )
//   사용법 : 인터페이스명 extends JpaRepository<모델클래스명, 기본키의자료형>
@Repository
public interface DeptRepository extends JpaRepository<Dept, Integer> {
}

 


 

service 폴더
업무 서비스
1. 전체 조회
더보기
package com.example.jpaexam.service;

import com.example.jpaexam.model.Dept;
import com.example.jpaexam.repository.DeptRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * packageName : com.example.jpaexam.service
 * fileName : DeptService
 * author : L.DH
 * date : 2023-10-16
 * description : 부서 업무 서비스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * ———————————————————————————————
 * 2023-10-16         L.DH         최초 생성
 */
@Service
public class DeptService {
    @Autowired
    DeptRepository deptRepository;  // com.example.jpaexam.repository 에 DeptRepository 인터페이스 DI 객체 가져오기

    /** 전체 조회 */
    public List<Dept> findAll() {
        List<Dept> list = deptRepository.findAll(); // db 전체 조회 함수 호출

        return list;
    }
}

 


 

controller 폴더
부서 컨트롤러 : (@RestController)
1. 전체 조회
더보기
package com.example.jpaexam.controller.exam01;

import com.example.jpaexam.model.Dept;
import com.example.jpaexam.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * packageName : com.example.jpaexam.controller.exam01
 * fileName : DeptController
 * author : L.DH
 * date : 2023-10-16
 * description : 부서 컨트롤러 : (@RestController)
 * 요약 :
 * 1. 전체 조회
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * ———————————————————————————————
 * 2023-10-16         L.DH         최초 생성
 */
@Slf4j
@RestController
@RequestMapping("/exam01")
public class DeptController {

    @Autowired
    DeptService deptService; // 객체 가져오기 (DI)

    /**
     * 전체 조회
     */
    @GetMapping("/dept")
    public ResponseEntity<Object> getDeptAll() {
        try {
//          todo: 전체 조회 함수 호출
            List<Dept> list = deptService.findAll();

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

}
더보기
###
GET http://localhost:8000/exam01/dept

<> 2023-10-16T171728.200.json