Spring Data JPA

Spring Data JPA هو جزء من عائلة Spring Data. يجعل Spring Data من السهل إنشاء تطبيقات تعمل بناءً على Spring والتي تستخدم طرقًا جديدة للوصول إلى البيانات ، مثل قواعد البيانات غير العلاقية ، وإطارات تقليل الخريطة ، وخدمات السحابة ، بالإضافة إلى دعم قوي لقواعد البيانات العلاقية المتقدمة. ستتناول هذه المقالة حول Spring Data JPA. سنلقي أيضًا نظرة على تطبيق مثالي لـ Spring Data JPA.

Spring Data JPA

بعض الميزات الرائعة التي يوفرها Spring Data JPA هي:

  1. إنشاء ودعم المستودعات التي تم إنشاؤها باستخدام Spring و JPA
  2. دعم QueryDSL واستعلامات JPA
  3. تدقيق فئات المجال
  4. دعم التحميل الدفعي والفرز والاستعلامات الديناميكية
  5. دعم تعيين XML للكيانات
  6. تقليل حجم الكود لعمليات CRUD العامة باستخدام CrudRepository

متى يجب استخدام Spring Data JPA؟

I would say that if you need to quickly create a JPA-based repository layer that is mainly for CRUD operations, and you do not want to create abstract DAO, implementing interfaces, Spring Data JPA is a good choice.

مثال على Spring Data JPA

لمثالنا على Spring Data JPA، سنقوم بإنشاء خدمة ويب RESTful التي ستتصل بقاعدة بيانات Postgresql. سنقوم بتنفيذ العمليات الأساسية للقراءة والإضافة والتحديث والحذف، وسنعمل على بيانات عينة لدينا بالفعل.

بيانات عينة لمثال Spring JPA

استخدم الاستعلام أدناه لإنشاء جدول في قاعدة بيانات Postgresql وإضافة بعض البيانات التجريبية.

create table people (
id serial not null primary key,
first_name varchar(20) not null,
last_name varchar(20) not null,
age integer not null
);

insert into people (id, first_name, last_name, age) values
(1, 'Vlad', 'Boyarskiy', 21),
(2,'Oksi', ' Bahatskaya', 30),
(3,'Vadim', ' Vadimich', 32);

هيكلية مشروع Spring Data JPA Maven

تُظهِر الصورة أدناه هيكلية مشروع Spring JPA النهائية. سنتعرض لكل من المكونات بالتفصيل لاحقًا.

تبعيات Maven لـ Spring Data JPA

نحتاج إلى إضافة التبعيات التالية لمشروع مثال Spring Data JPA الخاص بنا.

  1. postgresql: برنامج تشغيل Postgresql لجافا.
  2. spring-core، spring-context: تعتمد على النواة الأساسية لـ إطار العمل سبرينج.
  3. spring-webmvc، jackson-databind: لتطبيقات سبرينج ريست.
  4. spring-data-jpa، hibernate-entitymanager: لدعم سبرينج داتا JPA و هيبرنيت.

فيما يلي محتوى ملف البناء pom.xml النهائي.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>springData</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>Spring Data JPA Maven Webapp</name>
	<url>https://maven.apache.org</url>
	<properties>
		<spring.framework>4.3.0.RELEASE</spring.framework>
		<postgres.version>42.1.4</postgres.version>
		<serializer.version>2.8.1</serializer.version>
		<spring.data>1.3.4.RELEASE</spring.data>
		<hibernate.manager>4.2.5.Final</hibernate.manager>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.framework}</version>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>${postgres.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.framework}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.framework}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>${spring.data}</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.manager}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${serializer.version}</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>${project.artifactId}</finalName>
	</build>
</project>

فئات تكوين سبرينج

