JavaRush /Java Blog /Random-KO /Spring은 무섭지 않습니다. h2 데이터베이스를 채우는 방법(그리고 약간의 Hibernate)
Павел
레벨 11

Spring은 무섭지 않습니다. h2 데이터베이스를 채우는 방법(그리고 약간의 Hibernate)

Random-KO 그룹에 게시되었습니다
기사 주기의 내용 우리는 프로젝트를 계속합니다. 웹 프로젝트를 만드는 방법우리는 데이터베이스를 웹 프로젝트에 연결합니다. 이번에는 편지가 더 많이 올 테니 5분 안에 다 못 끝내겠습니다. 지난 기사에서는 Bean이 무엇인지, 컨텍스트, 엔터티, Spring의 종속성 주입, Bean을 구성하는 방법에 대해 Spring에 대한 여러 페이지 또는 여러 기사를 읽거나 최소한 Google에서 읽어보라고 조언했습니다 . 그렇지 않다면 지금 당장 또는 이 기사가 끝난 후에 수행하는 것이 좋습니다. h2 베이스를 채우기 전에. 데이터베이스를 채우기 위한 메소드를 실행하려면 유틸리티 클래스를 작성해야 합니다. 패키지에
ru.java.rush
유틸리티용 패키지 만들기
utils
유틸리티 자체는 다음과 같습니다.
package ru.java.rush.utils;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;

@Service //annotation помечает бин How сервис
public class InitiateUtils implements CommandLineRunner { //имплементируем интерфейс CommandLineRunner (командная строка запуска)

    @Override
//переопределяем метод который позволит
//нам выполнять методы нашего applications при запуске
    public void run(String... args) throws Exception {
        System.out.println("run"); //проверим что это работает
    }
}
애플리케이션을 실행하면 콘솔에 "run"이 표시됩니다 . 이 유틸리티는 애플리케이션 실행만 담당해야 하므로 애플리케이션 클래스의 대안으로 필요합니다. 엔터티를 만들어 보겠습니다. 엔터티는 일부 데이터를 저장하는 것이 목적인 Bean입니다. 패키지에
ru.java.rush
엔터티용 패키지 만들기
entities
그리고 본질 그 자체가 열매가 되게 하십시오.
package ru.java.rush.entities;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

@Entity//помечаем бин How сущность
@Table(name = "fruit_table")//в этой аннотации можно указать Name создаваемой таблицы
public class FruitEntity {

    @Id//annotation из пакета avax.persistence.*, помечает поле How id
    @Column(name = "id_fruit")//в этой аннотации можно указать Name поля
    @GenericGenerator(name = "generator", strategy = "increment")//незаметно добрались до hibernate,
// здесь указывается что id будет автоматически увеличиваться при новых записях
    @GeneratedValue(generator = "generator")//annotation генерации id
    private Integer id;

    @Column(name = "fruit_name")
    private String fruitName;

    @Column(name = "provider_code")
    private Integer providerCode;

   //что бы в с классом можно было совершать манипуляции создается
  //пустой конструктор, геттеры, сеттеры и переопределяется метод toString()

  public FruitEntity(){ //пустой конструктор

 }

public Integer getId() {
    return id;
}

 //геттеры, сеттеры
public String getFruitName() {
    return fruitName;
}

public FruitEntity setFruitName(String fruitName) {
    this.fruitName = fruitName;
    return this;
}

public Integer getProviderCode() {
    return providerCode;
}

public FruitEntity setProviderCode(Integer providerCode) {
    this.providerCode = providerCode;
    return this;
}

//переопределяем toString()
@Override
public String toString() {
    return "FruitEntity{" +
            "id=" + id +
            ", fruitName='" + fruitName + '\'' +
            ", providerCode=" + providerCode +
            '}';
}
}
생성자, getter, setter 및 toString()은 직접 작성할 필요가 없으며 빠르게 생성 될 수 있습니다 . 좋습니다. 우리 엔터티는 데이터베이스와 상호 작용하고 데이터베이스의 데이터를 저장합니다. 본질은 작동 중입니다. 하지만 누군가가 애플리케이션에서 엔터티를 운영해야 합니다. 이를 위해 그들은 "저장소"를 고안했습니다. 패키지에
ru.java.rush
리포지토리용 패키지 만들기
repositories
그리고 저장소 자체
package ru.java.rush.repositories;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import ru.java.rush.entities.FruitEntity;

@Repository//помечаем что этот бин - репозиторий
public interface FruitRepository extends JpaRepository<FruitEntity,Integer> {
//репозиторий является интерфейсом, который наследуется от другого интерфейса JpaRepository<>
//для него необходимо указать с Howой сущность он должен работать, у нас это FruitEntity
//и тип данных у поля id данной сущности, у нас это Integer
}
문제는 왜 인터페이스의 본문이 비어 있고 선언된 메서드가 하나도 없느냐는 것입니다. 대답하려면 Ctrl 키를 누른 채 JpaRepository를 클릭하고 자체적으로 PagingAndSortingRepository<t, ""> 및 QueryByExampleExecutor<>에서 상속되는지 확인하고 일부 메서드도 선언합니다. 여기서는 방법을 복사하지 않고 직접 찾아보세요. 리포지토리는 인터페이스이므로 아무 작업도 수행하지 않고 메서드만 선언하므로 이러한 메서드를 구현하려면 다른 사람이 필요합니다. 이것이 바로 '서비스'가 탄생한 이유입니다. 패키지에
ru.java.rush
서비스용 패키지 만들기
services
그리고 서비스 자체는
package ru.java.rush.services;

import org.springframework.stereotype.Service;

@Service//помечаем что этот бин - сервис
public class FruitService {
}
이제 우리는 "빈을 주입하는 방법과 이유"(종속성 주입)라는 중요한 지점에 도달했습니다. 내가 의미하는 바를 이해하지 못한다면 지금 또는 나중에 이 주제에 대해 읽어 보시기 바랍니다. 특히 "주입" 방법, 얼마나 많은지, 어떤 것이 더 좋고, 어떤 것이 더 나쁜지, 그리고 그 이유에 주의를 기울이시기 바랍니다. . 우리는 방법 중 하나를 사용합니다. "저장소"에 어떻게든 연결되려면 "서비스"가 필요합니다. 우리는 주석과 변수로 서비스를 보완합니다.
package ru.java.rush.services;

import org.springframework.stereotype.Service;
import ru.java.rush.repositories.FruitRepository;

@Service
public class FruitService {

    private final FruitRepository fruitRepository;  //final переменная репозитория

public FruitService(FruitRepository fruitRepository) {//внедрor зависимость через конструктор
    this.fruitRepository = fruitRepository;
}

}
이제 "저장소"에서 메서드를 구현할 수 있습니다. "서비스"를 보완합니다.
package ru.java.rush.services;

import org.springframework.stereotype.Service;
import ru.java.rush.entities.FruitEntity;
import ru.java.rush.repositories.FruitRepository;

@Service
public class FruitService {

    private final FruitRepository fruitRepository;

public FruitService(FruitRepository fruitRepository) {//внедor зависимость
    this.fruitRepository = fruitRepository;
}

//создали публичный метод (название любое может быть)
//на вход принимает сущность и сохраняет ее в базу
    public void save(FruitEntity fruitEntity){
        fruitRepository.save(fruitEntity); //реализовали метод внедренного бина
    }

//возвращает лист всех сущностей из базы
    public List<FruitEntity> getAll(){
       return fruitRepository.findAll(); //реализовали метод внедренного бина
    }
}
남은 것은 이를 유틸리티에 구현하는 것뿐입니다. InitiateUtils 클래스로 넘어가겠습니다.
package ru.java.rush.utils;


