1. Hello World 샘플 코드 구현

  • 클라이언트 쪽에서 “Hello, World” 문자열 데이터를 Request Body로 전송한다
  • Spring Data JDBC를 이용해서 전송받은  “Hello, World” 문자열을 H2 데이터베이스에 저장한다

 1) Package 생성

  • 기존 프로젝트 파일의 java > com.codestates > hello_world 패키지를 만든다
  • 아래의 클래스 또는 인터페이스를 생성한다

- MessageDto(DTO 클래스) - PostDto / ResponseDto

package com.codestates.hello_world;

import lombok.Getter;

import javax.validation.constraints.NotBlank;

//클라이언트가 Request Body로 전달하는 “Hello, World” 문자열을 바인딩하는 DTO 클래스
@Getter
public class MessagePostDto {
    @NotBlank
    private String message;
}
package com.codestates.hello_world;

import lombok.Getter;
import lombok.Setter;

//Response에 사용할 Dto
@Getter
@Setter
public class MessageResponseDto {
    private long messageId;
    private String message;
}

 

- MessageController

package com.codestates.hello_world.messageController;

import com.codestates.hello_world.messageMapper.MessageMapper;
import com.codestates.hello_world.messageService.MessageService;
import com.codestates.hello_world.message.Message;
import com.codestates.hello_world.messageDto.MessagePostDto;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

//문자열을 전달받는 Controller
@RequestMapping("/v1/message")
@RestController
public class MessageController {
    private final MessageService messageService;
    private final MessageMapper mapper;

    public MessageController(MessageService messageService,
                             MessageMapper mapper){
        this.messageService = messageService;
        this.mapper = mapper;
    }

    @PostMapping
    public ResponseEntity postMessage(
            @Valid @RequestBody MessagePostDto messagePostDto){
        Message message =
                messageService.createMessage(mapper.messageDtoToMessage(messagePostDto));
        return ResponseEntity.ok(mapper.messageToMessageResponseDto(message));
        }
}

 

- MessageMapper

package com.codestates.hello_world.messageMapper;

import com.codestates.hello_world.message.Message;
import com.codestates.hello_world.messageDto.MessagePostDto;
import com.codestates.hello_world.messageDto.MessageResponseDto;
import org.mapstruct.Mapper;

//DTO 클래스와 엔티티(Entity) 클래스를 매핑해주는 Mapper 인터페이스
@Mapper(componentModel = "spring")
public interface MessageMapper {

    Message messageDtoToMessage(MessagePostDto messagePostDto);
    MessageResponseDto messageToMessageResponseDto(Message message);

}

 

- MessageService

package com.codestates.hello_world.messageService;

import com.codestates.hello_world.message.Message;
import com.codestates.hello_world.messageRepository.MessageRepository;
import org.springframework.stereotype.Service;

//MessageRepository 인터페이스를 DI를 통해 주입받는다
//데이터베이스에 데이터를 저장하고 데이터베이스에 저장된 데이터를 다시 리턴
@Service
public class MessageService {
    private MessageRepository messageRepositoty;
    public MessageService(MessageRepository messageRepositoty){
        this.messageRepositoty = messageRepositoty;
    }
    public Message createMessage(Message message){
        return messageRepositoty.save(message);
    }
}

  → MessageRepository가 상속받은 CrudRepository에 save() 메서드가 정의되어 있다

  → 개발자가 데이터의 생성, 조회, 수정, 삭제 작업을 위한 별도의 코드를 구현하지 않아도 CrudRepository가 작업을 대신해주는 역할을 한다


- Message(엔티티 클래스)

package com.codestates.hello_world.message;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

//Message 클래스명은 데이터베이스의 테이블명에 해당한다
//@Id 애너테이션을 추가한 멤버 변수는 해당 엔티티의 고유 식별자 역할을 한다
//식별자는 데이터베이스의 Primary key로 지정한 컬럼에 해당한다
@Getter
@Setter
public class Message {
    @Id
    private long messageId;
    private String message;
}


- MessageRepository

package com.codestates.hello_world;

import org.apache.logging.log4j.message.Message;
import org.springframework.data.repository.CrudRepository;

//데이터베이스와의 연동을 담당하는 Repository
public interface MessageRepository extends CrudRepository<Message, Long>{

}

  →  CrudRepository라는 인터페이스를 상속하고 있고, CrudRepository의 제너릭 타입이 <Message, Long>으로 선언되어 있다   

  → CrudRepository 는 데이터베이스에 CRUD(데이터 생성, 조회, 수정, 삭제) 작업을 진행하기 위해 Spring에서 지원해주는 인터페이스이다

  → CrudRepository<Message, Long> 와 같이 제너릭 타입을 지정해줌으로써 Message 엔티티 클래스 객체에 담긴 데이터를 데이터베이스 테이블에 생성 또는 수정하거나 데이터베이스에서 조회한 데이터를 Message 엔티티 클래스로 변환할 수 있다

  → <Message, Long>에서 LongMessage 엔티티 클래스의 멤버 변수 중에 식별자를 의미하는 @Id 라는 애너테이션이 붙어있는 멤버 변수의 데이터 타입이다

  ※ 짧은 문장이고 MessageRepository 인터페이스 내부에 아무런 코드도 없으나, MessageRepository 인터페이스를 서비스 계층에서 DI를 통해 주입받은 후 데이터베이스 작업을 위해 사용하게 된다

 

프로젝트를 실행시키고 error 발생 시 변수들의 경로에 유의하여 수정하도록 한다!!!

 

2) 프로젝트 실행

  • 실행 전에 property 설정을 추가한다
spring:
  h2:
    console:
      enabled: true
      path: /h2     # (1) Context path
  datasource:
    url: jdbc:h2:mem:test     # (2) JDBC URL
  sql:
    init:
      schema-locations: classpath*:db/h2/schema.sql      # 추가할 부분
      # 테이블 생성을 위한 SQL 문이 추가된 ‘schema’라는 파일명으로 .sql 파일의 경로를 지정
  • 추가 후 resource > db.h2 > schema.sql 파일을 보면 아래와 같이 테이블이 추가되어 있다
CREATE TABLE IF NOT EXISTS MESSAGE (
    MESSAGE_ID bigint NOT NULL AUTO_INCREMENT,
    MESSAGE varchar(100) NOT NULL,
    PRIMARY KEY (MESSAGE_ID)
);
  • postman에서 post : http://localhost:8080/v1/message 입력 후 전송하면 아래와 같이 응답한다

  • 요청 전송 시 Request Body에 messageId 값은 포함하지 않았지만 Response Body에는 messageId가 포함되어 출력된다
  • MESSAGE 테이블의 식별자(Primary key)인 ‘message_id’ 컬럼에 AUTO_INCREMENT 설정이 되어 있으므로 ‘message_id’ 컬럼에 값을 입력하지 않더라도 데이터가 저장이 될 때 마다 자동으로 포함이 된다
  • chrome 화면으로 가서 다시 출력한 후 'SELECT *FROM MESSAGE'를 입력하고 RUN SELECT를 실행한다
    - 1개의 데이터 (ID:1 , MESSAGE:Hello World)가 입력되어 있음을 확인할 수 있다

 

2. JDBC DATA 구현 순서

 

+ Recent posts