SpringBoot에서 MySQL로 데이터 접근

hajin·2023년 4월 18일
0

원문

This guide walks you through the process of creating a Spring application connected to a MySQL Database (as opposed to an in-memory, embedded database, which most of the other guides and many sample applications use). It uses Spring Data JPA to access the database, but this is only one of many possible choices (for example, you could use plain Spring JDBC).
이 가이드는 스프링 애플레이케이션을 MySQL 데이터베이스에 접속하는 흐름에 대한 가이드입니다. DB에 접근을 위해서 스프링 데이터 JPA를 활용하지만 반드시 이걸 쓸 필요는 없고 Spring JDBC만 써서 DB를 관리하는 것도 방법일 수 있습니다.

필요한 것

  • MYSQL 5.6버전 이상
    - 도커를 설치했다면 데이터베이스를 컨테이너에서 기동하는 것도 좋은 선택지 일 수 있습니다.
  • 소요시간 15분
  • IDE 혹은 에디터
  • JAVA 17 이상
  • Gradle 7.5이상 혹은 Maven 3.5 이상

Spring 생성기로 프로젝트 시작

이 링크를 통해 미리 패키지명과 필요한 라이브러리가 들어간 Spring 프로젝트를 가져올 수 있습니다.

https://start.spring.io/에 접속해서 원하는 환경을 설정한 이후에 Spring Web, Spring Data JPAMySQL Driver를 가겨오고 압축된 프로젝트를 원하는 경로에 풀어서 편집기나 IDE로 엽니다.
VSCODE나 IntelliJ처럼 자체 Spring Initializer가 있으면 그걸로 생성해도 좋아요!!

DB 만들기

IDE나 콘솔로 프로젝트 경로에 터미널을 열고, MySQL client를 실행해 새 유저를 만듭니다. 리눅스에서는 sudo mysql --password를 윈도우면 MySQL WorkBench등을 이용해서 진행합니다.

이때 주의할 점은 root 계정으로 진행하면 모든 host의 DB에 접근할 수 있으니, 반드시 실습용 환경에서 진행하도록 합니다.

새 DB를 만들기 위해 mySQL 프롬프트에 커맨드를 아래와 같이 입력합니다.

mysql> create database db_example; -- Creates the new database
mysql> create user 'springuser'@'%' identified by 'ThePassword'; -- Creates the user
mysql> grant all on db_example.* to 'springuser'@'%'; -- Gives all privileges to the new user on the newly created database

application.properties 파일 생성

스프링 부트는 모든 설정에 기본 설정이 있습니다. 예를 들어 기본 데이터베이스는 H2인데, 다른 데이터베이스를 써야한다면, application.properties파일에서 연결 속성을 할당해야합니다. src/main/resources/application.properties처럼 써진대로 경로와 파일을 만들어서 아래와 같이 써줍시다.

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#spring.jpa.show-sql: true

여기서 spring.jpa.hibernate.ddl-auto는 아래와 같은 속성을 할당 할 수 있습니다.
|속성|설명|
|:-|:-|
|none|MySQL에서 기본으로 설정됩니다. 데이터베이스 구조에 변화가 없습니다.|
|update|하이버네이트가 객체 구조에 따라 데이터베이스를 바꿉니다.|
|create|데이터베이스를 항상 생성하되, 닫더라도 DROP(DB 삭제)하지 않습니다.|
|create-drop|데이터베이스를 생성한 후 SessionFactory가 닫히면 지워집니다.|

일단 데이터베이스 구조를 가지고 있지 않으니까 createupdate로 시작합시다. 프로젝트를 한번 실행하면 프로그램 요구사항에 따라 updatenone으로 바꿀 수 있습니다. update는 데이터베이스 구조를 바꿔야할 때 씁시다.

기본 설정인 H2를 포함에 다른 임베디드 데이터베이스의 기본은 create-drop이고, MySQL을 비롯한 몇몇 데이터베이스들의 기본은 none입니다.

데이터베이스가 프로덕션 상태가 된 후 이를 none으로 설정하고 Spring 애플리케이션에 연결된 MySQL 사용자의 모든 권한을 취소하고 MySQL 사용자에게 SELECT, UPDATE, INSERT 및 DELETE만 부여하는 것이 좋은 보안 방법입니다. 자세한 건 이 가이드 마지막에 볼 수 있습니다.

@Entity 모델 생성

src/main/java/com/example/accessingdatamysql/User.java에 지정된 경로 아래 파일을 생성해서 아래와 같이 써서 객체 모델을 생성합시다.

package com.example.accessingdatamysql;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity // This tells Hibernate to make a table out of this class
public class User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Integer id;

  private String name;

  private String email;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {/5
    this.email = email;
  }
}

Hibernate가 알아서 자동으로 객체를 테이블 형태로 변환합니다.

저장소(Repository) 생성

유저 기록을 저장할 저장소를 생성하기 위해 src/main/java/com/example/accessingdatamysql/UserRepository.java에 파일을 생성해 아래와 같이 작성합시다.

package com.example.accessingdatamysql;

import org.springframework.data.repository.CrudRepository;

import com.example.accessingdatamysql.User;

// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete

public interface UserRepository extends CrudRepository<User, Integer> {

}

스프링은 자동적으로 동명의 빈 bean내의 저장소 인터페이스를 자동으로 구현합니다. 위에서 useRepository로 생성됩니다.

컨트롤러 생성

애플리케이션의 HTTP 요청을 다루기 위해 컨트롤러를 생성해야합니다.
src/main/java/com/example/accessingdatamysql/MainController.java로 파일을 생성합시다.

package com.example.accessingdatamysql;

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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller // This means that this class is a Controller
@RequestMapping(path="/demo") // This means URL's start with /demo (after Application path)
public class MainController {
  @Autowired // This means to get the bean called userRepository
         // Which is auto-generated by Spring, we will use it to handle the data
  private UserRepository userRepository;

  @PostMapping(path="/add") // Map ONLY POST Requests
  public @ResponseBody String addNewUser (@RequestParam String name
      , @RequestParam String email) {
    // @ResponseBody means the returned String is the response, not a view name
    // @RequestParam means it is a parameter from the GET or POST request

    User n = new User();
    n.setName(name);
    n.setEmail(email);
    userRepository.save(n);
    return "Saved";
  }

  @GetMapping(path="/all")
  public @ResponseBody Iterable<User> getAllUsers() {
    // This returns a JSON or XML with the users
    return userRepository.findAll();
  }
}

위에서는 두 도달점에 대해 POST 및 GET을 명시적으로 지정합니다. 기본적으로 @RequestMapping은 모든 HTTP 작업을 매핑합니다.

어플리케이션 클래스 생성

Spring Initializer (저 위에 링크들...)에서 간단하게 클래스를 만듭니다. 아래에 있는건 Spring Initializer에서 자동으로 만든 클래스입니다.

package com.example.accessingdatamysql;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataMysqlApplication {

  public static void main(String[] args) {
    SpringApplication.run(AccessingDataMysqlApplication.class, args);
  }

}

예를 들어 위의 AccessingDataMysqlApplication클래스를 조정할 경우,
@SpringBootApplication은 아래의 것을 3가지 포괄하는 편한 어노테이션

@Configuration: 해당 클래스가 스프링 자체의 설정파일임을 알리는 어노테이션
@EnableAutoConfiguration:스프링 부트의 class 시작 경로를 알려주고, bean을 추가해주는 어노테이션
@ComonentScan 스프링에게 다른 컴포넌트와 설정, 서비스를 패키지(여기선 com/example)에게 알려주고 컨트롤러가 인지하게 함

main() 메소드는 스프링 부트의 SpringApplication.run()을 사용해 어플리케이션을 실행합니다. XML하나 없이 웹 애플리케이션이 만들어집니다.

이제 실행 가능한 JAR 생성

이제 Maven이나 Gradle로 어플리케이션을 가농할 수 있습니다.

./gradlew bootRun으로 실행 혹은 ./gradlew buildjava -jar build/libs/gs-accessing-data-mysql-0.1.0.jar으로 빌드를 자바로 직접 실행해도 됩니다.

만약 Maven을 쓴다면 ./mvnw spring-boot:run으로 기동하거나 ./mvnw만 친 이후 java -jar target/gs-accessing-data-mysql-0.1.0.jar로 빌드를 직접 실행해도 됩니다. 실행하면 자바 콘솔에 로그들이 나옵니다.

어플리케이션 테스트

자 이제 curl이나 비슷한 도구들을 이용해 HTTP 응답으로 테스트 해봅시다.

GET localhost:8080/demo/all 모든 데이터 수신
POST localhost:8080/demo/add 단일 유저 데이터 추가

아래와 같이 콘솔에 입력시

$ curl http://localhost:8080/demo/add -d name=First -d email=someemail@someemailprovider.com

이런 응답이 올 것이고

Saved

비슷하게 이렇게 입력시
$ curl http://localhost:8080/demo/all

이런 응답이 올겁니다.
[{"id":1,"name":"First","email":"someemail@someemailprovider.com"}]

보안 조정

이걸 Production 으로 들어갈 경우 SQL 삽입 공격에 취약할 수 있습니다. 해커는 DROP TABLE와 같은 파괴적인 SQL명령을 삽입할 수 있기에 보안적 실습 차원에서 데이터베이스에 조정이 필요합니다.

아래와 같은 커맨드는 스프링 애플리케이션과 연결된 사용자 모든 권한을 취소합니다.
mysql> revoke all on db_example.* from 'springuser'@'%';

이제 스프링 어플리케이션은 데이터베이스에 아무것도 못합니다.
그래도 어플리케이션에 권한은 있어야 하니 최소한의 권한은 줍시다.

mysql> grant select, insert, delete, update on db_example.* to 'springuser'@'%';
모든 권한 제거 후 일부 권한을 주는 것으로 스프링 애플리케이션이 데이터베이스의 데이터만 변경하는 권한을 가집니다.
데이터 베이스를 바꾸는 경우
1. 권한 재부여
2. spring.jpa.hibernate.ddl-autoupdate로 변경
3. 어플리케이션 재실행

후에 앞의 것을 반복해 다시 어플리케이션을 보호할 수 있습니다. FlywayLuqyubase를 이용해 마이그레이션 도구를 이용하는 것도 좋은 방법입니다.

profile
restart

0개의 댓글