import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;
import ru.java.rush.entities.FruitEntity;
import ru.java.rush.services.FruitService;

import java.util.List;

@Service
public class InitiateUtils implements CommandLineRunner {

    private final FruitService fruitService;

public InitiateUtils (FruitService fruitService) {//незабываем конструктор для внедрения
    this. fruitService = fruitService;
}

    @Override
    public void run(String... args) throws Exception {

//создаем несколько сущностей фруктов, через сеттеры заполняем поля
        FruitEntity fruitEntity1 = new FruitEntity();
        fruitEntity1.setFruitName("fruit1");
        fruitEntity1.setProviderCode(1);

        FruitEntity fruitEntity2 = new FruitEntity();
        fruitEntity2.setFruitName("fruit2");
        fruitEntity2.setProviderCode(2);

        FruitEntity fruitEntity3 = new FruitEntity();
        fruitEntity3.setFruitName("fruit3");
        fruitEntity3.setProviderCode(3);

//с помощью переменной сервиса вызываем методы сохранения в базу, по разу для одного an object
        fruitService.save(fruitEntity1);
        fruitService.save(fruitEntity2);
        fruitService.save(fruitEntity3);

//здесь вытаскиваем базу обратно
        List<FruitEntity> all = fruitService.getAll();

//и выводим что получилось
        for (FruitEntity entity : all) {
            System.out.println(entity);
        }
    }
}
콘솔 출력: FruitEntity(id=1, 과일 이름=과일1, 공급자 코드=1) FruitEntity(id=2, 과일 이름=과일2, 공급자 코드=2) FruitEntity(id=3, 과일 이름=과일3, 공급자 코드=3) 여기서 완료할 수 있습니다. "잠시만요!" - 가장 세심한 독자는 "어쨌든 Hibernate는 어디에 있습니까?"라고 외칠 것입니다. 그리고 Hibernate는 여기서 보이지 않는 전선의 전사 역할을 하며 매우 중요한 일을 했습니다: 그것은 우리를 위해 데이터베이스 구조를 생성했습니다. 우리가 "엔티티"의 필드를 작성하고 필요한 주석으로 표시했을 때 Hibernate는 해당 작업을 수행했습니다. 실제로 즉시 개발할 때는 데이터베이스 구조를 다룰 가능성이 거의 없으며 모든 것이 이미 생성 및 배포되어 있습니다. 그러나 이러한 소규모 프로젝트에서는 데이터베이스 구조를 생성하는 기능을 갖춘 Hibernate를 대체할 수 없습니다. 물론 이것이 유일한 장점은 아닙니다. 예를 들어 관련 엔터티를 생성하는 데 능숙합니다 (이 프로젝트에서는 사용하지 않습니다). 이 겸손한 작업자에게 인사를 합시다. 프로젝트 구조의 IDEA로 이동합니다(왼쪽에는 폴더와 파일이 있는 트리가 있음). 거기에서 외부 라이브러리를 찾아 열어서 다른 라이브러리 중에서 볼 수 있습니다.
Maven: org.hibernate.common:hibernate-commons-annotations:5.1.0.Final
Maven: org.hibernate.validator:hibernate-validator:6.0.17.Final
Maven: org.hibernate:hibernate-core:5.4.6.Final
특히, Hibernate는 Maven에 의해 다운로드되었으며
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
실제로 하이버 씨는 또 다른 비밀 작전을 수행했지만 이에 대해서는 다음 기사에서 다루겠습니다. 이제 그게 전부입니다. 교육 연습으로 FruitEntity 에 대해 saveAll() 메서드를 직접 구현하는 것이 좋습니다 . 이 메서드는 모든 엔터티를 데이터베이스에 한 번에 저장합니다. 다음으로 Lombok 라이브러리를 이용하여 프로젝트 코드를 단축하는 방법을 살펴보겠습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION