Это пример двунаправленной связи между объектами Java в веб-службе REST с API Джексона .
1. Предположим, у нас есть двунаправленные отношения между двумя объектами: Родителем и Ребенком.
2. Использование MySQL для создания файла схемы SQL для этих двух таблиц.
DROP SCHEMA IF EXISTS `bidirectional_schema` ;
CREATE SCHEMA IF NOT EXISTS `bidirectional_schema` DEFAULT CHARACTER SET utf8 ;
USE `bidirectional_schema` ;
-- -----------------------------------------------------
-- Table `bidirectional_schema`.`PARENT`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `bidirectional_schema`.`PARENT` ;
CREATE TABLE IF NOT EXISTS `bidirectional_schema`.`PARENT` (
`PARENT_ID` INT NOT NULL ,
`PARENT_CONTENT` VARCHAR(45) NULL ,
PRIMARY KEY (`PARENT_ID`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `bidirectional_schema`.`CHILD`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `bidirectional_schema`.`CHILD` ;
CREATE TABLE IF NOT EXISTS `bidirectional_schema`.`CHILD` (
`CHILD_ID` INT NOT NULL ,
`CHILD_CONTENT` VARCHAR(45) NULL ,
`PARENT_PARENT_ID` INT NOT NULL ,
PRIMARY KEY (`CHILD_ID`) ,
INDEX `fk_CHILD_PARENT_idx` (`PARENT_PARENT_ID` ASC) ,
CONSTRAINT `fk_CHILD_PARENT`
FOREIGN KEY (`PARENT_PARENT_ID` )
REFERENCES `bidirectional_schema`.`PARENT` (`PARENT_ID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
3- Затем мы вставим некоторые данные в эти две таблицы с помощью этих операторов вставки:
INSERT INTO `bidirectional_schema`.`parent` (`PARENT_ID`, `PARENT_CONTENT`) VALUES ('1', 'First Parent');
INSERT INTO `bidirectional_schema`.`child` (`CHILD_ID`, `CHILD_CONTENT`, `PARENT_PARENT_ID`) VALUES ('1', 'First Child', '1');
INSERT INTO `bidirectional_schema`.`child` (`CHILD_ID`, `CHILD_CONTENT`, `PARENT_PARENT_ID`) VALUES ('2', 'Second Child', '1');
4. Зависимости Maven для API Джексона, необходимые для этого примера.
<dependency>
<groupid>com.fasterxml.jackson.core</groupid>
<artifactid>jackson-annotations</artifactid>
<version>2.5.2</version>
</dependency>
<dependency>
<groupid>com.fasterxml.jackson.core</groupid>
<artifactid>jackson-core</artifactid>
<version>2.5.2</version>
</dependency>
<dependency>
<groupid>com.fasterxml.jackson.core</groupid>
<artifactid>jackson-databind</artifactid>
<version>2.5.2</version>
</dependency>
Также по этой ссылке вы можете получить требуемые зависимости Java EE.
https://wikis.oracle.com/display/GlassFish/Java+EE+7+Maven+Coordinates
5 — Использование Eclipse для создания сущностей из приведенных выше таблиц.
Файл -> Создать -> Другое, затем в мастере выберите JPA Entities из таблиц. Появится мастер для создания соединения с уже созданной схемой. Затем выберите две таблицы: дочернюю и родительскую. Наконец убедитесь, что «Список сгенерированных классов в persistence.xml». Вы можете продолжить и следовать настройкам по умолчанию, но я выбрал настройки отображения как показано ниже:
6- В файле persistence.xml нет ничего особенного. Но есть два момента, которые следует учитывать. Во-первых, я не указывал поставщика постоянства, поскольку я склонен использовать WildFly, поэтому приложение будет использовать поставщик постоянства по умолчанию, который называется Hibernate. Во-вторых, я создал источник данных в WildFly, чтобы его можно было использовать для подключения к нашей схеме. В-третьих, я использовал EclipseLink, поэтому я использую этот JPA-провайдер org.eclipse.persistence.jpa.PersistenceProvider. Проверьте этот пост, чтобы указать WildFly на EclipseLink.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="BidirectionalPU">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/Bidirectional_DataSource</jta-data-source>
<class>com.ithinkisink.entity.Child</class>
<class>com.ithinkisink.entity.Parent</class>
</persistence-unit>
</persistence>
7. Первый класс, который мы реализуем, — это класс ApplicationConfiguration, который будет указывать на родительский путь наших будущих служб REST.
package com.ithinkisink;
import javax.inject.Singleton;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
/**
*
* @author Belal
*
*/
@Singleton
@ApplicationPath("rest")
public class ApplicationConfiguration extends Application {
}
8. Затем мы создадим класс MyService, который будет иметь два веб-сервиса REST. Первый извлечет родителя с выбранными детьми. Второй вариант противоположен этому и будет извлекать ребенка с его родителями.
package com.ithinkisink.service;
package com.ithinkisink.service;
import javax.ejb.EJB;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.ithinkisink.entity.Child;
import com.ithinkisink.entity.Parent;
/**
*
* @author Belal
*
*/
@Path("MyService")
public class MyService {
@EJB
MyServiceDAO myServiceDAO;
@GET
@Path("/retrieveParentWithChildren")
@Produces(MediaType.APPLICATION_JSON)
public Parent retrieveParentWithChildren() {
return myServiceDAO.retrieveParentWithChildren();
}
@GET
@Path("/retrieveChildWithParent")
@Produces(MediaType.APPLICATION_JSON)
public Child retrieveChildWithParent() {
return myServiceDAO.retrieveChildWithParent();
}
}
9. Затем мы создадим ServiceDAO и заметим, что EntityManager внедряется с подключением к постоянному модулю, который мы уже определили в файле persistence.xml. Я передал название единицы персистентности, чтобы прояснить этот момент. Но вы можете просто использовать аннотацию @PersistenceContext без указания атрибута unitName, тогда она будет использовать наш модуль постоянства, поскольку в нашем приложении не определено никакого другого модуля постоянства.
package com.ithinkisink.service;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import com.ithinkisink.entity.Child;
import com.ithinkisink.entity.Parent;
@Stateless
public class MyServiceDAO {
@PersistenceContext(unitName="BidirectionalPU")
protected EntityManager entityManager;
public Parent retrieveParentWithChildren() {
int parentId = 1;
Query q = entityManager.createQuery("SELECT p FROM " + "Parent " + "p JOIN FETCH p.childs WHERE p.parentId = :parentId ");
q.setParameter("parentId", parentId);
return (q.getResultList().size() > 0) ? (Parent) q.getResultList().get(0) : null;
}
public Child retrieveChildWithParent() {
int childId = 1;
Query q = entityManager.createQuery("SELECT c FROM " + "Child " + "c JOIN FETCH c.parent WHERE c.childId = :childId ");
q.setParameter("childId", childId);
return (q.getResultList().size() > 0) ? (Child) q.getResultList().get(0) : null;
}
}
10. Теперь, когда наше приложение готово к тестированию, добавим его на сервер WildFly. Тогда запуск сервера должен быть успешным.
11. Для простоты я использовал Postman для тестирования запущенных веб-сервисов REST. Итак, ниже приведены скриншоты из результатов на Почтальоне. Вы можете найти полный пример на моем Github по этой ссылке: https://github.com/belalgalal/Blogging/tree/master/BidirectionalRESTJson