【Spring Boot JPA】ManyToOne OneToMany学习笔记
Spring Data JPA的官方文档参考:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
我希望使用JPA进行两个表的一对多和多对一的关系:
相册(Album)1 : N 相片(Photo)
Album的定义为:
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.Data;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "t_album")
@Data
public class Album {
@Id
private String id;
@Column
private String name;
@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "album")
private List<Photo> photos;
}
Photo的定义为:
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.Data;
import javax.persistence.*;
@Entity
@Table(name = "t_photo")
@Data
public class Photo {
@Id
private String id;
@Column
private String name;
@JsonBackReference
@ManyToOne(cascade = CascadeType.REFRESH)
@JoinColumn(name="album_id", referencedColumnName = "id")
private Album album;
}
说明:
jackson中的@JsonBackReference和@JsonManagedReference,以及@JsonIgnore均是为了解决对象中存在双向引用导致的无限递归(infinite recursion)问题。这些标注均可用在属性或对应的get、set方法中。
@JsonBackReference和@JsonManagedReference:这两个标注通常配对使用,通常用在父子关系中。@JsonBackReference标注的属性在序列化(serialization,即将对象转换为json数据)时,会被忽略(即结果中的json数据不包含该属性的内容)。@JsonManagedReference标注的属性则会被序列化。在序列化时,@JsonBackReference的作用相当于@JsonIgnore,此时可以没有@JsonManagedReference。但在反序列化(deserialization,即json数据转换为对象)时,如果没有@JsonManagedReference,则不会自动注入@JsonBackReference标注的属性(被忽略的父或子);如果有@JsonManagedReference,则会自动注入自动注入@JsonBackReference标注的属性。
@JsonIgnore:直接忽略某个属性,以断开无限递归,序列化或反序列化均忽略。当然如果标注在get、set方法中,则可以分开控制,序列化对应的是get方法,反序列化对应的是set方法。在父子关系中,当反序列化时,@JsonIgnore不会自动注入被忽略的属性值(父或子),这是它跟@JsonBackReference和@JsonManagedReference最大的区别。
Album的Repository定义:
import com.example.jpa.model.Album;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AlbumRepository extends JpaRepository<Album, String> {
}
Photo的Repository定义:
import com.example.jpa.model.Album;
import com.example.jpa.model.Photo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface PhotoRepository extends JpaRepository<Photo, String> {
public List<Photo> findByAlbum(Album album);
}
说明:findByAlbum是希望获取一个相册中所有的照片
Album的Restful服务:
import com.example.jpa.model.Album;
import com.example.jpa.model.Photo;
import com.example.jpa.repository.AlbumRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
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.RestController;
import java.util.List;
import java.util.Optional;
@RestController
public class AlbumService {
@Autowired
AlbumRepository albumRepository;
@RequestMapping(value = "/album", method = RequestMethod.POST)
public Album addAlbum(@RequestBody Album album) {
return albumRepository.save(album);
}
@RequestMapping(value = "/album", method = RequestMethod.GET)
public List<Album> getAllAlbum() {
return albumRepository.findAll();
}
@RequestMapping(value = "/album/photo", method = RequestMethod.GET)
public List<Photo> getAlbumPhoto(@RequestBody Album album) {
Optional<Album> optional = albumRepository.findOne(Example.of(album));
return optional.get().getPhotos();
}
}
Photo的Restful服务:
import com.example.jpa.model.Album;
import com.example.jpa.model.Photo;
import com.example.jpa.repository.PhotoRepository;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;
import java.util.List;
@RestController
public class PhotoService {
@Autowired
PhotoRepository photoRepository;
@RequestMapping(value = "/photo", method = RequestMethod.POST)
public Photo addPhoto(@RequestBody Photo photo) {
return photoRepository.save(photo);
}
@RequestMapping(value = "/photo/all", method = RequestMethod.GET)
public List<Photo> getAllPhotos() {
return photoRepository.findAll();
}
@RequestMapping(value = "/photo/album", method = RequestMethod.GET)
public List<Photo> getAlbumPhotos(@RequestBody Album album) {
return photoRepository.findByAlbum(album);
}
}
pom文件定义为:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jpa</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties配置文件:
#配置数据库连接地址
spring.datasource.primary.jdbc-url=jdbc:h2:mem:testdb
#;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=TRUE
#配置数据库驱动
spring.datasource.primary.driver-class-name=org.h2.Driver
#配置数据库用户名
spring.datasource.primary.username=sa
#配置数据库密码
spring.datasource.primary.password=
#配置能远程访问
spring.h2.console.settings.web-allow-others=true
#配置访问地址
spring.h2.console.path=/h2-console
#配置项目启动 h2就启动
spring.h2.console.enabled=true
现在启动服务,使用PostMan进行测试:
添加Album:
POST: http://127.0.0.1:8080/album
Body:
{
"id":"album1",
"name":"the album1"
}
添加Photo:
POST: http://127.0.0.1:8080/photo
Body:
{
"id":"photo1",
"name":"the photo1",
"album":{
"id":"album1"
}
}
查询Album中的Photo:
GET: http://127.0.0.1:8080/album/photo
Body:
{
"id":"album1"
}