欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Spring Boot JPA】ManyToOne OneToMany学习笔记

程序员文章站 2022-04-12 17:50:01
...

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"
}