我们的老师要求我们创建一个Sping Boot 应用程序来使用DTO以一对多的关系管理歌曲和专辑,但我们需要在控制器中手动进行Map,我们不能使用外部库。问题是,无论我如何尝试更改方法,它总是导致Spring上的错误(我们使用PostgreSQL,在pgadmin中我可以看到数据,没有问题)。
例如,对于我现在共享的代码,我最初可以在歌曲和专辑上使用get,但如果我添加了一首新歌,get方法将导致NoSuchElementException,
特别是这一行:at com.newplaylist.controller.SongController.getSongs(SongController.java:55)
它指向这一行:songs.add(new SongDTO((Song) iterator.next(), iterator.next().getAlbum()));
我也收到了一个500内部服务器错误的 Postman 。提前感谢帮助,如果需要我可以添加完整的异常跟踪。
- 歌曲DTO
import com.newplaylist.entity.Album;
import com.newplaylist.entity.Song;
public class SongDTO {
private Integer id;
private String author, title;
private AlbumDTO album;
public SongDTO() {
}
public SongDTO(Song song) {
this.id = song.getId();
this.author = song.getAuthor();
this.title = song.getTitle();
}
public SongDTO(Song song, Album album) {
this.id = song.getId();
this.author = song.getAuthor();
this.title = song.getTitle();
this.album = new AlbumDTO(album, true);
}
// getters and setters...
}
- 相册DTO
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.newplaylist.entity.Album;
import com.newplaylist.entity.Song;
public class AlbumDTO {
private Integer id;
private String name;
private String production;
private Set<SongDTO> songs;
public AlbumDTO() {
}
public AlbumDTO(Album album) {
this.id = album.getId();
this.name = album.getName();
this.production = album.getProduction();
}
public AlbumDTO(Album album, boolean lazy) {
this.id = album.getId();
this.name = album.getName();
this.production = album.getProduction();
songs = new HashSet<SongDTO>();
album.getSongs();
if (!lazy) {
for (Iterator<Song> iterator = album.getSongs().iterator(); iterator.hasNext();) {
songs.add(new SongDTO((Song) iterator.next()));
}
}
}
// getters and setters...
}
- 乐曲控制器
package com.newplaylist.controller;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.newplaylist.dto.AlbumDTO;
import com.newplaylist.dto.SongDTO;
import com.newplaylist.entity.Album;
import com.newplaylist.entity.Song;
import com.newplaylist.service.SongService;
@RestController
@RequestMapping("/song")
public class SongController {
@Autowired
SongService songService;
public void init() {
}
@PostMapping("/add")
public ResponseEntity<?> addSong(@RequestBody Song song) {
try {
return new ResponseEntity<SongDTO>(new SongDTO(songService.addSong(song), song.getAlbum()), HttpStatus.CREATED);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<Object>(e.getStackTrace(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/all")
public ResponseEntity<Collection<SongDTO>> getSongs() {
Collection<SongDTO> songs = new ArrayList<>();
try {
for (Iterator<Song> iterator = songService.getSongs().iterator(); iterator.hasNext();) {
songs.add(new SongDTO((Song) iterator.next(), iterator.next().getAlbum()));
}
return new ResponseEntity<Collection<SongDTO>>(songs, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
- 相册控制器
package com.newplaylist.controller;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.newplaylist.dto.AlbumDTO;
import com.newplaylist.dto.SongDTO;
import com.newplaylist.entity.Album;
import com.newplaylist.entity.Song;
import com.newplaylist.service.AlbumService;
@RestController
@RequestMapping("/album")
public class AlbumController {
@Autowired
AlbumService albumService;
@PostMapping("/add")
public ResponseEntity<?> addAlbum(@RequestBody Album album) {
try {
return new ResponseEntity<AlbumDTO>(new AlbumDTO(albumService.addAlbum(album), true), HttpStatus.CREATED);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<Object>(e.getStackTrace(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/all")
public ResponseEntity<Collection<AlbumDTO>> getAlbums() {
Collection<AlbumDTO> albums = new ArrayList<>();
try {
for (Iterator<Album> iterator = albumService.getAlbums().iterator(); iterator.hasNext();) {
albums.add(new AlbumDTO((Album) iterator.next(), false));
}
return new ResponseEntity<Collection<AlbumDTO>>(albums, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
- 相册(实体)
package com.newplaylist.entity;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
@Entity
public class Album {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String production;
//@JsonBackReference // per scegliere quale reference stampare, altrimenti andrebbe in loop infinito
@OneToMany(mappedBy = "album", cascade = CascadeType.ALL)
private Set<Song> songs;
public Album() {
super();
}
public Album(Integer id, String name, String production, Set<Song> songs) {
super();
this.id = id;
this.name = name;
this.production = production;
this.songs = songs;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProduction() {
return production;
}
public void setProduction(String production) {
this.production = production;
}
public Set<Song> getSongs() {
return songs;
}
public void setSongs(Set<Song> songs) {
this.songs = songs;
}
}
- 歌曲(实体)
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
@Entity
public class Song {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String author, title;
// @OneToOne
// @JoinColumn(name = "album") // campo album della tab song. questo campo contiene un id che si collega all'entità Album, perciò fai l'inner join con essa.
// private Album album;
// @ManyToOne
// @JoinColumn(name = "playlist")
// private Playlist playlist;
@ManyToOne
@JoinColumn(name = "album", nullable = false)
//@JsonManagedReference
private Album album;
public Song() {}
public Song(Integer id, String author, String title) {
super();
this.id = id;
this.author = author;
this.title = title;
}
public Song(Integer id, String author, String title, Album album) {
super();
this.id = id;
this.author = author;
this.title = title;
this.album = album;
}
// getters and setters
}
我相信问题出在这些类中的一个,但是如果你需要其他的东西,我可以把项目上传到GitHub上。
1条答案
按热度按时间mzillmmw1#
你需要这样的东西
调用iterator.next()将总是获取一首新歌,这意味着iterator.next().getAlbum()将获取与集合中下一首歌对应的专辑,而不是第一次调用iterator.next()时已经获取的当前专辑。此外,如果歌曲数量为奇数,它将导致异常。