Spring Data JPA

Spring Data JPA היא חלק ממשפחת Spring Data. Spring Data מקלה על יצירת יישומים שמשתמשים בדרכים חדשות לגשת לנתונים, כמו מסדי נתונים לא רלציוניים, מסגרות מפה-הפחתה, שירותי ענן, ותמיכה מתקדמת במסדי נתונים רלציוניים. מאמר זה ידון ב-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. נממש פעולות בסיסיות של CRUD ונעבוד על נתוני דוגמא שכבר יצרנו.

נתוני דוגמא לדוגמא של 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: מנהיג Java של Postgresql.
  2. spring-core, spring-context: מסתבר הקרן של Spring Framework.
  3. spring-webmvc, jackson-databind: ליישום REST של Spring.
  4. spring-data-jpa, hibernate-entitymanager: לתמיכה ב- Spring Data JPA וב- Hibernate.

למטה יש תוכן של קובץ הבנייה 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>

מחלקות הגדרת Spring

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: זו הערה ב- spring שאומרת שזו מחלקת הגדרה.

  • @EnableTransactionManagement: ההערה הזו מאפשרת למשתמשים להשתמש בניהול עסקאות ביישום.

  • @EnableJpaRepositories("com.journaldev.spring.repository"): מציינת את מיקום מחלקות המאגרים.

  • @PropertySource("classpath:database.properties"): אומר שיש לנו קובץ מאפיינים ב-classpath שלנו. הערכים מתוך קובץ זה יוזרקו לתוך משתני סביבת ההרצה. תוכן קובץ 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 bean. לאחר מכן, עלינו להגדיר את ה-LocalContainerEntityManagerFactoryBean bean. אנו זקוקים לבין זה כדי לשלוט על הישויות. בתוך ה-beans אלו, עליך לציין את ספק ההתמצאות שלך, כלומר HibernatePersistence במקרה שלנו.

  • השלב הבא הוא להגדיר פול עבור ניהול עסקאות. בדוגמתנו זה JpaTransactionManager. שימו לב שבלעדי הגדרת מנהל עסקאות לא נוכל להשתמש ב @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(שם = "אנשים"): משייכת מחלקה זו לטבלה במסד הנתונים.
  • @Id: אומר ששדה זה הוא המפתח הראשי.
  • @GeneratedValue(strategy = GenerationType.IDENTITY): מגדיר את האסטרטגיה ליצירת מפתח ראשי.
  • @Column(name = "age"): מציין עמודה במסד נתונים שבה תתייחס השדה הזה.

Spring Data JPA Repository

השלב הבא הוא ליצור את מאגר הנתונים של 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

עכשיו שקוד 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 מציינת שהשיטה תופעל במסגרת העסקה. Spring ידאג לניהול העסקה.

מחלקת בקרת Spring

השלב הסופי הוא ליצור את מחלקת הבקרה כדי לחשוף את ה- API שלנו לעולם החיצוני.

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

רק לבנות ולהתקין את הפרויקט בתוך מתקן ה- servlet האהוב עליך כמו Tomcat. התמונות למטה מציגות את התגובה לכמה משיחות ה- API.

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