JavaRush /Java 博客 /Random-ZH /Spring 并不可怕,或者如何填充 h2 数据库(和一点 Hibernate)
Павел
第 11 级

Spring 并不可怕,或者如何填充 h2 数据库(和一点 Hibernate)

已在 Random-ZH 群组中发布
文章周期的内容 我们继续我们的项目。如何创建网络项目。 我们将数据库连接到我们的网络项目。这次信件会更多,五分钟之内我们就过不了。在上一篇文章中,我建议您阅读有关 Spring 的 几页或几篇文章,或者至少谷歌一下什么是 bean、上下文、实体、Spring 中的依赖注入、配置 bean 的方法。如果没有,那么我建议您立即或在阅读本文之后执行此操作。在填充我们的 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 {
}
现在我们到达了一个重要的点:“如何以及为什么注入 bean”(注入依赖项)。如果你不明白我的意思,那么我请你现在或以后阅读这个主题,特别注意“注入”的方法,有多少种,哪个更好,哪个更差,以及为什么。我们使用其中一种方法。我们需要“服务”以某种方式连接到“存储库”。我们用注释和变量来补充我们的服务。
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,fruitName=fruit1,providerCode=1)FruitEntity(id=2,fruitName=fruit2,providerCode=2)FruitEntity(id=3,fruitName=fruit3,providerCode=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>
事实上,Hiber先生还进行了另一项秘密行动,不过我们将在下一篇文章中讲述。现在一切都确定了。作为一项训练练习,我建议您自己实现FruitEntity的 saveAll() 方法 ,该方法会将所有实体一次性保存到数据库中。 接下来我们看看如何使用Lombok库来缩短项目代码
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION