【问题标题】:@ManyToOne relations missing from JSON resultJSON 结果中缺少@ManyToOne 关系
【发布时间】:2022-10-24 03:34:11
【问题描述】:

我刚刚开始使用 Spring boot,并且正在使用默认存储库 api 将 db 数据检索为 json。 我添加了一个@ManyToOne 与我的歌曲和艺术家实体的关系。

但是现在我没有从服务器的 json 响应中获取 Artist 对象,而且我并不清楚如何在不错过 PagingAndSorting 存储库中的分页功能的情况下包含它。

我正在使用 spring-data-rest-jpa。

我的回复现在看起来像:

 "_embedded": {
    "songs": [
      {
        "id": 1,
        "title": "SongTitle",
        "genre": "Rap",
        "length": 500,
        "_links": {
          "self": {
            "href": "http://localhost:8080/api/songs/1"
          },
          "song": {
            "href": "http://localhost:8080/api/songs/1"
          },
          "artist": {
            "href": "http://localhost:8080/api/songs/1/artist"
          }
        }
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/api/songs?page=0&size=1"
    },
    "self": {
      "href": "http://localhost:8080/api/songs?size=1"
    },
    "next": {
      "href": "http://localhost:8080/api/songs?page=1&size=1"
    },
    "last": {
      "href": "http://localhost:8080/api/songs?page=19&size=1"
    },
    "profile": {
      "href": "http://localhost:8080/api/profile/songs"
    }
  },
  "page": {
    "size": 1,
    "totalElements": 20,
    "totalPages": 20,
    "number": 0
  }
}

但我希望它是这样的:

"_embedded": {
    "songs": [
      {
        "id": 1,
        "title": "SongTitle",
        "genre": "Rap",
        "length": 500,
        "artist": {
           "id": 1,
           "name": "Artistname"
        }
        "_links": {
          "self": {
            "href": "http://localhost:8080/api/songs/1"
          },
          "song": {
            "href": "http://localhost:8080/api/songs/1"
          },
          "artist": {
            "href": "http://localhost:8080/api/songs/1/artist"
          }
        }
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/api/songs?page=0&size=1"
    },
    "self": {
      "href": "http://localhost:8080/api/songs?size=1"
    },
    "next": {
      "href": "http://localhost:8080/api/songs?page=1&size=1"
    },
    "last": {
      "href": "http://localhost:8080/api/songs?page=19&size=1"
    },
    "profile": {
      "href": "http://localhost:8080/api/profile/songs"
    }
  },
  "page": {
    "size": 1,
    "totalElements": 20,
    "totalPages": 20,
    "number": 0
  }
}

歌曲.java

@Getter
@Setter
@Entity
@Table(name = "song")
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Long id;

    @NotNull
    @NotBlank(message = "The song has to have a title")
    private String title;

    @NotNull
    @NotBlank(message = "The song has to have a genre")
    private String genre;

    @NotNull
    @Min(value = 1, message = "The song has to have a song length in seconds")
    private int length;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "artist_id", referencedColumnName = "id")
    private Artist artist;

   /* @Version
    private long version;*/

    public Song() {
    }

    public Song(String title, Artist artist, String genre, int length) {
        this.title = title;
        this.artist = artist;
        this.genre = genre;
        this.length = length;
    }

    public void setArtist(Artist artist) {
        this.artist = artist;
    }

    public Artist getArtist() {
        return artist;
    }

  
}

艺术家.java

@Getter
@Setter
@Entity
@Table(name = "artist")
public class Artist {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @NotNull
    @NotBlank(message = "The artist has to have a name")
    private String name;

    @JsonIgnore
    @OneToMany(mappedBy = "artist")
    private List<Song> songs;

    public Artist() {
    }

    public Artist(String name) {
        this.name = name;
    }

为了测试,我在 SongController 中编写了一个方法:

@GetMapping
    List<Song> getSongs() {
        return songRepository.findAll();
    }

结果包括 Artist 对象,但不会对其进行任何分页。我怎么能包括它?

json结果:

[
{
    "id": 1,
    "title": "SongTitle",
    "genre": "Rap",
    "length": 500,
    "artist": {
      "id": 1,
      "name": "ArtistName"
    }
  }
]

【问题讨论】:

  • spring data rest 默认使用 HATEOAS 返回只是子对象的链接。因此,您的第一个任务需要您自己实现 HATEOS 表示。第二个任务:您只需返回一个对象列表。那么为什么要有分页细节呢?
  • 我知道这些链接,但我不想用它们来提出额外的请求,但没关系。我知道我返回的只是一个列表,这就是我问的原因,我怎么能包括分页。毕竟我已经解决了它,我会发布一个答案。

标签: java spring hibernate jpa spring-data-jpa


【解决方案1】:

在您提出所有有用的建议后,我找到了答案: 我已将控制器中方法的返回类型更改为 Page 并使用如下所示的 PageRequest 类:

@GetMapping
    public Page<Song> getSongs(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "5") int size) {
        PageRequest pr = PageRequest.of(page, size);
        return songRepository.findAll(pr);
    }

还使用了一些默认值来避免一些异常;)

【讨论】:

    【解决方案2】:

    使用@JsonIdentityInfo 或@JsonIgnore 并删除@JsonBackReference。这是@JsonIgnore 的示例

    public class Artist {
        public Long id;
        public String name;
    
        public List<Song> songs;
    }
    
    public class Song {
        public Long id;
        public String title;
        public String genre;
        public int length;
    
        @JsonIgnore
        public Artist artist;
    }
    

    在这种情况下,@JsonManagedReference 或 @JsonBackReference 将无济于事(在https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion 上阅读更多信息):

    (...) 我们可以使用 @JsonIgnore 注释来简单地忽略关系的一侧,从而破坏链。[我的补充:循环调用链]

    这是@JsonIdentityInfo 的示例:

    @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class, 
      property = "id")
    public class Artist { ... }
    
    @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class, 
      property = "id")
    public class Song { ... }
    

    【讨论】:

    • 嘿,我已经更新了我的问题。如果我想在我的结果中显示它,我不能在我的 Song 类的 Artist 属性上使用“@JsonIgnore”。我用@JsonIdentityInfo 尝试了你的解决方案,但我的结果保持不变
    • 我懂了。使用时@JsonIdentityInfo, 你删除了@JsonBackReference@JsonIgnore?
    • 我再次尝试删除 JsonIgnore,反之亦然,但它仍然保持不变。是否可以在歌曲对象的结果中获取艺术家对象?
    猜你喜欢
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    相关资源
    最近更新 更多