▼ Backend/스프링 (Spring)

Spring Boot | JPA + lombok 사용하기

Valar 2021. 7. 19. 21:50
반응형

▶ JPA, 자바 지속성 API (Java Persistence API)

자바 플랫폼 SE와 자바 플랫폼 EE를 사용하는 응용프로그램에서 관계형 데이터베이스의 관리를 표현하는 Java API이다.

 

▶ lombok(https://projectlombok.org/)

getter, setter 등의 반복 메서드를 자동으로 연결하고 도구를 빌드하여 Java를 향상시키는 Java 라이브러리이다.

 

테이블 생성 member with mariaDB

CREATE TABLE member (
	MBR_SEQ BIGINT(20) NOT NULL AUTO_INCREMENT,
	ID VARCHAR(200) NULL DEFAULT NULL,
	PWD VARCHAR(200) NULL DEFAULT NULL,
	NAME VARCHAR(200) NULL DEFAULT NULL,
	ADDR_LOAD VARCHAR(300) NULL DEFAULT NULL,
	REG_ID VARCHAR(200) NULL DEFAULT NULL,
	REG_DTM DATETIME NULL DEFAULT NULL,
	MOD_ID VARCHAR(200) NULL DEFAULT NULL,
	MOD_DTM DATETIME NULL DEFAULT NULL,
	PRIMARY KEY (MBR_SEQ) USING BTREE
)

 

1. Dependency 추가 (jpa, lombok, mariadb)

Maven의 경우 pom.xml에 추가

 

<!-- JPA -->
<dependency> 
  <groupId>org.springframework.boot</groupId> 
  <artifactId>spring-boot-starter-data-jpa</artifactId> 
</dependency>
<!-- JPA -->

<!-- lombok -->
<dependency> 
  <groupId>org.projectlombok</groupId> 
  <artifactId>lombok</artifactId> 
  <optional>true</optional> 
</dependency>
<!-- lombok -->

<!-- MariaDB --> 
<dependency> 
  <groupId>org.mariadb.jdbc</groupId> 
  <artifactId>mariadb-java-client</artifactId> 
</dependency> 
<!-- MariaDB -->

 

 

gradle의 경우 build.gradle에 추가

 

dependencies {
    //Jpa
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    //lombok
    implementation 'org.projectlombok:lombok'
    //mariaDB
    implementation 'org.mariadb.jdbc:mariadb-java-client'
}

 

2. 데이터베이스 설정

application.properties

 

spring.datasource.driverClassName=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/database
spring.datasource.username=user
spring.datasource.password=pwd!@#

 

application.yml

 

spring:
  datasource:
    driverClassName: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306/database
    username: user
    password: pwd!@#

 

3. 재사용될 컬럼을 추상 클래스로 작성

CommonVo.java

 

import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.CreationTimestamp;
import lombok.Data;

//Getter, Setter Auto Create
@Data
//공통 매핑 정보가 필요할 때, 부모 클래스에 선언하고 속성만 상속 받아서 사용하고 싶을 때 사용한다.
@MappedSuperclass
public abstract class CommonVo {

    // register id
    private String regId;

    // modify id
    private String modId;

    // register Date time
    @CreationTimestamp
    /* 보통 JPA는 SAVE시에 모든 칼럼을 INSERT한다.
    그럴 경우, NOT NULL로 설정된 칼럼은 기본값으로 삽입되는것이 아닌 NULL로 삽입을 시도한다.
    이로 인해 에러가 발생하는데, 이럴 경우에 아예 쿼리에서 빼버려서 실행이 안되게 만들 수 있다.
    쿼리에서 제외된 칼럼은 DB에 지정된 default값으로 삽입이 된다.
    특정 칼럼을 제외하고 save하는 방법은 다음과 같다. insertable = false, updatable = false*/
    @Column(updatable = false)
    private LocalDateTime regDtm;

    // modify Date time
    @CreationTimestamp
    private LocalDateTime modDtm;
}

 

4. CommonVo를 상속받은 MemberVo 작성

MemberVo.java

 

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.melon.boot.common.vo.CommonVo;
import lombok.Data;

//Getter, Setter Auto Create
@Data
//Table Mapping
@Entity(name = "member")
public class MemberVo extends CommonVo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long mbrSeq;
    private String id;
    private String pwd;
    private String name;
    private String addrLoad;
}

 

5. JpaRepository를 상속받은 interface 작성

MemberRepository.java

 

package com.melon.boot.member.service.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.melon.boot.member.vo.MemberVo;

public interface MemberRepository extends JpaRepository<MemberVo, Long> {
}

 

6. Service Class 작성

MemberService.java

 

import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.melon.boot.member.service.repository.MemberRepository;
import com.melon.boot.member.vo.MemberVo;

@Service
public class MemberService {

    @Autowired
    private MemberRepository memberRepository;

    /* INSERT */
    public MemberVo save(MemberVo memberVo) throws Exception {
        return memberRepository.save(memberVo);
    }

    /* SELECT LIST */
    public List < MemberVo > findAll() throws Exception {
        return memberRepository.findAll();
    }

    /* SELECT BY ID */
    public Optional < MemberVo > findById(Long mbrSeq) throws Exception {
        return memberRepository.findById(mbrSeq);
    }

    /* UPDATE */
    public MemberVo updateById(MemberVo memberVo) throws Exception {

        Optional < MemberVo > e = memberRepository.findById(memberVo.getMbrSeq());

        MemberVo resultMember = null;

        if (e.isPresent()) {
            resultMember = memberRepository.save(memberVo);
        }

        return resultMember;
    }