package com.journaldev.spring.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.journaldev.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig {

	private final String PROPERTY_DRIVER = "driver";
	private final String PROPERTY_URL = "url";
	private final String PROPERTY_USERNAME = "user";
	private final String PROPERTY_PASSWORD = "password";
	private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
	private final String PROPERTY_DIALECT = "hibernate.dialect";

	@Autowired
	Environment environment;

	@Bean
	LocalContainerEntityManagerFactoryBean entityManagerFactory() {
		LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
		lfb.setDataSource(dataSource());
		lfb.setPersistenceProviderClass(HibernatePersistence.class);
		lfb.setPackagesToScan("com.journaldev.spring.model");
		lfb.setJpaProperties(hibernateProps());
		return lfb;
	}

	@Bean
	DataSource dataSource() {
		DriverManagerDataSource ds = new DriverManagerDataSource();
		ds.setUrl(environment.getProperty(PROPERTY_URL));
		ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
		ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
		ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
		return ds;
	}

	Properties hibernateProps() {
		Properties properties = new Properties();
		properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
		properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
		return properties;
	}

	@Bean
	JpaTransactionManager transactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
		return transactionManager;
	}
}
  • @Configuration: تعني هذه التعليقة سبرينج أنها فئة تكوين.

  • @EnableTransactionManagement: تتيح هذه التعليقة للمستخدمين استخدام إدارة المعاملات في التطبيق.

  • @EnableJpaRepositories("com.journaldev.spring.repository"): تشير إلى مكان وجود فئات المستودعات.

  • @PropertySource("classpath:database.properties") : يشير إلى وجود ملف خاصية في مسار الفئات. سيتم حقن قيم هذا الملف في المتغيرات البيئية. يتم عرض محتويات ملف database.properties في الأسفل.

    driver=org.postgresql.Driver
    url=jdbc:postgresql://127.0.0.1:5432/postgres
    user=postgres
    password=postgres
    
    hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect
    hibernate.show_sql=true
    
  • لاستخدام Spring Data ، أولاً يجب علينا تكوين حبة DataSource. ثم نحتاج إلى تكوين حبة LocalContainerEntityManagerFactoryBean. نحتاج هذه الحبة للتحكم في الكيانات. في هذه الحبات ، يجب عليك تحديد مزود الاستمرارية أي HibernatePersistence في حالتنا.

  • الخطوة التالية هي تكوين الـ bean لإدارة الـ transaction. في مثالنا، نحن نستخدم JpaTransactionManager. يجب ملاحظة أنه بدون تكوين مدير الـ transaction، لا يمكننا استخدام التعليق البرمجي @Transactional.

كلاسي AppInitializer و WebConfig مستخدمتان لتكوين تطبيقنا كتطبيق ويب بدون استخدام ملف web.xml.

فئة النموذج

package com.journaldev.spring.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "people")
public class Person {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(name = "age")
	private Integer age;
	@Column(name = "first_name")
	private String firstName;
	@Column(name = "last_name")
	private String lastName;

	public Person() {
	}

	public Long getId() {
		return id;
	}

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

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@Override
	public String toString() {
		return "Person{" + "id=" + id + ", age=" + age + ", firstName='" + firstName + '\'' + ", lastName='" + lastName
				+ '\'' + '}';
	}
}

هنا لدينا بعض التعليقات البرمجية الجديدة. دعنا نتحدث عنها بتفصيل أكثر.

  • @Entity: هذا التعليق البرمجي يسمح لمدير الكائنات بإستخدام هذه الفئة ووضعها في السياق.
  • @Table(name = “people”): يقوم بربط الفئة مع جدول في قاعدة البيانات.
  • @Id: يشير إلى أن هذا الحقل هو المفتاح الأساسي.
  • @GeneratedValue(strategy = GenerationType.IDENTITY): يحدد استراتيجية توليد المفتاح الأساسي.
  • @Column(name = "age"): يشير إلى عمود في قاعدة البيانات سيتم ربط هذا الحقل به.

واجهة برمجة التطبيقات JPA لبيانات Spring

الخطوة التالية هي إنشاء واجهة برمجة التطبيقات JPA.

package com.journaldev.spring.repository;

import org.springframework.data.repository.CrudRepository;

import com.journaldev.spring.model.Person;

import java.util.List;

public interface PersonRepository<P> extends CrudRepository<Person, Long> {
    List<Person> findByFirstName(String firstName);
}

من خلال الاستدادة من CrudRepository ، يمكننا استدعاء العديد من الطرق دون الحاجة إلى تنفيذها بنفسنا. بعض هذه الطرق هي:

  • save
  • findOne
  • exists
  • findAll
  • count
  • delete
  • deleteAll

يمكننا أيضًا تعريف طرقنا الخاصة. يجب أن تستخدم أسماء هذه الطرق الكلمات الرئيسية الخاصة مثل “find” و “order” مع اسم المتغيرات. حاول مطورو Spring Data JPA أخذ معظم الخيارات الممكنة التي قد تحتاجها في الاعتبار. في مثالنا ، تعود طريقة findByFirstName(String firstName) بجميع الإدخالات من الجدول حيث يساوي حقل first_name firstName. هذه واحدة من أهم ميزات Spring Data JPA لأنها تقلل الكثير من رموز البرامج المتكررة. أيضًا فرص الأخطاء أقل لأن هذه الطرق المستخدمة بواسطة Spring مجربة جيدًا من قبل العديد من المشاريع التي تستخدمها بالفعل.

فئة خدمة الربيع

الآن بعد أن تمت كتابة رمزنا بناءً على Spring Data JPA ، الخطوة التالية هي إنشاء فئة الخدمة وتعريف الأساليب التي سنعمل بها على جدول قاعدة البيانات.

package com.journaldev.spring.services;

import java.util.List;

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

import com.journaldev.spring.model.Person;
import com.journaldev.spring.repository.PersonRepository;

@Service
public class PersonService {

	@Autowired
	PersonRepository<Person> personRepository;

	@Transactional
	public List<Person> getAllPersons() {
		return (List<Person>) personRepository.findAll();
	}

	@Transactional
	public List<Person> findByName(String name) {
		return personRepository.findByFirstName(name);
	}

	@Transactional
	public Person getById(Long id) {
		return personRepository.findOne(id);
	}

	@Transactional
	public void deletePerson(Long personId) {
		personRepository.delete(personId);
	}

	@Transactional
	public boolean addPerson(Person person) {
		return personRepository.save(person) != null;
	}

	@Transactional
	public boolean updatePerson(Person person) {
		return personRepository.save(person) != null;
	}
}

تشير التعليقة @Transactional إلى أن الطريقة ستتم تنفيذها داخل العملية. سوف يهتم الربيع بإدارة العمليات التنفيذية.

فئة تحكم الربيع

الخطوة النهائية هي إنشاء فئة التحكم لتعريف واجهة برمجة التطبيق (APIs) للعالم الخارجي.

package com.journaldev.spring.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.journaldev.spring.model.Person;
import com.journaldev.spring.services.PersonService;

@RestController
public class PersonController {

	@Autowired
	PersonService personService;

	@RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
	public @ResponseBody Person getAllUsers(@PathVariable Long id) {
		return personService.getById(id);
	}

	@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
	public List<Person> getPersoneByName(@PathVariable String name) {
		return personService.findByName(name);
	}

	@RequestMapping(value = "/person", method = RequestMethod.GET)
	public List<Person> getAll() {
		return personService.getAllPersons();
	}

	@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
	public HttpStatus deletePersnone(@PathVariable Long id) {
		personService.deletePerson(id);
		return HttpStatus.NO_CONTENT;
	}

	@RequestMapping(value = "/person", method = RequestMethod.POST)
	public HttpStatus insertPersone(@RequestBody Person person) {
		return personService.addPerson(person) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
	}

	@RequestMapping(value = "/person", method = RequestMethod.PUT)
	public HttpStatus updatePerson(@RequestBody Person person) {
		return personService.updatePerson(person) ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
	}
}

اختبار Spring Data JPA

قم ببناء المشروع ونشره على خادم الويب المفضل لديك مثل تومكات. الصور التالية توضح الاستجابة لبعض استدعاءات واجهة برمجة التطبيق (APIs).

قراءة الكل في Spring Data JPA

الحصول على العنصر بواسطة الاسم في Spring Data JPA

إنشاء عنصر في Spring Data JPA

تحديث عنصر في Spring Data JPA

حذف عنصر في Spring Data JPA

هذا كل شيء بالنسبة لمثال تعليمي عن Spring Data JPA. يمكنك تنزيل المشروع النهائي من الرابط أدناه.

تنزيل مشروع مثال Spring Data JPA

المرجع: الموقع الرسمي

Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa