From 9787e46afa3f5aead60f1f6664f61526bd2799f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B0=D1=82=D1=8C=D1=8F=D0=BD=D0=B0=20=D0=90=D1=80?= =?UTF-8?q?=D1=82=D0=B0=D0=BC=D0=BE=D0=BD=D0=BE=D0=B2=D0=B0?= Date: Thu, 1 Jun 2023 15:51:35 +0400 Subject: [PATCH] lab4 --- build.gradle | 2 + front/lab4/src/components/Album.vue | 137 ++++++++++++++++++ front/lab4/src/services/AlbumDataService.js | 25 ++++ front/lab4/src/services/ArtistDataService.js | 25 ++++ front/lab4/src/services/SongDataService.js | 25 ++++ front/package.json | 76 +++++----- front/public/index.html | 14 -- .../is/sbapp/controllers/AlbumController.java | 62 ++++---- .../ulstu/is/sbapp/controllers/AlbumDTO.java | 41 +++--- .../sbapp/controllers/ArtistController.java | 58 +++----- .../ulstu/is/sbapp/controllers/ArtistDTO.java | 29 ++-- .../is/sbapp/controllers/SongController.java | 57 ++++---- .../ulstu/is/sbapp/controllers/SongDTO.java | 34 ++++- .../ulstu/is/sbapp/database/model/Album.java | 98 ++++++------- .../ulstu/is/sbapp/database/model/Artist.java | 72 ++++----- .../ulstu/is/sbapp/database/model/Song.java | 48 +++--- .../sbapp/database/service/AlbumService.java | 79 +++++----- .../sbapp/database/service/ArtistService.java | 55 +++---- .../sbapp/database/service/SongService.java | 55 ++++--- .../database/util/error/AdviceController.java | 42 ++++++ .../util/validation/ValidationException.java | 9 ++ .../util/validation/ValidatorUtil.java | 30 ++++ 22 files changed, 674 insertions(+), 399 deletions(-) create mode 100644 front/lab4/src/components/Album.vue create mode 100644 front/lab4/src/services/AlbumDataService.js create mode 100644 front/lab4/src/services/ArtistDataService.js create mode 100644 front/lab4/src/services/SongDataService.js delete mode 100644 front/public/index.html create mode 100644 src/main/java/ru/ulstu/is/sbapp/database/util/error/AdviceController.java create mode 100644 src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidationException.java create mode 100644 src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidatorUtil.java diff --git a/build.gradle b/build.gradle index 2f1221a..7162d35 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,8 @@ dependencies { implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' implementation 'org.jetbrains:annotations:24.0.0' implementation 'org.jetbrains:annotations:24.0.0' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.hibernate.validator:hibernate-validator' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/front/lab4/src/components/Album.vue b/front/lab4/src/components/Album.vue new file mode 100644 index 0000000..3cb6af4 --- /dev/null +++ b/front/lab4/src/components/Album.vue @@ -0,0 +1,137 @@ + + + + + \ No newline at end of file diff --git a/front/lab4/src/services/AlbumDataService.js b/front/lab4/src/services/AlbumDataService.js new file mode 100644 index 0000000..7fa6d12 --- /dev/null +++ b/front/lab4/src/services/AlbumDataService.js @@ -0,0 +1,25 @@ +import axios from "../http-common"; +class AlbumDataService { + + getAll() { + return axios.get( "/albums"); + } + + get(id) { + return axios.get( `/albums/${id}`); + } + + create(data) { + return axios.post( `/albums`, data); + } + + update(id, data) { + return axios.put(`/albums/${id}`, data); + } + + delete(id) { + return axios.delete(`/albums/${id}`); + } +} + +export default new AlbumDataService(); \ No newline at end of file diff --git a/front/lab4/src/services/ArtistDataService.js b/front/lab4/src/services/ArtistDataService.js new file mode 100644 index 0000000..54a42b2 --- /dev/null +++ b/front/lab4/src/services/ArtistDataService.js @@ -0,0 +1,25 @@ +import axios from "../http-common"; +class ArtistDataService { + + getAll() { + return axios.get( "/artists"); + } + + get(id) { + return axios.get( `/artists/${id}`); + } + + create(data) { + return axios.post( `/artists`, data); + } + + update(id, data) { + return axios.put(`/artists/${id}`, data); + } + + delete(id) { + return axios.delete(`/artists/${id}`); + } +} + +export default new ArtistDataService(); \ No newline at end of file diff --git a/front/lab4/src/services/SongDataService.js b/front/lab4/src/services/SongDataService.js new file mode 100644 index 0000000..a8191ab --- /dev/null +++ b/front/lab4/src/services/SongDataService.js @@ -0,0 +1,25 @@ +import axios from "../http-common"; +class SongDataService { + + getAll() { + return axios.get( "/songs"); + } + + get(id) { + return axios.get( `/songs/${id}`); + } + + create(data) { + return axios.post( `/songs`, data); + } + + update(id, data) { + return axios.put(`/songs/${id}`, data); + } + + delete(id) { + return axios.delete(`/songs/${id}`); + } +} + +export default new SongDataService(); \ No newline at end of file diff --git a/front/package.json b/front/package.json index 4eee605..deb156a 100644 --- a/front/package.json +++ b/front/package.json @@ -1,48 +1,50 @@ { - "name": "pages_react", + "name": "front", "version": "0.1.0", "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, "dependencies": { - "@fortawesome/fontawesome-free": "^6.2.1", - "axios": "^1.1.3", - "bootstrap": "^5.2.3", - "react": "^18.2.0", - "react-bootstrap": "^2.7.2", - "react-dom": "^18.2.0", - "react-router-dom": "^6.6.1", - "react-scripts": "5.0.1", - "web-vitals": "^2.1.4" + "axios": "^1.4.0", + "bootstrap": "^4.6.0", + "core-js": "^3.8.3", + "jquery": "^3.6.4", + "popper.js": "^1.16.1", + "vue": "^3.2.13", + "vue-router": "^4.1.6" }, "devDependencies": { - "@types/react": "^18.0.24", - "@types/react-dom": "^18.0.8", - "@vitejs/plugin-react": "^2.2.0", - "json-server": "^0.17.1", - "npm-run-all": "^4.1.5", - "vite": "^3.2.3" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "eslint": "^7.32.0", + "eslint-plugin-vue": "^8.0.3" }, "eslintConfig": { + "root": true, + "env": { + "node": true + }, "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" + "plugin:vue/vue3-essential", + "eslint:recommended" ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } + "parserOptions": { + "parser": "@babel/eslint-parser" + }, + "rules": { + "vue/multi-word-component-names": 0 + } + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead", + "not ie 11" + ] } \ No newline at end of file diff --git a/front/public/index.html b/front/public/index.html deleted file mode 100644 index 28306de..0000000 --- a/front/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - Песни, исполнители и альбомыы - - - -
- - \ No newline at end of file diff --git a/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumController.java b/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumController.java index 6020098..49ff8ca 100644 --- a/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumController.java +++ b/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumController.java @@ -1,43 +1,55 @@ package ru.ulstu.is.sbapp.controllers; -import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import ru.ulstu.is.sbapp.database.service.AlbumService; +import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/album") public class AlbumController { private final AlbumService albumService; + @Autowired public AlbumController(AlbumService albumService){ this.albumService = albumService; } - @PostMapping - public AlbumDTO addAlbum(@RequestBody @Validated AlbumDTO albumDTO){ - return new AlbumDTO(albumService.addAlbum(albumDTO)); - } - @PutMapping("/{id}") - public AlbumDTO updateAlbum(@PathVariable Long id, @RequestBody @Validated AlbumDTO albumDTO){ - return new AlbumDTO(albumService.updateAlbum(id, albumDTO)); - } - @DeleteMapping("/{id}") - public AlbumDTO removeAlbum(@PathVariable Long id){ - return new AlbumDTO(albumService.deleteAlbum(id)); - } - @DeleteMapping - public void removeAllAlbums(){ - albumService.deleteAllAlbums(); - } - @GetMapping("/{id}") - public AlbumDTO findAlbum(@PathVariable Long id){ + @GetMapping("/albums/{id}") + public AlbumDTO getAlbum(@PathVariable Long id) { return new AlbumDTO(albumService.findAlbum(id)); } - @GetMapping - public List findAllAlbums(){ - return albumService.findAllAlbums() - .stream() - .map(x -> new AlbumDTO(x)) - .toList(); + @GetMapping("/albums") + public List getAlbums() { + return albumService.findAllAlbums().stream().map(AlbumDTO::new).toList(); + } + @PostMapping("/albums") + public ResponseEntity createAlbum(@RequestBody @Valid AlbumDTO albumDTO){ + List list = new ArrayList<>(); + for (ArtistDTO art: + albumDTO.getArtistList()) { + list.add(art.getId()); + } + return new ResponseEntity<> + (new AlbumDTO(albumService.addAlbum + (albumDTO.getAlbumName(),list)), HttpStatus.OK); + } + @PutMapping("/albums/{id}") + public ResponseEntity updateAlbum(@RequestBody @Valid AlbumDTO albumDTO){ + List list = new ArrayList<>(); + for (ArtistDTO art: + albumDTO.getArtistList()) { + list.add(art.getId()); + } + return new ResponseEntity<> + (new AlbumDTO(albumService.updateAlbum + (albumDTO.getId(), albumDTO.getAlbumName(), list)), HttpStatus.OK); + } + @DeleteMapping("/albums/{id}") + public AlbumDTO deleteAlbum(@PathVariable Long id){ + return new AlbumDTO(albumService.deleteAlbum(id)); } } diff --git a/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumDTO.java b/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumDTO.java index 41d1b13..d7d8ad1 100644 --- a/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumDTO.java +++ b/src/main/java/ru/ulstu/is/sbapp/controllers/AlbumDTO.java @@ -1,38 +1,41 @@ package ru.ulstu.is.sbapp.controllers; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; import ru.ulstu.is.sbapp.database.model.Album; import java.util.List; public class AlbumDTO { - private long id; - private String albumName; - private List songDTOList; - private List artistDTOList; + @NotNull(message = "Id can't be null") + private final Long id; + @NotBlank(message = "Name can't be null or empty") + private final String albumName; + @Null + private final List artistList; public AlbumDTO(Album album){ this.id = album.getId(); this.albumName = album.getAlbumName(); - this.artistDTOList = album.getArtists() == null ? null : album.getArtists() - .stream() - .filter(x -> x.getAlbum().contains(album)) - .map(ArtistDTO::new) - .toList(); - this.songDTOList = album.getSongs() == null ? null : album.getSongs() - .stream() - .map(SongDTO::new) - .toList(); + this.artistList = album.getArtists().stream().map(ArtistDTO::new).toList(); } - public AlbumDTO(){} - public long getId() { + public AlbumDTO(Long id, String albumName, List artistList){ + this.id = id; + this.albumName = albumName; + this.artistList = artistList; + } + public Long getId() { return id; } public String getAlbumName(){ return albumName; } - public List getSongDTOList(){ - return songDTOList; + public List getArtistList(){ + return artistList; } - public List getArtistDTOList(){ - return artistDTOList; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public String getData() { + return String.format("%s %s %s", id, albumName, artistList.toString()); } } diff --git a/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistController.java b/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistController.java index 3e49b7c..7d02e18 100644 --- a/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistController.java +++ b/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistController.java @@ -1,6 +1,9 @@ package ru.ulstu.is.sbapp.controllers; -import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import ru.ulstu.is.sbapp.database.service.ArtistService; @@ -10,45 +13,32 @@ import java.util.List; @RequestMapping("/artist") public class ArtistController { private final ArtistService artistService; + @Autowired public ArtistController(ArtistService artistService){ this.artistService = artistService; } - @PostMapping - public ArtistDTO addArtist(@RequestBody @Validated ArtistDTO artistDTO) { - return new ArtistDTO(artistService.addArtist(artistDTO)); - } - - @PutMapping("/{id}") - public ArtistDTO updateArtist(@PathVariable Long id,@RequestBody @Validated ArtistDTO artistDTO) { - return new ArtistDTO(artistService.updateArtist(id, artistDTO)); - } - - @DeleteMapping("/{id}") - public ArtistDTO removeArtist(@PathVariable Long id) { - return new ArtistDTO(artistService.deleteArtist(id)); - } - - @DeleteMapping - public void removeAllArtists() { - artistService.deleteAllArtists(); - } - - @GetMapping("/{id}") - public ArtistDTO findArtist(@PathVariable Long id) { + @GetMapping("/artists/{id}") + public ArtistDTO getArtist(@PathVariable Long id) { return new ArtistDTO(artistService.findArtist(id)); } - @GetMapping("/worker/{id}") - public List findSongsOnWorkplace(@PathVariable Long id){ - return artistService.findAllSongsProducedArtist(id) - .stream() - .map(SongDTO::new) - .toList(); - } - @GetMapping - public List findAllArtist() { - return artistService.findAllArtists() - .stream() + @GetMapping("/artists") + public List getArtists() { + return artistService.findAllArtists().stream() .map(ArtistDTO::new) .toList(); } + @PostMapping("/artists") + public ResponseEntity createArtist(@RequestBody @Valid ArtistDTO artistDTO) { + return new ResponseEntity<>(new ArtistDTO(artistService.addArtist(artistDTO.getArtistName(), artistDTO.getGenre())), HttpStatus.OK); + } + + @PutMapping("/artists/{id}") + public ResponseEntity updateArtist(@RequestBody @Valid ArtistDTO artistDTO) { + return new ResponseEntity<>(new ArtistDTO(artistService.updateArtist(artistDTO.getId(), artistDTO.getArtistName(), artistDTO.getGenre())), HttpStatus.OK); + } + + @DeleteMapping("/artists/{id}") + public ArtistDTO deleteArtist(@PathVariable Long id) { + return new ArtistDTO(artistService.deleteArtist(id)); + } } diff --git a/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistDTO.java b/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistDTO.java index 4b4edda..0877a02 100644 --- a/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistDTO.java +++ b/src/main/java/ru/ulstu/is/sbapp/controllers/ArtistDTO.java @@ -1,38 +1,35 @@ package ru.ulstu.is.sbapp.controllers; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import ru.ulstu.is.sbapp.database.model.Artist; import java.util.List; public class ArtistDTO { - private long id; - private String artistName; - private String genre; - private List albumDTOList; + @NotNull(message = "Id can't be null") + private final Long id; + @NotBlank(message = "Name can't be null or empty") + private final String artistName; + @NotBlank(message = "Genre can't be null or empty") + private final String genre; public ArtistDTO(Artist artist){ this.id = artist.getId(); this.artistName = artist.getArtistName(); this.genre = artist.getGenre(); - this.albumDTOList = artist.getAlbum() == null ? null : artist.getAlbum() - .stream() - .filter(x -> x.getArtists().contains(artist.getId())) - .map(y -> new AlbumDTO(y)) - .toList(); } - public ArtistDTO() { + public ArtistDTO(Long id, String artistName, String genre) { + this.id = id; + this.artistName = artistName; + this.genre = genre; } - - public long getId() { + public Long getId() { return id; } public String getArtistName() { return artistName; } - public String getGenre() { return genre; } - public List getAlbumDTOList(){ - return albumDTOList; - } } diff --git a/src/main/java/ru/ulstu/is/sbapp/controllers/SongController.java b/src/main/java/ru/ulstu/is/sbapp/controllers/SongController.java index 819f4f8..2e497f4 100644 --- a/src/main/java/ru/ulstu/is/sbapp/controllers/SongController.java +++ b/src/main/java/ru/ulstu/is/sbapp/controllers/SongController.java @@ -1,6 +1,9 @@ package ru.ulstu.is.sbapp.controllers; -import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import ru.ulstu.is.sbapp.database.service.SongService; @@ -10,44 +13,34 @@ import java.util.List; @RequestMapping("/song") public class SongController { private final SongService songService; + @Autowired public SongController(SongService songService){ this.songService = songService; } - @PostMapping - public SongDTO addSong(@RequestBody @Validated SongDTO songDTO) { - return new SongDTO(songService.addSong(songDTO)); - } - - @PutMapping("/{id}") - public SongDTO updateSong(@PathVariable Long id,@RequestBody @Validated SongDTO songDTO) { - return new SongDTO(songService.updateSong(id, songDTO)); - } - - @DeleteMapping("/{id}") - public SongDTO removeSong(@PathVariable Long id) { - return new SongDTO(songService.deleteSong(id)); - } - - @DeleteMapping - public void removeAllSongs() { - songService.deleteAllSongs(); - } - - @GetMapping("/{id}") - public SongDTO findSong(@PathVariable Long id) { + @GetMapping("/songs/{id}") + public SongDTO getSong(@PathVariable Long id) { return new SongDTO(songService.findSong(id)); } - @GetMapping("/workplace/{id}") - public List findSongsOnWorkplace(@PathVariable Long id){ - return songService.findSongsInAlbum(id).stream() + @GetMapping("/songs") + public List getSongs() { + return songService.findAllSongs().stream() .map(SongDTO::new) .toList(); } - @GetMapping - public List findAllSong() { - return songService.findAllSongs() - .stream() - .map(x-> new SongDTO(x)) - .toList(); + @PostMapping("/songs") + public ResponseEntity createSong(@RequestBody @Valid SongDTO songDTO) { + return new ResponseEntity<> + (new SongDTO(songService.addSong + (songDTO.getSongName(), songDTO.getDuration(), songDTO.getAlbum().getId())), HttpStatus.OK); + } + + @PutMapping("/song/{id}") + public ResponseEntity updateSong(@RequestBody @Valid SongDTO songDTO) { + return new ResponseEntity<>(new SongDTO(songService.updateSong(songDTO.getId(), songDTO.getSongName(), songDTO.getDuration(), songDTO.getAlbum().getId())), HttpStatus.OK); + } + + @DeleteMapping("/songs/{id}") + public SongDTO deleteSong(@PathVariable Long id) { + return new SongDTO(songService.deleteSong(id)); } } diff --git a/src/main/java/ru/ulstu/is/sbapp/controllers/SongDTO.java b/src/main/java/ru/ulstu/is/sbapp/controllers/SongDTO.java index 3084567..ad23c5d 100644 --- a/src/main/java/ru/ulstu/is/sbapp/controllers/SongDTO.java +++ b/src/main/java/ru/ulstu/is/sbapp/controllers/SongDTO.java @@ -1,17 +1,30 @@ package ru.ulstu.is.sbapp.controllers; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import ru.ulstu.is.sbapp.database.model.Song; public class SongDTO { - private Long id; - private String songName; - private Double Duration; + @NotNull(message = "Id can't be null") + private final Long id; + @NotBlank(message = "Name can't be null or empty") + private final String songName; + @NotNull(message = "Album can't be null") + private final AlbumDTO album; + @NotBlank(message = "Duration can't be null or empty") + private final Double duration; public SongDTO(Song song){ this.id = song.getId(); this.songName = song.getSongName(); - this.Duration = song.getSongDuration(); + this.duration = song.getDuration(); + this.album = new AlbumDTO(song.getAlbum()); } - public SongDTO(){ + public SongDTO(Long id, String songName, Double duration, AlbumDTO album){ + this.id = id; + this.songName = songName; + this.duration = duration; + this.album = album; } public Long getId() { return id; @@ -19,7 +32,14 @@ public class SongDTO { public String getSongName(){ return songName; } - public Double getSongDuration(){ - return Duration; + public Double getDuration(){ + return duration; + } + public AlbumDTO getAlbum() { + return album; + } + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + public String getData() { + return String.format("%s %s %s %s", id, songName, duration, album.getAlbumName()); } } diff --git a/src/main/java/ru/ulstu/is/sbapp/database/model/Album.java b/src/main/java/ru/ulstu/is/sbapp/database/model/Album.java index 63b917a..7e27db2 100644 --- a/src/main/java/ru/ulstu/is/sbapp/database/model/Album.java +++ b/src/main/java/ru/ulstu/is/sbapp/database/model/Album.java @@ -1,96 +1,93 @@ package ru.ulstu.is.sbapp.database.model; import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; import java.util.Objects; @Entity -@Table(name = "album") public class Album { @Id - @GeneratedValue - private long id; - @NotNull(message = "Name can't be empty") - @Column(name = "name") + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + @NotBlank private String albumName; - @OneToMany(cascade = {CascadeType.MERGE}) - @JoinColumn(name = "songs", nullable = true) + @OneToMany(fetch = FetchType.EAGER,mappedBy = "album") private List songs; - @ManyToMany(cascade = { CascadeType.MERGE }, fetch = FetchType.EAGER) + @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "albums_artists", joinColumns = @JoinColumn(name = "album_fk"), inverseJoinColumns = @JoinColumn(name = "artist_fk")) private List artists; - public Album(){ - } - public Album(String albumName, List artists, List songs){ + public Album(){} + public Album(String albumName){ this.albumName = albumName; - this.artists = artists; - this.songs = songs; } public Long getId() { return id; } - - public String getAlbumName() { + public String getAlbumName(){ return albumName; } + public void setAlbumName(String albumName) { this.albumName = albumName; } - public List getArtists() { + public List getArtists(){ return artists; } - public List getSongs(){return songs;} - public void setArtists(List artists) { - this.artists = artists; - } - public void setSongs(List songs) { - this.songs = songs; - } - public void update(Album album){ - this.albumName = album.albumName; - this.artists = album.getArtists(); - } public void addArtist(Artist artist){ - if (artists == null){ - this.artists = new ArrayList<>(); - } - if (!artists.contains(artist)) { - this.artists.add(artist); - artist.addAlbum(this); - } + if(artists==null) + artists=new ArrayList<>(); + artists.add(artist); + artist.addAlbum(this); } + public void setArtists(List art){ + this.artists=art; + } public void removeArtist(Artist artist){ - if (artists.contains(artist)) { - this.artists.remove(artist); + if(artists!=null){ + artists.remove(artist); artist.removeAlbum(this); } } - public void addSong(Song song){ - if (songs == null){ - this.songs = new ArrayList<>(); - } - if (!songs.contains(song)) { - this.songs.add(song); - } + public List getSongs(){ + return songs; } - public void removeSong(Song song){ - if (songs.contains(song)) { - this.songs.remove(song); - } + public void addSong(Song song){ + if(songs==null) + songs = new ArrayList<>(); + songs.add(song); + } + public void removeSong(Song song){ + if(song!=null) + songs.remove(song); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Album album = (Album) o; + if(!this.id.equals(album.getId())) return false; + if(!this.albumName.equals(album.getAlbumName())) return false; + if(artists.size() != album.getArtists().size()) return false; + if(artists.size()>0){ + for (Artist art: + artists) { + boolean check = false; + for (Artist artAlb: + album.getArtists()) { + if(art.equals(artAlb)) + check = true; + } + if(!check) + return false; + } + } return Objects.equals(id, album.id); } - @Override public int hashCode() { return Objects.hash(id); @@ -100,7 +97,8 @@ public class Album { public String toString() { return "Album{" + "id=" + id + - ", albumName='" + albumName + '\'' + + ", Name='" + albumName + '\'' + + "Artists:" + (artists == null ? "[]" : artists.toString()) + '}'; } } diff --git a/src/main/java/ru/ulstu/is/sbapp/database/model/Artist.java b/src/main/java/ru/ulstu/is/sbapp/database/model/Artist.java index 27cdcd0..6b82e86 100644 --- a/src/main/java/ru/ulstu/is/sbapp/database/model/Artist.java +++ b/src/main/java/ru/ulstu/is/sbapp/database/model/Artist.java @@ -1,7 +1,7 @@ package ru.ulstu.is.sbapp.database.model; import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; @@ -10,73 +10,57 @@ import java.util.Objects; @Entity public class Artist { @Id - @GeneratedValue + @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @NotNull(message = "Name can't be empty") - @Column(name = "artistName") + @NotBlank private String artistName; - @NotNull(message = "Genre can't be null or empty") - @Column(name = "genre") + @NotBlank private String genre; - @ManyToMany(mappedBy = "artists",cascade = CascadeType.MERGE, fetch = FetchType.EAGER) - private List album; - public Artist() { - } + @ManyToMany(fetch = FetchType.EAGER,mappedBy = "artists") + private List albums; - public Artist(String artistName, String genre) { + public Artist(){} + public Artist(String artistName, String genre){ this.artistName = artistName; this.genre = genre; } - public Long getId() { return id; } - - public String getArtistName() { + public String getArtistName(){ return artistName; } - - public void setArtistName(String artistName) { - this.artistName = artistName; + public void setArtistName(String value){ + artistName=value; } - - public String getGenre() { + public String getGenre(){ return genre; } - - public void setGenre(String genre) { - this.genre = genre; + public void setGenre(String value){ + genre=value; } - - public List getAlbum() { - return album; + public List getAlbums(){ + return albums; } - - public void setAlbum(List album) { - this.album = album; + public void addAlbum(Album album){ + if(albums==null) + albums = new ArrayList<>(); + albums.add(album); } - - public void addAlbum(Album album) { - if (this.album == null) { - this.album = new ArrayList<>(); - } - if (!this.album.contains(album)) - this.album.add(album); + public void removeAlbum(Album album){ + if(album!=null) + albums.remove(album); } - - public void removeAlbum(Album album) { - if (this.album.contains(album)) - this.album.remove(album); - } - @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Artist artist = (Artist) o; + if(!this.artistName.equals(artist.getArtistName())) return false; + if(!this.genre.equals(artist.getGenre())) return false; + if(this.id != artist.getId()) return false; return Objects.equals(id, artist.id); } - @Override public int hashCode() { return Objects.hash(id); @@ -86,8 +70,8 @@ public class Artist { public String toString() { return "Artist{" + "id=" + id + - ", artistName='" + artistName + '\'' + - ", genre='" + genre + '\'' + + ", Name='" + artistName + '\'' + + ", Genre='" + genre + '\'' + '}'; } } diff --git a/src/main/java/ru/ulstu/is/sbapp/database/model/Song.java b/src/main/java/ru/ulstu/is/sbapp/database/model/Song.java index a8f8752..4915ca1 100644 --- a/src/main/java/ru/ulstu/is/sbapp/database/model/Song.java +++ b/src/main/java/ru/ulstu/is/sbapp/database/model/Song.java @@ -1,6 +1,7 @@ package ru.ulstu.is.sbapp.database.model; import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.util.Objects; @@ -9,39 +10,50 @@ import java.util.Objects; @Table(name = "song") public class Song { @Id - @GeneratedValue + @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @NotNull(message = "Name can't be empty") - @Column(name = "name") + @NotBlank private String songName; - @NotNull(message = "Duration can't be empty") - @Column(name = "duration") - private Double Duration; - public Song(){ + @NotBlank + private Double duration; + @NotNull + @ManyToOne + private Album album; + public Song(){} + public Song(String songName, Double duration){ + this.songName=songName; + this.duration=duration; } - public Song(String songName, Double Duration){ - this.songName = songName; - this.Duration = Duration; + public Long getId() { + return id; } - public Long getId(){return id;} public String getSongName(){ return songName; } - public Double getSongDuration(){ - return Duration; - } public void setSongName(String songName) { this.songName = songName; } - - public void setSongDuration(Double Duration) { - this.Duration = Duration; + public Double getDuration(){return duration;} + public void setDuration(Double duration) { + this.duration = duration; } + public Album getAlbum() { + return album; + } + public void setAlbum(Album value){ + album=value; + album.addSong(this); + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Song song = (Song) o; + if(!this.id.equals(song.getId())) return false; + if(!this.songName.equals(song.getSongName())) return false; + if(!this.duration.equals(song.getDuration())) return false; + if(!this.album.getId().equals(song.getAlbum().getId())) return false; return Objects.equals(id, song.id); } @Override @@ -54,7 +66,7 @@ public class Song { return "Song{" + "id=" + id + ", songName='" + songName + '\'' + - ", Duration='" + Duration + '\'' + + ", Duration='" + duration + '\'' + '}'; } } diff --git a/src/main/java/ru/ulstu/is/sbapp/database/service/AlbumService.java b/src/main/java/ru/ulstu/is/sbapp/database/service/AlbumService.java index 1657a93..59489e6 100644 --- a/src/main/java/ru/ulstu/is/sbapp/database/service/AlbumService.java +++ b/src/main/java/ru/ulstu/is/sbapp/database/service/AlbumService.java @@ -3,51 +3,45 @@ package ru.ulstu.is.sbapp.database.service; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.ulstu.is.sbapp.Repository.IAlbumRepository; -import ru.ulstu.is.sbapp.controllers.AlbumDTO; import ru.ulstu.is.sbapp.database.model.Album; import ru.ulstu.is.sbapp.database.model.Artist; -import ru.ulstu.is.sbapp.database.model.Song; +import ru.ulstu.is.sbapp.database.util.validation.ValidatorUtil; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @Service public class AlbumService { + private final IAlbumRepository albumRepository; - private final ArtistService artistService; - private final SongService songService; - public AlbumService(IAlbumRepository albumRepository, - ArtistService artistService, - SongService songService - ){ + private final ValidatorUtil validatorUtil; + private final ArtistService artistService; + + public AlbumService(IAlbumRepository albumRepository, ValidatorUtil validatorUtil, ArtistService artistService){ this.albumRepository = albumRepository; + this.validatorUtil = validatorUtil; this.artistService = artistService; - this.songService = songService; } @Transactional - public Album addAlbum(AlbumDTO albumDTO) { + public Album addAlbum(String albumName, List artistsId) { + final Album album = new Album(albumName); + if(artistsId.size() > 0 ) + { + for (Long id: + artistsId) { + Artist art = artistService.findArtist(id); + album.addArtist(art); + } + } + else + album.setArtists(new ArrayList<>()); + validatorUtil.validate(album); - List artists = artistService.findAllArtistsById(albumDTO); - List songs = songService.findAllSongById(albumDTO); + return albumRepository.save(album); + } - final Album album = new Album( - albumDTO.getAlbumName(), artists, songs); - albumRepository.save(album); - return album; - } - @Transactional - public Album addSong(AlbumDTO albumDTO, List songs){ - final Album currentAlbum = findAlbum(albumDTO.getId()); - currentAlbum.setSongs(songs); - return currentAlbum; - } - @Transactional - public Album addArtist(AlbumDTO albumDTO, List artists){ - final Album currentAlbum = findAlbum(albumDTO.getId()); - currentAlbum.setArtists(artists); - return currentAlbum; - } @Transactional(readOnly = true) public Album findAlbum(Long id) { final Optional album = albumRepository.findById(id); @@ -59,24 +53,31 @@ public class AlbumService { } @Transactional - public Album updateAlbum(Long id, AlbumDTO albumDTO) { + public Album updateAlbum(Long id, String albumName, List artistIds) { final Album currentAlbum = findAlbum(id); - currentAlbum.setAlbumName(albumDTO.getAlbumName()); - - List newArtists = artistService.findAllArtistsById(albumDTO); - List newSongs = songService.findAllSongById(albumDTO); - - currentAlbum.setArtists(newArtists); - currentAlbum.setSongs(newSongs); - albumRepository.save(currentAlbum); - return currentAlbum; + currentAlbum.setAlbumName(albumName); + if(artistIds.size()>0) + { + currentAlbum.getArtists().clear(); + for (Long ArtId: + artistIds) { + Artist art = artistService.findArtist(ArtId); + currentAlbum.addArtist(art); + } + } + else + currentAlbum.getArtists().clear(); + validatorUtil.validate(currentAlbum); + return albumRepository.save(currentAlbum); } + @Transactional public Album deleteAlbum(Long id) { final Album currentAlbum = findAlbum(id); albumRepository.delete(currentAlbum); return currentAlbum; } + @Transactional public void deleteAllAlbums() { albumRepository.deleteAll(); diff --git a/src/main/java/ru/ulstu/is/sbapp/database/service/ArtistService.java b/src/main/java/ru/ulstu/is/sbapp/database/service/ArtistService.java index 69174cb..8b5f454 100644 --- a/src/main/java/ru/ulstu/is/sbapp/database/service/ArtistService.java +++ b/src/main/java/ru/ulstu/is/sbapp/database/service/ArtistService.java @@ -3,72 +3,57 @@ package ru.ulstu.is.sbapp.database.service; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.ulstu.is.sbapp.Repository.IArtistRepository; -import ru.ulstu.is.sbapp.controllers.AlbumDTO; -import ru.ulstu.is.sbapp.controllers.ArtistDTO; -import ru.ulstu.is.sbapp.database.model.Album; import ru.ulstu.is.sbapp.database.model.Artist; -import ru.ulstu.is.sbapp.database.model.Song; +import ru.ulstu.is.sbapp.database.util.validation.ValidatorUtil; import java.util.List; import java.util.Optional; @Service public class ArtistService { + private final IArtistRepository artistRepository; - public ArtistService(IArtistRepository artistRepository){ + private final ValidatorUtil validatorUtil; + + public ArtistService(IArtistRepository artistRepository, + ValidatorUtil validatorUtil) { this.artistRepository = artistRepository; + this.validatorUtil = validatorUtil; } @Transactional - public Artist addArtist(ArtistDTO artistDTO) { - Artist artist =new Artist(artistDTO.getArtistName(), artistDTO.getGenre()); - artistRepository.save(artist); - return artist; + public Artist addArtist(String artistName, String genre) { + final Artist artist = new Artist(artistName, genre); + validatorUtil.validate(artist); + return artistRepository.save(artist); } + @Transactional(readOnly = true) public Artist findArtist(Long id) { final Optional artist = artistRepository.findById(id); - return artist.orElseThrow(()->new ArtistNotFoundException(id)); + return artist.orElseThrow(() -> new ArtistNotFoundException(id)); } @Transactional(readOnly = true) public List findAllArtists() { return artistRepository.findAll(); } - @Transactional(readOnly = true) - public List findAllArtistsById(AlbumDTO albumDTO) { - return artistRepository - .findAllById(albumDTO - .getArtistDTOList() - .stream() - .map(x -> x.getId()) - .toList()); - } @Transactional - public Artist updateArtist(Long id, ArtistDTO artistDTO) { + public Artist updateArtist(Long id, String artistName, String genre) { final Artist currentArtist = findArtist(id); - currentArtist.setArtistName(artistDTO.getArtistName()); - currentArtist.setGenre(artistDTO.getGenre()); - artistRepository.save(currentArtist); - return currentArtist; + currentArtist.setArtistName(artistName); + currentArtist.setGenre(genre); + validatorUtil.validate(currentArtist); + return artistRepository.save(currentArtist); } @Transactional public Artist deleteArtist(Long id) { - final Artist currentArtist= findArtist(id); - int size = currentArtist.getAlbum().size(); - for (int i = 0; i < size; i++) { - Album temp = currentArtist.getAlbum().get(i); - temp.removeArtist(currentArtist); - currentArtist.removeAlbum(temp); - } + final Artist currentArtist = findArtist(id); artistRepository.delete(currentArtist); return currentArtist; } - @Transactional - public List findAllSongsProducedArtist(Long id){ - return artistRepository.getSongs(findArtist(id)); - } + @Transactional public void deleteAllArtists() { artistRepository.deleteAll(); diff --git a/src/main/java/ru/ulstu/is/sbapp/database/service/SongService.java b/src/main/java/ru/ulstu/is/sbapp/database/service/SongService.java index 1d2e4b5..edbb8eb 100644 --- a/src/main/java/ru/ulstu/is/sbapp/database/service/SongService.java +++ b/src/main/java/ru/ulstu/is/sbapp/database/service/SongService.java @@ -3,53 +3,55 @@ package ru.ulstu.is.sbapp.database.service; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.ulstu.is.sbapp.Repository.ISongRepository; -import ru.ulstu.is.sbapp.controllers.SongDTO; -import ru.ulstu.is.sbapp.controllers.AlbumDTO; +import ru.ulstu.is.sbapp.database.model.Album; import ru.ulstu.is.sbapp.database.model.Song; +import ru.ulstu.is.sbapp.database.util.validation.ValidatorUtil; import java.util.List; import java.util.Optional; @Service public class SongService { + private final ISongRepository songRepository; - public SongService(ISongRepository songRepository){ + private final ValidatorUtil validatorUtil; + private final AlbumService albumService; + + public SongService(ISongRepository songRepository, ValidatorUtil validatorUtil, AlbumService albumService){ this.songRepository = songRepository; + this.validatorUtil = validatorUtil; + this.albumService = albumService; } + @Transactional - public Song addSong(SongDTO songDTO) { - final Song song = new Song(songDTO.getSongName(), songDTO.getSongDuration()); - songRepository.save(song); - return song; + public Song addSong(String songName, Double duration, Long albumId){ + final Song song = new Song(songName,duration); + Album curAlbum = albumService.findAlbum(albumId); + song.setAlbum(curAlbum); + validatorUtil.validate(song); + return songRepository.save(song); } + @Transactional(readOnly = true) public Song findSong(Long id) { final Optional song = songRepository.findById(id); - return song.orElseThrow(()->new SongNotFoundException(id)); - } - @Transactional(readOnly = true) - public List findAllSongById(AlbumDTO albumDTO) { - return songRepository - .findAllById(albumDTO - .getSongDTOList() - .stream() - .map(x->x.getId()) - .toList()); + return song.orElseThrow(() -> new SongNotFoundException(id)); } @Transactional(readOnly = true) public List findAllSongs() { - return songRepository - .findAll(); + return songRepository.findAll(); } @Transactional - public Song updateSong(Long id, SongDTO song) { + public Song updateSong(Long id, String songName, Double duration, Long albumId) { final Song currentSong = findSong(id); - currentSong.setSongName(song.getSongName()); - currentSong.setSongDuration(song.getSongDuration()); - songRepository.save(currentSong); - return currentSong; + currentSong.setSongName(songName); + currentSong.setDuration(duration); + Album curAlbum = albumService.findAlbum(albumId); + currentSong.setAlbum(curAlbum); + validatorUtil.validate(currentSong); + return songRepository.save(currentSong); } @Transactional @@ -59,11 +61,6 @@ public class SongService { return currentSong; } - @Transactional - public List findSongsInAlbum(Long id){ - return songRepository.findSongsInAlbum(findSong(id)); - } - @Transactional public void deleteAllSongs() { songRepository.deleteAll(); diff --git a/src/main/java/ru/ulstu/is/sbapp/database/util/error/AdviceController.java b/src/main/java/ru/ulstu/is/sbapp/database/util/error/AdviceController.java new file mode 100644 index 0000000..69450bb --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/database/util/error/AdviceController.java @@ -0,0 +1,42 @@ +package ru.ulstu.is.sbapp.database.util.error; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import ru.ulstu.is.sbapp.database.service.AlbumNotFoundException; +import ru.ulstu.is.sbapp.database.service.ArtistNotFoundException; +import ru.ulstu.is.sbapp.database.service.SongNotFoundException; +import ru.ulstu.is.sbapp.database.util.validation.ValidationException; + +import java.util.stream.Collectors; + +@ControllerAdvice +public class AdviceController { + @ExceptionHandler({ + AlbumNotFoundException.class, + ArtistNotFoundException.class, + SongNotFoundException.class, + ValidationException.class + }) + public ResponseEntity handleException(Throwable e) { + return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleBindException(MethodArgumentNotValidException e) { + final ValidationException validationException = new ValidationException( + e.getBindingResult().getAllErrors().stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.toSet())); + return handleException(validationException); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleUnknownException(Throwable e) { + e.printStackTrace(); + return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidationException.java b/src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidationException.java new file mode 100644 index 0000000..16871de --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidationException.java @@ -0,0 +1,9 @@ +package ru.ulstu.is.sbapp.database.util.validation; + +import java.util.Set; + +public class ValidationException extends RuntimeException { + public ValidationException(Set errors) { + super(String.join("\n", errors)); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidatorUtil.java b/src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidatorUtil.java new file mode 100644 index 0000000..8baf8d0 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/database/util/validation/ValidatorUtil.java @@ -0,0 +1,30 @@ +package ru.ulstu.is.sbapp.database.util.validation; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.springframework.stereotype.Component; + +import java.util.Set; +import java.util.stream.Collectors; + +@Component +public class ValidatorUtil { + private final Validator validator; + + public ValidatorUtil() { + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + this.validator = factory.getValidator(); + } + } + + public void validate(T object) { + final Set> errors = validator.validate(object); + if (!errors.isEmpty()) { + throw new ValidationException(errors.stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.toSet())); + } + } +}