    /* DELETE */
    public void deleteById(Long mbrSeq) throws Exception {
        memberRepository.deleteById(mbrSeq);
    }
}

 

7. Controller Class 작성

테스트용으로 하드코딩 샘플 데이터가 들어가 있으니, 화면을 작성하고 실제로 사용할 때에는 샘플 데이터를 지우고 객체를 받아 사용한다.

 

MemberController.java

 

import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.melon.boot.member.service.MemberService;
import com.melon.boot.member.vo.MemberVo;

@Controller
@RequestMapping("/member")
public class MemberController {

    @Autowired
    MemberService memberService;

    @GetMapping("/insert")
    public void insertMember() throws Exception {
        try {
            MemberVo memberVo = new MemberVo();

            memberVo.setId("tester");
            memberVo.setPwd("pwd123!@#");
            memberVo.setName("tom");
            memberVo.setAddrLoad("seoul city");
            memberVo.setRegId("reg_id");
            memberVo.setModId("mod_id");

            memberService.save(memberVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @GetMapping("/selectList")
    public void selectMemberList() throws Exception {
        try {
            memberService.findAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @GetMapping("/select")
    public void selectMember() throws Exception {
        try {
            memberService.findById((long) 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @GetMapping("/update")
    public void updateMember() throws Exception {
        try {
            MemberVo memberVo = new MemberVo();

            memberVo.setMbrSeq((long) 1);
            memberVo.setId("update tester");
            memberVo.setPwd("update pwd123!@#");
            memberVo.setName("update name");
            memberVo.setAddrLoad("update seoul city");
            memberVo.setRegId("update reg_id");
            memberVo.setModId("update mod_id");
            memberVo.setModDtm(LocalDateTime.now());

            memberService.updateById(memberVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @GetMapping("/delete")
    public void deleteMember(MemberVo memberVo) throws Exception {
        try {
            memberService.deleteById((long) 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

8. 테스트 URL

  • /member/insert
  • /member/selectList
  • /member/select
  • /member/update
  • /member/delete

쿼리 실행 로그를 콘솔에 출력

application.properties

 

#쿼리 로그 설정
spring.jpa.show-sql=true 

#SQL문을 보기 좋게 출력
spring.jpa.properties.hibernate.format_sql=true

#바인딩되는 파라미터 값 출력
logging.level.org.hibernate.type.descriptor.sql=trace

 

application.yml

 

spring:
  jpa: 
    show-sql: true #쿼리 로그 설정
    properties: 
      hibernate: 
        format_sql: true #SQL문을 보기 좋게 출력
logging: 
  level:
    org: 
      hibernate: 
        type: 
         descriptor:
          sql: trace #바인딩되는 파라미터 값 출력

 

 

 

그 외에 이름 안에서 지원되는 키워드

 

And			findByLastnameAndFirstname	… where x.lastname = ?1 and x.firstname = ?2
Or			findByLastnameOrFirstname	… where x.lastname = ?1 or x.firstname = ?2
Is,Equals		findByFirstname,findByFirstnameIs,findByFirstnameEquals	… where x.firstname = 1?
Between			findByStartDateBetween	… where x.startDate between 1? and ?2
LessThan		findByAgeLessThan	… where x.age < ?1
LessThanEqual		findByAgeLessThanEqual	… where x.age ⇐ ?1
GreaterThan		findByAgeGreaterThan	… where x.age > ?1
GreaterThanEqual	findByAgeGreaterThanEqual	… where x.age >= ?1
After			findByStartDateAfter	… where x.startDate > ?1
Before			findByStartDateBefore	… where x.startDate < ?1
IsNull			findByAgeIsNull	… where x.age is null
IsNotNull,NotNull	findByAge(Is)NotNull	… where x.age not null
Like			findByFirstnameLike	… where x.firstname like ?1
NotLike			findByFirstnameNotLike	… where x.firstname not like ?1
StartingWith		findByFirstnameStartingWith	… where x.firstname like ?1(parameter bound with appended %)
EndingWith		findByFirstnameEndingWith	… where x.firstname like ?1(parameter bound with prepended %)
Containing		findByFirstnameContaining	… where x.firstname like ?1(parameter bound wrapped in %)
OrderBy			findByAgeOrderByLastnameDesc	… where x.age = ?1 order by x.lastname desc
Not			findByLastnameNot	… where x.lastname <> ?1
In			findByAgeIn(Collection<Age> ages)	… where x.age in ?1
NotIn			findByAgeNotIn(Collection<Age> age)	… where x.age not in ?1
True			findByActiveTrue()	… where x.active = true
False			findByActiveFalse()	… where x.active = false
IgnoreCase		findByFirstnameIgnoreCase	… where UPPER(x.firstame) = UPPER(?1)

 

 

직접 쿼리를 작성하여 사용할 경우 @Query 어노테이션을 사용한다.

 

// 트랜잭션
@Transactional
// @Modifying 어노테이션은 @Query 어노테이션으로 작성된 수정, 삭제 쿼리 메소드를 사용할 때 필요하다. 
// 조회 쿼리를 제외하고 데이터에 변경이 일어나는 INSERT, UPDATE, DELETE 쿼리에서 사용한다.
@Modifying
@Query(value="UPDATE MEMBER SET PWD=:#{#memberVo.pwd} WHERE MEM_SEQ = :#{#memberVo.seq}", nativeQuery = true)
public int updateMemberPwd(MemberVo memberVo);

 


 

프로젝트 Export Archive File

melon.zip
0.11MB

 

프로젝트 import, export
 

Spring Boot | 프로젝트 import, export

import export

kitty-geno.tistory.com

 

Reference
https://spring.io/projects/spring-data-jpa
반응형