[JAVA] J'ai essayé de démarrer avec Spring Data JPA

Au début

Je n'avais jamais touché à un OR Mapper autre que Doma, alors j'y ai soudainement pensé et l'ai touché avec un demi-intérêt.

Comment installer dans l'application Spring Boot - Je voudrais écrire sur la comparaison avec Doma que j'ai ressentie en créant une API simple.

environnement

supposition

Je voudrais créer une API simple et la toucher de différentes manières. L'API à créer est la suivante.

point final Http Method Aperçu Remarques
/api/employee/{employeeId} GET Obtenez des informations sur les employés qui correspondent à l'ID d'employé.
/api/employee GET Obtenez des informations sur les employés. Nous allons également affiner par conditions de recherche.
/api/employee POST Enregistrez les informations sur les employés.
/api/employee/{employeeId} PUT Mettez à jour les informations sur les employés.
/api/employee/{employeeId} DELETE Supprimer les informations sur les employés.

Création d'API

(Pour le moment) Création d'un modèle pour l'application

Créez un modèle pour votre application à l'aide du plug-in VS Code appelé Spring Initializer Java Support.

Ce plug-in lui-même est inclus dans le Spring Boot Extension Pack, donc le [Spring Boot Extension Pack]( Il suffit d'avoir https://marketplace.visualstudio.com/items?itemName=Pivotal.vscode-boot-dev-pack) installé.

Créez un modèle de manière interactive. Dans la palette de commandes, sélectionnez "Spring Initializr: Générer un projet Gradle".

create-application-01.png

Sélectionnez Java.

create-application-02.png

Entrez le nom du package. Cette fois, laissez-le par défaut comme «com.example».

create-application-03.png

Saisissez le nom du projet. Veuillez nous donner votre nom préféré. (J'ai utilisé des employés-api.)

create-application-04.png

Sélectionnez la version de Spring Boot. (Sélectionnez 2.3.1)

create-application-05.png

Sélectionnez une bibliothèque dépendante. J'ai choisi la bibliothèque suivante car je voulais juste créer une API simple.

Spring Boot DevTools / Lombok / Spring Web / Spring Data JPA / PostgreSQL Driver

create-application-06.png

Définissez les informations de connexion dans ʻapplication.properties`

spring.jpa.database=postgresql
spring.datasource.platform=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/sample
spring.datasource.username=postgres
spring.datasource.password=postgres

Définir la classe Entity

ʻInsert_date et ʻupdate_date sont définis comme des éléments communs dans la table.

CommonEntity.java


/**
 *Une classe qui définit les éléments communs dans une table.</br>
 *Toutes les classes Entity sont créées en héritant de cette classe.
 */
@MappedSuperclass
@Getter
@Setter
public class CommonEntity {

  /**Date et heure d'enregistrement des données*/
  @Column(name = "insert_date")
  @Temporal(TemporalType.DATE)
  private Date insertdate;

  /**Date et heure de mise à jour des données*/
  @Column(name = "update_date")
  @Temporal(TemporalType.DATE)
  private Date updateDate;

  /**
   *Méthode couramment exécutée avant l'enregistrement des données
   */
  @PrePersist
  public void preInsert() {
    Date date = new Date();
    setInsertdate(date);
    setUpdateDate(date);
  }

  /**
   *Méthodes couramment exécutées avant la mise à jour des données
   */
  @PreUpdate
  public void preUpdate() {
    setUpdateDate(new Date());
  }

}

Hérite de CommonEntity qui définit les éléments de table communs et crée une classe Entity à usage professionnel.

EmployeeEntity.java


@Entity
@Table(name = "employee")
@Getter
@Setter
public class EmployeeEntity extends CommonEntity {

  /**ID d'employé*/
  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer employeeId;
  
  /**Nom de l'employé*/
  @Column(name = "name")
  private String employeeName;

  /**âge*/
  @Column(name = "age")
  private Integer age;

  /**ID de position*/
  @Column(name = "position_id")
  private String positionId;

  /**ID de service*/
  @Column(name = "department_id")
  private String departmentId;

}

Définir l'interface du référentiel

ʻDéfinissez une interface qui hérite de org.springframework.data.jpa.repository.JpaRepository`.

EmployeeRepository.java


package com.example.employeeapi.employee;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<EmployeeEntity, Integer> {

}

(Référence) JpaRepository

Il existe des méthodes qui peuvent gérer les opérations CRUD de base. Dans l'interface qui hérite de cette interface (dans cet exemple, ʻEmployeeRepository`), vous pouvez définir votre propre méthode lorsque la méthode préparée à l'avance dans les spécifications métier, etc. n'est pas suffisante. (Rejoignez-nous pour obtenir des enregistrements, etc.)

JpaRepository.java


/*
 * Copyright 2008-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.jpa.repository;

import java.util.List;

import javax.persistence.EntityManager;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

/**
 * JPA specific extension of {@link org.springframework.data.repository.Repository}.
 *
 * @author Oliver Gierke
 * @author Christoph Strobl
 * @author Mark Paluch
 */
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#findAll()
	 */
	@Override
	List<T> findAll();

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
	 */
	@Override
	List<T> findAll(Sort sort);

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
	 */
	@Override
	List<T> findAllById(Iterable<ID> ids);

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
	 */
	@Override
	<S extends T> List<S> saveAll(Iterable<S> entities);

	/**
	 * Flushes all pending changes to the database.
	 */
	void flush();

	/**
	 * Saves an entity and flushes changes instantly.
	 *
	 * @param entity
	 * @return the saved entity
	 */
	<S extends T> S saveAndFlush(S entity);

	/**
	 * Deletes the given entities in a batch which means it will create a single {@link Query}. Assume that we will clear
	 * the {@link javax.persistence.EntityManager} after the call.
	 *
	 * @param entities
	 */
	void deleteInBatch(Iterable<T> entities);

	/**
	 * Deletes all entities in a batch call.
	 */
	void deleteAllInBatch();

	/**
	 * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
	 * implemented this is very likely to always return an instance and throw an
	 * {@link javax.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
	 * immediately.
	 *
	 * @param id must not be {@literal null}.
	 * @return a reference to the entity with the given identifier.
	 * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
	 */
	T getOne(ID id);

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
	 */
	@Override
	<S extends T> List<S> findAll(Example<S> example);

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
	 */
	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

Définir le service, la classe de contrôleur

Définissez une classe Service qui utilise le ʻEmployee Repository` défini précédemment et une classe Controller qui l'appelle.

EmployeeService.java


package com.example.employeeapi.employee;

import java.util.ArrayList;
import java.util.List;

import javax.transaction.Transactional;

import com.example.employeeapi.employee.dto.Employee;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Transactional
public class EmployeeService {

  @Autowired
  private EmployeeRepository employeeRepository;

  public Employee getEmployeeById(String employeeId) {
    EmployeeEntity entity = employeeRepository.findById(Integer.parseInt(employeeId)).get();
    Employee employee = new Employee();
    copyEntityToBean(entity, employee);
    return employee;
  }

  public List<Employee> getEmployeeList() {
    List<Employee> employees = new ArrayList<>();
    List<EmployeeEntity> employeeEntityList = employeeRepository.findAll();
    employeeEntityList.forEach(entity -> {
      Employee employee = new Employee();
      copyEntityToBean(entity, employee);
      employees.add(employee);
    });
    return employees;
  }

  public Employee createEmployee(Employee employee) {
    EmployeeEntity entity = new EmployeeEntity();
    copyBeanToEntityForInsert(employee, entity);
    EmployeeEntity createdEntity = employeeRepository.save(entity);
    Employee newEmployee = new Employee();
    copyEntityToBean(createdEntity, newEmployee);
    return newEmployee;
  }

  public Employee updateEmployee(Employee employee) {
    EmployeeEntity entity = new EmployeeEntity();
    copyBeanToEntityForUpdate(employee, entity);
    EmployeeEntity updatedEntity = employeeRepository.save(entity);
    Employee updatedEmployee = new Employee();
    copyEntityToBean(updatedEntity, updatedEmployee);
    return updatedEmployee;
  }

  public boolean deleteEmployeeById(String employeeId) {
    employeeRepository.deleteById(Integer.parseInt(employeeId));
    return true;
  }

  private void copyEntityToBean(EmployeeEntity entity, Employee employee) {
    //Pour l'exemple, faites une simple copie.
    //Si vous voulez le faire proprement, BeanUtils#Utilisez copyProperties, etc.
    employee.setId(String.valueOf(entity.getEmployeeId()));
    employee.setName(entity.getEmployeeName());
    employee.setAge(String.valueOf(entity.getAge()));
    employee.setPositionId(entity.getPositionId());
    employee.setDepartmentId(entity.getDepartmentId());
    employee.setInsertDate(String.valueOf(entity.getInsertdate()));
    employee.setUpdateDate(String.valueOf(entity.getUpdateDate()));
  }

  private void copyBeanToEntityForInsert(Employee employee, EmployeeEntity entity) {
    //Pour l'exemple, faites une simple copie.
    //Si vous voulez le faire proprement, BeanUtils#Utilisez copyProperties, etc.
    if (!"".equals(employee.getName())) {
      entity.setEmployeeName(employee.getName());
    }
    if (!"".equals(employee.getAge())) {
      entity.setAge(Integer.parseInt(employee.getAge()));
    }
    if (!"".equals(employee.getPositionId())) {
      entity.setPositionId(employee.getPositionId());
    }
    if (!"".equals(employee.getDepartmentId())) {
      entity.setDepartmentId(employee.getDepartmentId());
    }
  }

  private void copyBeanToEntityForUpdate(Employee employee, EmployeeEntity entity) {
    //Pour l'exemple, faites une simple copie.
    //Si vous voulez le faire proprement, BeanUtils#Utilisez copyProperties, etc.
    entity.setEmployeeId(Integer.parseInt(employee.getId()));
    copyBeanToEntityForInsert(employee, entity);
  }

}

EmployeeController.java


package com.example.employeeapi.employee;

import java.util.List;

import com.example.employeeapi.common.dto.HttpResponseDto;
import com.example.employeeapi.employee.dto.Employee;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EmployeeController {

  @Autowired
  private EmployeeService employeeService;

  @GetMapping(path = "/api/employee/{employeeId}")
  public HttpResponseDto getEmployeeById(@PathVariable("employeeId") String employeeId) {
    HttpResponseDto httpResponseDto = new HttpResponseDto();
    Employee employee = employeeService.getEmployeeById(employeeId);
    httpResponseDto.setHttpStatus(HttpStatus.OK);
    httpResponseDto.setResponseData(employee);
    return httpResponseDto;
  }

  @GetMapping(path = "/api/employee")
  public HttpResponseDto getEmployeeList() {
    HttpResponseDto httpResponseDto = new HttpResponseDto();
    List<Employee> employees = employeeService.getEmployeeList();
    httpResponseDto.setHttpStatus(HttpStatus.OK);
    httpResponseDto.setResponseData(employees);
    return httpResponseDto;
  }

  @PostMapping(path = "/api/employee")
  public HttpResponseDto createEmployee(@RequestBody Employee employee) {
    HttpResponseDto httpResponseDto = new HttpResponseDto();
    Employee newEmployee = employeeService.createEmployee(employee);
    httpResponseDto.setHttpStatus(HttpStatus.CREATED);
    httpResponseDto.setResponseData(newEmployee);
    return httpResponseDto;
  }

  @PutMapping(path = "/api/employee/{employeeId}")
  public HttpResponseDto updateEmployee(@PathVariable("employeeId") String emplyeeId, @RequestBody Employee employee) {
    HttpResponseDto httpResponseDto = new HttpResponseDto();
    employee.setId(emplyeeId);
    Employee updatedEmployee = employeeService.updateEmployee(employee);
    httpResponseDto.setHttpStatus(HttpStatus.CREATED);
    httpResponseDto.setResponseData(updatedEmployee);
    return httpResponseDto;
  }

  @DeleteMapping(path = "/api/employee/{employeeId}")
  public HttpResponseDto deleteEmployee(@PathVariable("employeeId") String employeeId) {
    HttpResponseDto httpResponseDto = new HttpResponseDto();
    if (employeeService.deleteEmployeeById(employeeId)) {
      httpResponseDto.setHttpStatus(HttpStatus.OK);
      httpResponseDto.setMessage("delete success.");
    } else {
      // do something
    }
    return httpResponseDto;
  }
}

Comparaison avec d'autres OR Mapper (subjectif)

Je l'ai écrit en comparaison avec d'autres OR Mappers, mais c'est une comparaison avec Doma.

――Ce que je ressentais était bon

(Supplément) Construction de la base de données

La base de données de vérification est construite sur la base de Docker. C'est pénible de créer une base de données car cela fonctionne avec le copier-coller! Veuillez l'utiliser.

$ tree
.
├── docker-compose.yml
└── init-script
    ├── 01_create_table.sql
    └── 02_insert_data.sql

docker-compose.yml


version: '3'
volumes:
  db_data:
services:
  database:
    image: postgres:11.6
    container_name: postgres
    ports:
      - 5432:5432
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init-script:/docker-entrypoint-initdb.d
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: sample

01_create_table.sql


create table department (
  --Code départemental
  id varchar(3) primary key,
  --Nom du département
  name varchar(50),
  --Date d'entrée des données
  insert_date date,
  --Date de mise à jour des données
  update_date date
);

create table "position" (
  --ID de position
  id varchar(2) primary key,
  --Titre
  name varchar(20),
  --Date d'entrée des données
  insert_date date,
  --Date de mise à jour des données
  update_date date
);

--génération de table
create table "employee" (
  --numéro d'employé
  id serial primary key,
  --Nom de l'employé
  name varchar(50),
  --âge
  age integer,
  --Position
  position_id varchar(2) references position(id),
  --Identifiant du service d'affiliation
  department_id varchar(3) references department(id),
  --Date d'entrée des données
  insert_date date,
  --Date de mise à jour des données
  update_date date
);

02_insert_data.sql


insert into department (id, name, insert_date, update_date)
values ('001', 'Département des Ressources Humaines', '2020-06-17', '2020-06-17');
insert into department (id, name, insert_date, update_date)
values ('002', 'Département des affaires générales', '2020-06-17', '2020-06-17');
insert into department (id, name, insert_date, update_date)
values ('003', 'Département de développement', '2020-06-17', '2020-06-17');
insert into department (id, name, insert_date, update_date)
values ('004', 'Département des relations publiques', '2020-06-17', '2020-06-17');
insert into position (id, name, insert_date, update_date)
values ('01', 'Réalisateur', '2020-06-17', '2020-06-17');
insert into position (id, name, insert_date, update_date)
values ('02', 'Directeur', '2020-06-17', '2020-06-17');
insert into position (id, name, insert_date, update_date)
values ('03', 'Général', '2020-06-17', '2020-06-17');
insert into employee (
    name,
    age,
    position_id,
    department_id,
    insert_date,
    update_date
  )
values (
    'Shacho-san',
    50,
    '01',
    '001',
    '2020-06-17',
    '2020-06-17'
  );
insert into employee (
    name,
    age,
    position_id,
    department_id,
    insert_date,
    update_date
  )
values (
    'Butcho-san',
    46,
    '02',
    '001',
    '2020-06-17',
    '2020-06-17'
  );
insert into employee (
    name,
    age,
    position_id,
    department_id,
    insert_date,
    update_date
  )
values (
    'Kaccho',
    30,
    '03',
    '001',
    '2020-06-17',
    '2020-06-17'
  );
insert into employee (
    name,
    age,
    position_id,
    department_id,
    insert_date,
    update_date
  )
values (
    'Pampy',
    30,
    '03',
    '002',
    '2020-06-17',
    '2020-06-17'
  );

À la fin

J'aimerais imaginer un cas d'utilisation réel et créer une API plus pratique.

référence

Recommended Posts

J'ai essayé de démarrer avec Spring Data JPA
J'ai essayé de démarrer avec Web Assembly
J'ai essayé de démarrer avec Swagger en utilisant Spring Boot
J'ai essayé le guide d'introduction de Spring Boot [Accès aux données avec JPA]
Les débutants de Rails ont essayé de se lancer avec RSpec
Démarrez avec Spring Boot
J'ai essayé d'implémenter le téléchargement de fichiers avec Spring MVC
J'ai démarré MySQL 5.7 avec docker-compose et j'ai essayé de me connecter
Comment démarrer avec Slim
J'ai essayé d'interagir avec Java
J'ai essayé GraphQL avec Spring Boot
J'ai essayé Flyway avec Spring Boot
OU rechercher avec la spécification Spring Data Jpa
J'ai essayé de me connecter à MySQL en utilisant le modèle JDBC avec Spring MVC
[Note] Comment démarrer avec Rspec
J'ai essayé Spring.
J'ai essayé l'initialisation paresseuse avec Spring Boot 2.2.0
J'ai essayé Spring Data JDBC 1.0.0.BUILD-SNAPSHOT (-> 1.0.0.RELEASE)
J'ai essayé de vérifier AdoptOpenJDK 11 (11.0.2) avec l'image Docker
J'ai essayé de faire une authentification de base avec Java
J'ai essayé de gérer la configuration des jambes de force avec Coggle
Comment démarrer avec Eclipse Micro Profile
J'ai essayé de lier JavaFX et Spring Framework.
Je voulais classer la botte à ressort dans un multi-projet
Trier par Spring Data JPA (avec tri par clé composée)
Création d'un référentiel commun avec Spring Data JPA
J'ai essayé de casser le bloc avec java (1)
J'ai essayé de démarrer avec Gradle sur Heroku
[J'ai essayé] Tutoriel de printemps
J'ai essayé Spring Batch
Commencez avec Gradle
Jackson ne peut pas sérialiser JSON hibernateLazyInitializer dans Spring Data JPA entraîne une erreur
J'ai essayé de générer automatiquement une classe à convertir d'une classe de données en un bundle avec APT
J'ai essayé de cloner une application Web pleine de bugs avec Spring Boot
J'ai essayé ce que je voulais essayer avec Stream doucement.
Un mémorandum lors de l'essai de Spring Data JPA avec STS
J'ai essayé de lire et de sortir CSV avec Outsystems
J'ai essayé d'implémenter TCP / IP + BIO avec JAVA
[Java 11] J'ai essayé d'exécuter Java sans compiler avec javac
05. J'ai essayé de supprimer la source de Spring Boot
J'ai essayé de réduire la capacité de Spring Boot
J'ai essayé de dessiner une animation avec l'API Blazor + canvas
Présentation de «Introduction à la programmation pratique de la rouille» (jour 3)
J'ai essayé d'implémenter Sterling Sort avec Java Collector
J'ai essayé de créer une fonction / écran d'administrateur de site commercial avec Java et Spring
[spring] Utilisons Spring Data JPA
J'ai essayé la machine Spring State
J'ai essayé UPSERT avec PostgreSQL.
Premiers pas avec Spring Boot
J'ai essayé BIND avec Docker
J'ai essayé de vérifier yum-cron
J'ai essayé de créer un environnement de développement java8 avec Chocolatey
J'ai essayé de moderniser une application Java EE avec OpenShift.