Исследование подходов построения микросервисной архитектуры на примере создания музыкального стримингового приложения

Компоненты микросервисной архитектуры, её отличия от монолитной. Определение подходов коммуникации в микросервисах. Проектирование музыкального стримингового приложения как практическая реализация концепции микросервисной архитектуры и ее функционала.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 10.12.2019
Размер файла 2,5 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Рисунок 6 - Страница альбома

На странице альбома (см. рисунок 6) представлена информация об альбоме и композициях, включенных в данный альбом. Для воспроизведения композиции достаточно навести курсор мыши на номер композиции и нажать на появившийся значок воспроизведения. В специальном поле можно оставить свой комментарий, который будет следовать вслед за ранее размещенными. Размер одного комментария составляет от 1 до 256 символов.

При переходе в историю пользователя (страница «History») открывается список альбомов, к которым обращался пользователь для прослушивания (см. рисунок 7).

Рисунок 7 - История прослушанных альбомов

С данной страницы также доступен переход к списку лайков, поставленных пользователем, и оставленных им комментариев к альбомам.

Для перехода на страницу альбома достаточно щелкнуть клавишей мыши на его логотип или имя, а для перехода на страницу исполнителя, включенного в альбом, к которому обращался пользователь, выбрать наименование исполнителя и щелкнуть по нему клавишей мыши.

Страница наиболее популярных исполнителей и альбомов, отсортированных по времени, выглядит следующим образом (см. рисунок 8).

Рисунок 8- Страница наиболее популярных исполнителей и альбомов, отсортированных по времени их загрузки

На данной странице представлены исполнители и альбомы, отсортированные по времени их загрузки на данный сервис. Максимальное количество размещенных на странице исполнителей и альбомов - десять единиц.

Страница управления исполнителями состоит из списка исполнителей, кнопок создания и удаления. Удалять можно сразу несколько исполнителей (см. рисунок 9).

Рисунок 9 - Страница управления исполнителями

При нажатии на кнопку добавления или на самого исполнителя появляется всплывающее окно (pop-up), в котором можно создавать или редактировать конкретного исполнителя (см рисунок 10).

Рисунок 10 - Окно создания и редактирования на странице управления исполнителями

При нажатии на кнопку перехода на страницу управления альбомами появляется список созданных альбомов, которые относятся к данному исполнителю, а также кнопки создания и удаления альбомов. Удалять можно сразу несколько альбомов.

При нажатии на кнопку создания альбома или на один из созданных альбомов появляется всплывающее окно (pop-up), в котором можно создавать или редактировать выбранный альбом (см. рисунок 11).

Рисунок 11 - Окно создания и редактирования на странице управления альбомами

Рисунок 12 - Всплывающее окно (pop-up) для редактирования имени пользователя

Редактирование имени пользователя осуществляется в специально предназначенном для этого вплывающем окне (см. рисунок 12).

функционал микросервисный архитектура музыкальный стриминговый

Заключение

Данная работа посвящена рассмотрению основной концепции микросервисной архитектуры при детальном разборе её компонентов. В ходе работы были изучены основные элементы архитектуры, проведено её краткое сравнение с монолитной архитектурой, недостатки которой способствовали появлению микросервисов. При написании работы использованы статьи и научные труды практических архитекторов и разработчиков программного обеспечения, специализирующих на изучении практических аспектов использования различных архитектурных стилей построения приложений.

Для демонстрации практического применения архитектурного стиля микросервисов было создано музыкальное стриминговое приложение, программно-аппаратная часть которого построена на основе микросервисной архитектуры. Данное приложение позволяет его пользователю прослушивать полюбившуюся музыку, которая была загружена им самим, либо другими пользователями, редактировать исполнителей, альбомы и композиции.

С теоретической точки зрения настоящая работа будет способствовать систематизации знаний в области микросервисной архитектуры, а результаты её практической части послужат дальнейшей популяризации архитектурного стиля микросервисов как стиля, несущего в себе целый ряд технических преимуществ и показавшего себя как надежная основа при разработке различных веб-приложений.

Список использованной литературы

1. Bhatia, Siddhartha. Enterprise Approaches to Microservices: Choose Yours

Wisely. 2017

2. Fowler Martin, Lewis James. Microservices, a definition of this new architectural term.2014.

3. Newman, Sam. Building Microservices. Sebastopol, California: O'Reilly Media, 2015. -- 280 p. -- ISBN-13: 978-1491950357.

4. Richardson Chris. What are microservices? 2018.

5. Richardson Chris. Pattern: Shared database//A pattern language for microservices.2018

6. Anatomy of an HTTP Transaction.

7. Angular.

8. AWS Blog & Podcast

9. Netflix Open Source

10. RabbitMQ

11. Spotify

12. Spring Cloud

13. Spring Cloud Gateway

14. Spring WebFlux.

15. TIDEL

16. YouTubeMusic

Приложение

Artist.java

@Document(collection = "artist")

public class Artist {

@Id

private UUID id;

@Indexed(name = "name", direction = IndexDirection.DESCENDING)

private String name;

private String description;

private Date date;

@Indexed(name = "url", unique = true, direction =

IndexDirection.DESCENDING)

private String url;

private String location;

private UUID userId;

private Map<String, String> links;

}

Album.java

@Document(collection = "album")

public class Album {

@Id

private UUID id;

@Indexed(name = "artistId", direction = IndexDirection.DESCENDING)

private UUID idOfArtist;

@Indexed(name = "name", direction = IndexDirection.DESCENDING)

private String name;

@Indexed(name = "date", direction = IndexDirection.DESCENDING)

private Date date;

@Indexed(name = "genre", direction = IndexDirection.DESCENDING)

private List<String> genre;

}

Prediction.java

@Document(collection = "prediction")

public class Prediction {

@Id

private UUID id;

@Indexed

private UUID userId;

@Indexed(unique = true)

private String genre;

private long numberOfListenings;

}

Song.java

@Document(collection = "song")

public class Song {

@Id

private UUID id;

@Indexed(name = "albumId")

private UUID albumId;

@Indexed(name = "name")

private String name;

}

User.java

@Document(collection = "user")

public class User {

@Id

private UUID id;

@Indexed(name = "name", unique = true)

private String name;

private Date date;

private Date lastActivity;

private String password;

}

Like.java

@Document(collection = "like")

public class Like {

@Id

private UUID id;

@Indexed

private UUID albumId;

@Indexed

private UUID userId;

}

FileContrainer.java

public class FileContainer {

private UUID id;

private FilePart file;

}

History Element.java

@Document("history-element")

public class HistoryElement {

@Id

private UUID id;

@Indexed

private UUID userId;

@Indexed

private UUID albumId;

}

Comment.java

@Document("comment")

public class Comment {

@Id

private UUID id;

@Indexed(name = "userId")

private UUID userId;

@Indexed(name = "albumId")

private UUID albumId;

private String message;

}

ArtistCotnroller.java

@RestController

@RequestMapping("artist")

public class ArtistController {

@Autowired

@Qualifier("create")

private ValidationService createValidationService;

@Autowired

@Qualifier("edit")

private ValidationService editValidationService;

@Autowired

private ArtistCommandExecutorService artistCommandExecutorService;

@PostMapping

public Mono<ResponseEntity<ArtistResponse>>

createArtist(@RequestBody Mono<ArtistDTO> artistCommand) {

return artistCommand.subscribeOn(Schedulers.elastic())

.flatMap(artist -> createValidationService.validate(artist))

.flatMap(artist -> {

List<Pair<Field, ErrorCode>> result = artist.getErrors();

if (result != null && !result.isEmpty()) {

return

Mono.just(ResponseEntity.badRequest().body(generateErrorValidationResp

onse(result.get(0))));

} else {

return

artistCommandExecutorService.executeCreateCommand(artist.getArtistD

TO())

.flatMap(artistDTO ->

Mono.just(ResponseEntity.ok(generateCompletedResponse(artistDTO))));

}

})

.onErrorResume(ExecutingException.class, errorResult ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR)

.body(generateErrorExecutionResponse(errorResult))))

.onErrorResume(RuntimeException.class, errorResult ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR)

.body(generateErrorRuntimeResponse(errorResult))));

}

@PutMapping

public Mono<ResponseEntity<ArtistResponse>> editArtist(@RequestBody

Mono<ArtistDTO> artistCommand) {

return artistCommand.subscribeOn(Schedulers.elastic())

.flatMap(artist -> editValidationService.validate(artist))

.flatMap(artist -> {

Pair<Field, ErrorCode> result = artist.getErrors().get(0);

if (result != null) {

return

Mono.just(ResponseEntity.badRequest().body(generateErrorValidationResp

onse(result)));

} else {

return

artistCommandExecutorService.executeEditCommand(artist.getArtistDT

O())

.flatMap(artistDTO ->

Mono.just(ResponseEntity.ok(generateCompletedResponse(artistDTO))));

}

})

.onErrorResume(ExecutingException.class, errorResult ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR)

.body(generateErrorExecutionResponse(errorResult))))

.onErrorResume(RuntimeException.class, errorResult ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR)

.body(generateErrorRuntimeResponse(errorResult))));

}

@DeleteMapping("/{id}")

public Mono<ResponseEntity<ArtistResponse>>

deleteArtist(@PathVariable UUID id) {

return Mono.just(id)

.flatMap(artistId -> Mono.defer(() ->

artistCommandExecutorService.executeDeleteCommand(artistId)))

.flatMap(result -> Mono.defer(() -> {

ArtistResponse response = new ArtistResponse();

ArtistDTO artistDTO = new ArtistDTO();

artistDTO.setId(result);

response.setCommand(artistDTO);

return Mono.just(ResponseEntity.status(HttpStatus.OK).body(response));

}))

.onErrorResume(ExecutingException.class, error ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR)

.body(generateErrorExecutionResponse(error))))

.onErrorResume(RuntimeException.class, error ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR)

.body(generateErrorRuntimeResponse(error))));

}

private static ArtistResponse generateCompletedResponse(ArtistDTO

artistDTO) {

ArtistResponse artistResponse = new ArtistResponse();

artistResponse.setCommand(artistDTO);

return artistResponse;

}

private static ArtistResponse generateErrorValidationResponse(Pair<Field,

ErrorCode> error) {

ArtistResponse errorResponse = new ArtistResponse();

if (error != null) {

errorResponse.setCode(error.getSecond());

errorResponse.setParameters(Collections.singletonMap(ErrorParameters.FI

ELD,

error.getFirst().toString()));

}

errorResponse.setErrorType(ErrorType.VALIDATION);

return errorResponse;

}

private static ArtistResponse

generateErrorExecutionResponse(ExecutingException ex) {

ArtistResponse errorResponse = new ArtistResponse();

errorResponse.setErrorType(ex.getErrorType());

return errorResponse;

}

private static ArtistResponse

generateErrorRuntimeResponse(RuntimeException ex) {

ArtistResponse errorResponse = new ArtistResponse();

errorResponse.setErrorType(ErrorType.EXECUTING);

return errorResponse;

}

private static ResponseEntity<ArtistResponse>

generateNotFoundResponse() {

ArtistResponse errorResponse = new ArtistResponse();

errorResponse.setErrorType(ErrorType.EXECUTING);

errorResponse.setCode(ErrorCode.EXECUTING);

return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);

}

}

ArtistQueryController.java

@RestController

@RequestMapping("artist")

public class ArtistQueryController {

@Autowired

private QueryService queryService;

("{id}")

public Mono<ResponseEntity<ArtistSearchResultDTO>>

getArtistById(@PathVariable UUID id) {

return queryService.getById(id)

.flatMap(artist -> Mono.defer(() -> Mono.just(ResponseEntity

.ok()

.body(artist))))

.defaultIfEmpty(ResponseEntity.notFound().build());

}

@GetMapping("name/{name}")

public Flux<ArtistSearchResultDTO> getAllByName(@PathVariable

String name) {

return queryService.getAllByName(name);

}

@GetMapping("url/{url}")

public Mono<ResponseEntity<ArtistSearchResultDTO>>

getAllByUrl(@PathVariable String url) {

return queryService.getByUrl(url)

.flatMap(artist -> Mono.defer(() -> Mono.just(ResponseEntity

.ok()

.body(artist))))

.defaultIfEmpty(ResponseEntity.notFound().build());

}

@GetMapping("all")

public Flux<ArtistSearchResultDTO> getAll() {

return queryService.getAll();

}

}

InternalArtistController.java

@RestController

@RequestMapping("internal/artist")

public class InternalArtistController {

@Autowired

private SearchService searchService;

private final QueryService queryService;

public InternalArtistController(QueryService queryService) {

this.queryService = queryService;

}

@GetMapping("{id}")

public Mono<Boolean> existsArtistById(@PathVariable UUID id) {

return queryService.existsArtistById(id);

}

}

AlbumController.java

@RestController

@RequestMapping("album")

public class AlbumController {

@Autowired

private AlbumService albumService;

@Autowired

@Qualifier("create")

private ValidationService validationCreateService;

@Autowired

@Qualifier("edit")

private ValidationService validationEditService;

private static final Function<RuntimeException, ? extends

Mono<ResponseEntity<AlbumResponse>>> ERROR_HANDLER = error

-> Mono.defer( () -> {

AlbumResponse albumResponse = new AlbumResponse();

albumResponse.setErrorType(ErrorType.EXECUTING);

albumResponse.setParameters(Collections.singletonMap(ErrorParameters.M

ESSAGE, error.getMessage()));

return

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(albumResponse));

});

@PostMapping

public Mono<ResponseEntity<AlbumResponse>>

efer(() -> validationCreateService.validate(albumDTO)))

.flatMap(validationResult -> Mono.defer(() ->

albumService.create(validationResult.getAlbumDTO())

.flatMap(result -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateAlbumResponse(result)))))))

.onErrorResume(RuntimeException.class, ERROR_HANDLER);

}

@PutMapping

public Mono<ResponseEntity<AlbumResponse>>

editArtist(@RequestBody Mono<AlbumDTO> album) {

return album

.flatMap(albumDTO -> Mono.defer(() ->

validationEditService.validate(albumDTO)))

.flatMap(validationResult -> Mono.defer(() ->

albumService.edit(validationResult.getAlbumDTO())

.flatMap(result -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateAlbumResponse(result)))))))

.onErrorResume(RuntimeException.class, ERROR_HANDLER);

}

@DeleteMapping("{id}")

public Mono<ResponseEntity<AlbumResponse>>

deleteArtist(@PathVariable UUID id) {

return Mono.just(id)

.flatMap(albumId -> Mono.defer(() -> albumService.delete(albumId)

.flatMap(result -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateAlbumResponseById(result)))))))

.onErrorResume(RuntimeException.class, ERROR_HANDLER);

}

private static AlbumResponse generateAlbumResponse(AlbumDTO

albumDTO) {

AlbumResponse albumResponse = new AlbumResponse();

albumResponse.setAlbumDTO(albumDTO);

return albumResponse;

}

private static AlbumResponse generateAlbumResponseById(UUID id) {

AlbumResponse albumResponse = new AlbumResponse();

AlbumDTO albumDTO = new AlbumDTO();

albumDTO.setId(id);

albumResponse.setAlbumDTO(albumDTO);

return albumResponse;

}

}

AlbumQueryController.java

@RestController

@RequestMapping("album")

public class AlbumQueryController {

@Autowired

private QueryService queryService;

@GetMapping("{id}")

public Mono<AlbumDTO> getById(@PathVariable UUID id) {

return queryService.getById(id);

}

@GetMapping("name/{name}")

public Flux<AlbumDTO> getAllByName(@PathVariable String name) {

return queryService.getAllByName(name);

}

@GetMapping("artist/{id}")

public Flux<AlbumDTO> getAllByName(@PathVariable UUID id) {

roller.java

@RestController

@RequestMapping("internal/album")

public class AlbumInternalController {

Mono<Boolean> existsById(@PathVariable UUID id) {

return albumExternalService.existsAlbumById(id);

}

@GetMapping("ids")

public Flux<AlbumDTO> getAlbumsByIds(@RequestParam("ids")

List<UUID> ids) {

if (ids.isEmpty()) {

return Flux.empty();

}

return albumExternalService.getAlbumsByIds(ids);

}

@GetMapping("genre")

public Flux<AlbumDTO> getAlbumsByGenre(@RequestParam(required =

false) String genre) {

return genre != null ? albumExternalService.getAlbumsByGenre(genre) :

albumExternalService.getAlbumsRandom();

}

}

SongController.java

@RestController

@RequestMapping("song")

public class SongController {

@Autowired

private SongService songService;

@Autowired

@Qualifier("create")

private ValidationService validationCreateService;

@Autowired

@Qualifier("edit")

private ValidationService validationEditService;

@PostMapping

public Mono<ResponseEntity<SongResponse>>

createSong(@RequestBody Mono<SongDTO> songDTO) {

return songDTO

.subscribeOn(Schedulers.elastic())

.flatMap(song -> Mono.defer(() ->

validationCreateService.validate(song)))

.flatMap(result -> Mono.defer(() -> {

List<Pair<Field, ErrorCode>> errors = result.getErrors();

if (!errors.isEmpty()) {

return

Mono.just(ResponseEntity.badRequest().body(generateErrorResponse(errors

)));

} else {

return songService.create(result.getSong())

.flatMap(song -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateSongResponse(song)))));

}

}))

.onErrorResume(RuntimeException.class,

error ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateInternalError(error))));

}

@PutMapping

public Mono<ResponseEntity<SongResponse>> editSong(@RequestBody

Mono<SongDTO> songDTO) {

return songDTO

.subscribeOn(Schedulers.elastic())

.flatMap(song -> Mono.defer(() -> validationEditService.validate(song)))

.flatMap(result -> Mono.defer(() -> {

List<Pair<Field, ErrorCode>> errors = result.getErrors();

if (!errors.isEmpty()) {

return

Mono.just(ResponseEntity.badRequest().body(generateErrorResponse(errors

turn songService.create(result.getSong())

.flatMap(song -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateSongResponse(song)))));

}

}))

.onErrorResume(RuntimeException.class,

error ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateInternalError(error))));

}

@DeleteMapping("{id}")

public Mono<ResponseEntity<SongResponse>>

deleteSong(@PathVariable UUID id) {

return songService.delete(id)

.flatMap(result -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateSongResponseWithId(result)))))

.onErrorResume(RuntimeException.class,

error ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateInternalError(error))));

}

private static SongResponse generateSongResponse(SongDTO song) {

SongResponse songResponse = new SongResponse();

songResponse.setSong(song);

return songResponse;

}

private static SongResponse generateSongResponseWithId(UUID id) {

SongResponse songResponse = new SongResponse();

SongDTO songDTO = new SongDTO();

songDTO.setId(id);

songResponse.setSong(songDTO);

return songResponse;

}

private static SongResponse generateInternalError(RuntimeException ex) {

SongResponse songResponse = new SongResponse();

songResponse.setErrorType(ErrorType.EXECUTING);

songResponse.setErrorCode(ErrorCode.EXECUTING);

songResponse.setParams(Collections.singletonMap(ErrorParameters.MESS

AGE, ex.getMessage()));

return songResponse;

}

private static SongResponse generateErrorResponse(List<Pair<Field,

ErrorCode>> errors) {

SongResponse songResponse = new SongResponse();

Pair<Field, ErrorCode> error = errors.get(0);

songResponse.setErrorCode(error.getSecond());

songResponse.setParams(Collections.singletonMap(ErrorParameters.FIELD

, error.getFirst().toString()));

songResponse.setErrorType(ErrorType.VALIDATION);

return songResponse;

}

}

SongQueryController.java

@RestController

@RequestMapping("song")

public class SongQueryController {

@Autowired

private SongQueryService songQueryService;

@GetMapping("{id}")

public Mono<SongDTO> getById(@PathVariable UUID id) {

return songQueryService.getById(id);

}

@GetMapping("album/{id}")

public Flux<SongDTO> getAllByAlbumId(@PathVariable UUID id) {

return songQueryService.getAllByAlbumId(id);

}

@GetMapping("name/{name}")

public Flux<SongDTO> getAllByName(@PathVariable String name) {

return songQueryService.getAllByName(name);

}

}

SongInternalController.java

@RestController

class SongInternalController {

@Autowired

private InternalQueryService internalQueryService;

@GetMapping("{id}")

public Mono<Boolean> existsById(@PathVariable UUID id) {

return internalQueryService.existsSongById(id);

}

}

UserController.java

@RestController

@RequestMapping("user")

public class UserController {

@Autowired

private UserService userService;

@Autowired

@Qualifier("create")

private UserValidationService userValidationCreateService;

@Autowired

@Qualifier("edit")

private UserValidationService userValidationEditService;

@PutMapping

public Mono<ResponseEntity<UserResponse>> editUser(@RequestBody

Mono<UserDTO> userDTO) {

return userDTO

.subscribeOn(Schedulers.elastic())

.flatMap(user -> Mono.defer(() ->

userValidationEditService.validate(user)))

.flatMap(result -> Mono.defer(() -> {

List<Pair<Field, ErrorCode>> errors = result.getErrors();

if (errors != null && !errors.isEmpty()) {

return

Mono.just(ResponseEntity.badRequest().body(generateValidationErrorResp

onse(errors)));

} else {

return

userService.edit(result.getUserDTO()).subscribeOn(Schedulers.elastic())

.flatMap(user -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateUserResponse(user)))));

}

}))

.onErrorResume(RuntimeException.class,

error -> Mono.defer(() ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateErrorResponse(error)))));

}

@DeleteMapping("{id}")

public Mono<ResponseEntity<UserResponse>> deleteUser(@PathVariable

UUID id) {

return userService.delete(id)

.subscribeOn(Schedulers.elastic())

.flatMap(result -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateUserResponseWithId(result)))))

.onErrorResume(RuntimeException.class,

error -> Mono.defer(() ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateErrorResponse(error)))));

}

private static UserResponse generateUserResponse(UserDTO userDTO) {

UserResponse userResponse = new UserResponse();

userResponse.setUser(userDTO);

return userResponse;

}

private static UserResponse generateUserResponseWithId(UUID id) {

UserResponse userResponse = new UserResponse();

UserDTO userDTO = new UserDTO();

userDTO.setId(id);

userResponse.setUser(userDTO);

return userResponse;

}

private static UserResponse

generateValidationErrorResponse(List<Pair<Field, ErrorCode>> errors) {

UserResponse userResponse = new UserResponse();

Pair<Field, ErrorCode> error = errors.get(0);

userResponse.setCode(error.getSecond());

userResponse.setErrorType(ErrorType.VALIDATION);

userResponse.setParameters(Collections.singletonMap(ErrorParameters.FIE

LD, error.getFirst().toString()));

return userResponse;

}

private static UserResponse generateErrorResponse(Exception ex) {

UserResponse userResponse = new UserResponse();

userResponse.setErrorType(ErrorType.EXECUTING);

userResponse.setParameters(Collections.singletonMap(ErrorParameters.ME

SSAGE, ex.getMessage()));

return userResponse;

}

}

UserQueryController.java

@RestController

@RequestMapping("user")

public class UserQueryController {

@Autowired

private QueryService queryService;

@GetMapping("{id}")

public Mono<UserDTO> getUserById(@PathVariable UUID id) {

return queryService.getUserById(id);

}

@GetMapping("name/{name}")

public Mono<UserDTO> getUserByName(@PathVariable String name) {

return queryService.getUserByName(name);

}

@PostMapping

public Mono<ResponseEntity<UserResponse>> createUser(@RequestBody

Mono<UserDTO> userDTO) {

return userDTO

.subscribeOn(Schedulers.elastic())

.flatMap(user -> Mono.defer(() ->

userValidationCreateService.validate(user)))

.flatMap(result -> Mono.defer(() -> {

List<Pair<Field, ErrorCode>> errors = result.getErrors();

if (errors != null && !errors.isEmpty()) {

return

Mono.just(ResponseEntity.badRequest().body(generateValidationErrorResp

onse(errors)));

} else {

return

internalService.create(result.getUserDTO()).subscribeOn(Schedulers.elastic

())

.flatMap(user -> Mono.defer(() ->

Mono.just(ResponseEntity.ok(generateUserResponse(user)))));

}

}))

.onErrorResume(RuntimeException.class,

error -> Mono.defer(() ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateErrorResponse(error)))));

}

}

}

InternalController.java

@RestController

@RequestMapping("internal/user")

public class InternalController {

@Autowired

private InternalService internalService;

@GetMapping("{id}")

public Mono<Boolean> userExistsById(@PathVariable UUID id) {

return internalService.userExistsById(id);

}

}

LikeController.java

@RestController

@RequestMapping("like")

public class LikeController {

private final ValidationService validationService;

private final LikeService likeService;

public LikeController(ValidationService validationService, LikeService

likeService) {

this.validationService = validationService;

this.likeService = likeService;

}

@PostMapping

public Mono<ResponseEntity<LikeResponse>> addLike(@RequestBody

Mono<LikeDTO> likeDTO) {

return likeDTO

.subscribeOn(Schedulers.elastic())

.flatMap(validationService::validate)

.flatMap(result -> {

if (result.isValid()) {

return likeService.addLike(result.getLikeDTO())

.map(LikeController::generateLikeResponse)

.map(ResponseEntity::ok);

}

return

Mono.just(ResponseEntity.badRequest().body(generateValidationErrorLike

Response(result.getErrors())));

})

.onErrorResume(error ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateErrorResponse(error))));

}

@DeleteMapping("{id}")

public Mono<Void> deleteLike(@PathVariable UUID id) {

return likeService.deleteLikeById(id);

}

private static LikeResponse generateLikeResponse(LikeDTO likeDTO) {

LikeResponse likeResponse = new LikeResponse();

likeResponse.setLikeDTO(likeDTO);

return likeResponse;

}

private static LikeResponse

generateValidationErrorLikeResponse(List<String> errors) {

LikeResponse likeResponse = new LikeResponse();

LikeError likeError = new LikeError();

likeError.setType(ErrorType.VALIDATION);

likeError.setError(errors.stream().collect(Collectors.toMap(o -> "FIELD",

o -> o)));

likeResponse.setError(likeError);

return likeResponse;

}

private static LikeResponse generateErrorResponse(Throwable exception)

{

LikeResponse likeResponse = new LikeResponse();

LikeError likeError = new LikeError();

likeError.setType(ErrorType.EXECUTION);

likeError.setError(Collections.singletonMap("MESSAGE",

exception.getMessage()));

likeResponse.setError(likeError);

return likeResponse;

}

}

LikeQueryController.java

@RestController

private LikeQueryService likeQueryService;

@GetMapping("user/{id}")

public Flux<LikeDTO> getLikesByUserId(@PathVariable UUID id) {

return likeQueryService.getLikesByUserId(id);

}

@GetMapping("album/{id}/count")

public Mono<Long> getCountOfLikesByAlbumId(@PathVariable UUID

id) {

return likeQueryService.countLikesByAlbumId(id);

}

@GetMapping("album/{id}")

public Flux<LikeDTO> getLikesByAlbumId(@PathVariable UUID id) {

return likeQueryService.getLikesByAlbumId(id);

}

@GetMapping("top")

public Flux<UUID> getTop() {

return likeQueryService.getTop();

}

}

HistoryController.java

@RestController

@RequestMapping("history")

public class HistoryController {

@Autowired

private HistoryService historyService;

@Autowired

private HistoryQueryService historyQueryService;

@PostMapping

public Mono<Void> addHistory(@RequestBody HistoryElementDTO

historyElementDTOMono) {

return historyService.addHistory(historyElementDTOMono);

}

@GetMapping("user/{id}")

public Flux<HistoryElementDTO> getHistoryOfUserById(@PathVariable

UUID id) {

return historyQueryService.getAllHistoryByUserId(id);

@RequestMapping("comment")

public class CommentController {

@Autowired

private CommentService commentService;

@Autowired

private UserAdapterService userAdapterService;

@PostMapping

public Mono<ResponseEntity<CommentResponse>>

create(@RequestBody Mono<CommentDTO> comment) {

return comment

.subscribeOn(Schedulers.elastic())

.flatMap(result -> Mono.defer(() ->

userAdapterService.userExistsById(result)))

.flatMap(result -> Mono.defer(() -> {

if (result.getUserExistence()) {

return commentService.create(result.getComment())

.flatMap(commentDTO -> Mono.defer(() -> {

CommentResponse commentResponse = new CommentResponse();

commentResponse.setComment(commentDTO);

return Mono.just(ResponseEntity.ok(commentResponse));

}));

} else {

return

Mono.just(ResponseEntity.badRequest().body(generateValidationErrorResp

onse(result.getComment().getUserId())));

}

}))

.onErrorResume(RuntimeException.class,

error -> Mono.defer(() ->

Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERR

OR).body(generateErrorResponse(error)))));

}

@DeleteMapping("{id}")

public Mono<Void> delete(@PathVariable UUID id) {

return commentService.deleteById(id);

}

private static CommentResponse generateValidationErrorResponse(UUID

id) {

CommentResponse commentResponse = new CommentResponse();

commentResponse.setCode(ErrorCode.REFERENCE_ERROR);

commentResponse.setErrorType(ErrorType.VALIDATION);

commentResponse.setParameters(Collections.singletonMap(ErrorParameter

s.FIELD, "userId"));

return commentResponse;

}

private static CommentResponse generateErrorResponse(Exception ex) {

CommentResponse commentResponse = new CommentResponse();

commentResponse.setErrorType(ErrorType.EXECUTING);

commentResponse.setParameters(Collections.singletonMap(ErrorParameter

s.MESSAGE, ex.getMessage()));

return commentResponse;

}

}

Основной контроллер для получения сущностей комментариев

(Comment):

CommentQueryController.java

@RestController

@RequestMapping("comment")

public class CommentQueryController {

private final CommentService commentService;

@GetMapping("album/{id}")

public Flux<CommentDTO> getCommentsByAlbumId(@PathVariable

UUID albumId) {

return Flux.interval(Duration.ofMillis(500))

.flatMap(element ->

commentService.getAllCommentsByAlbumId(albumId));

}

@GetMapping("user/{id}")

public Flux<CommentDTO> getCommentsByUserId(@PathVariable UUID

userId) {

return Flux.interval(Duration.ofMillis(500))

.flatMap(element -> commentService.getByUserId(userId));

}

}

ImageController.java

@RestController

@RequestMapping("image")

public class ImageController {

@Autowired

@Qualifier("artist")

private FileUploadService fileUploadArtistService;

@Autowired

@Qualifier("album")

private FileUploadService fileUploadAlbumService;

@Autowired

private ImageService imageService;

@PostMapping(value = "artist/{id}", consumes =

MediaType.MULTIPART_FORM_DATA_VALUE)

public Mono<Void> uploadArtistHandler(@PathVariable UUID id,

@RequestPart Mono<FilePart> file) {

return uploadFile(id, file)

.flatMap(fileContainer -> Mono.defer(() ->

fileUploadArtistService.saveFile(fileContainer)));

}

@PostMapping(value = "album/{id}",

consumes = MediaType.MULTIPART_FORM_DATA_VALUE,

produces = MediaType.APPLICATION_STREAM_JSON_VALUE)

") UUID id, @RequestPart("file") Mono<FilePart> file) {

return uploadFile(id, file)

.flatMap(fileContainer ->

fileUploadAlbumService.saveFile(fileContainer));

}

@GetMapping(value = "artist/{id}",

produces = MediaType.MULTIPART_FORM_DATA_VALUE)

public Flux<byte[]> getArtistHandler(@PathVariable("id") UUID id) {

return imageService.downloadArtistImage(id);

}

@GetMapping(value = "album/{id}",

produces = MediaType.MULTIPART_FORM_DATA_VALUE)

public Flux<byte[]> getAlbumHandler(@PathVariable("id") UUID id) {

return imageService.downloadAlbumImage(id);

}

private Mono<FileContainer> uploadFile(UUID id, Mono<FilePart> file) {

return file

ilePart -> Mono.defer(() -> Mono.create(result -> {

FileContainer fileContainer = new FileContainer();

fileContainer.setId(id);

fileContainer.setFile(filePart);

result.success(fileContainer);

})));

}

}

MusicController.java

@RestController

@RequestMapping("music")

public class MusicController {

@Autowired

private FileService fileService;

@PostMapping(value = "{id}", consumes =

MediaType.MULTIPART_FORM_DATA_VALUE)

public Mono<Void> uploadArtistHandler(@PathVariable UUID id,

@RequestBody Flux<Part> parts) {

return parts

.filter(part -> part instanceof FilePart)

.ofType(FilePart.class)

.map(filePart -> new FileContainer(id, filePart))

.flatMap(fileContainer -> fileService.saveFile(fileContainer))

.then();

}

@GetMapping(value = "{id}", produces =

MediaType.MULTIPART_FORM_DATA_VALUE)

public Flux<byte[]> uploadArtistHandler(@PathVariable UUID id) {

return fileService.downloadFile(id);

}

}

app-routing.module.ts

import {NgModule} from '@angular/core';

import {Routes, RouterModule} from '@angular/router';

import {WelcomePageComponent} from './welcome-page/welcome-

page/welcome-page.component';

import {MainPageComponent} from './main-page/main-page/main-

page.component';

import {HomePageComponent} from './main-page/home-page/home-

page.component';

import {ArtistPageComponent} from "./main-page/artist-page/artist-

page.component";

import {AlbumPageModule} from "./main-page/album-page/album-

page.module";

import {WelcomePageModule} from "./welcome-page/welcome-

page.module";

import {MainPageModule} from "./main-page/main-page.module";

import {ArtistPageModule} from "./main-page/artist-page/artist-

page.module";

import {AlbumPageComponent} from "./main-page/album-page/album-

page.component";

import {TopPageComponent} from "./main-page/top-page/top-

page.component";

import {HistoryComponent} from "./main-page/history/history.component";

import {HistoryModule} from "./main-page/history/history.module";

import {ArtistLabComponent} from "./main-page/artist-lab/artist-

lab.component";

import {ArtistLabModule} from "./main-page/artist-lab/artist-lab.module";

import {AlbumLabComponent} from "./main-page/artist-lab/album-

lab/album-lab.component";

import {AlbumLabModule} from "./main-page/artist-lab/album-lab/album-

lab.module";

const routes: Routes = [

{path: '', redirectTo: '/welcome', pathMatch: 'full'},

{path: 'welcome', component: WelcomePageComponent},

{

path: 'home', component: MainPageComponent, children: [

{path: 'artist/:id', component: ArtistPageComponent},

{path: 'album/:id', component: AlbumPageComponent},

{path: 'top', component: TopPageComponent},

{path: 'history', component: HistoryComponent},

{path: 'user/artist/:id', component: ArtistLabComponent},

{path: 'user/artist/:id/album', component: AlbumLabComponent},

{

path: '', component: HomePageComponent

}

]

}

];

@NgModule({

imports: [RouterModule.forRoot(routes),

WelcomePageModule,

MainPageModule,

ArtistPageModule,

AlbumPageModule,

HistoryModule,

ArtistLabModule,

AlbumLabModule

],

exports: [RouterModule]

})

export class AppRoutingModule {

}

comment.component.ts

@Component({

selector: 'app-history-comment',

templateUrl: './comment.component.html',

styleUrls: ['./comment.component.css']})

export class CommentComponent implements OnInit {

displayedColumns: string[] = ['picture', 'name', 'comment'];

dataSource = ELEMENT_DATA;

expandedElement: CommentHistoryElement | null;

constructor() { }

ngOnInit() {

}

changeComment(comment: string): string[] {

let result = new Array<string>();

if (comment.length <= limitOfCommentLine) {

result.push(comment);

return result;

}

const length = result.length + limitOfCommentLine;

for (let i = 0; i <= length; i += limitOfCommentLine) {

result.push(comment.substr(i, limitOfCommentLine).split('').filter(letter => letter).join(''));

}

return result;

}

}

artist-edit.component.ts

@Component({

selector: 'app-artist-edit',

templateUrl: './artist-edit.component.html',

styleUrls: ['./artist-edit.component.css']

})

export class ArtistEditComponent implements OnInit {

@Input() artist: ArtistLabElement;

isEdit: boolean;

@Inject(MAT_DIALOG_DATA) public dataArtist: ArtistLabModel) {

this.artist = dataArtist.artist;

this.isEdit = dataArtist.type === LabType.edit;

}

ngOnInit() {

}

save() {

this.close();

}

cancel() {

this.close();

}

private close() {

this.dialogRef.close();

}

}

artist-request-service.service.ts

@Injectable({

providedIn: 'root'

})

export class ArtistRequestServiceService{

private readonly ARTIST_GET_BY_ID_URL: string;

private readonly ARTIST_GET_TOP_URL: string;

constructor(private http: HttpClient) {

this.ARTIST_GET_BY_ID_URL = environment.url +

ARTIST_GET_BY_ID;

this.ARTIST_GET_TOP_URL = environment.url +

ARTIST_GET_BY_TOP;

}

getArtistById(id: string): Observable<Artist> {

const url = this.ARTIST_GET_BY_ID_URL + id;

return this.http.get<Artist>(url);

}

getArtistTopByLikes(): Observable<Artist[]> {

return this.http.get<Artist[]>(this.ARTIST_GET_TOP_URL);

}

}

album-request-service.service.ts

@Injectable({

providedIn: 'root'

})

export class AlbumRequestServiceService {

private readonly ALBUM_GET_BY_ID_URL: string;

private readonly ALBUM_GET_TOP_URL: string;

constructor(private http: HttpClient) {

this.ALBUM_GET_BY_ID_URL = environment.url +

ALBUM_GET_BY_ID;

this.ALBUM_GET_TOP_URL = environment.url +

ALBUM_GET_BY_TOP;

}

getAlbumById(id: string): Observable<Album> {

const url = this.ALBUM_GET_BY_ID_URL + id;

return this.http.get<Album>(url);

}

getAlbumTopByLikes(): Observable<Album[]> {

return this.http.get<Album[]>(this.ALBUM_GET_TOP_URL);

}

}

Размещено на allbest.ru

...

Подобные документы

  • Проблема управления инфраструктурой веб-приложения с микросервисной архитектурой. Тенденции к созданию программного обеспечения. Ключевые направления в разработке веб-приложений. Архитектура спроектированной системы мониторинга. Эффективность сервиса.

    статья [532,1 K], добавлен 10.12.2016

  • Выбор и обоснование аппаратного обеспечения. Типы архитектуры веб-приложений. Шаблоны проектирования архитектуры приложения. Разработка инфологической модели базы данных. Подготовка к разработке приложения. Рассмотрение причин возникновения паттернов.

    дипломная работа [3,0 M], добавлен 27.11.2022

  • Реализация web-сервиса для сбора и анализа статистических данных по тексту, а также web-приложения, поддерживающего взаимодействие с сервисом и организующего пользовательский интерфейс. Проектирование архитектуры приложения. Язык программирования C#.

    курсовая работа [417,6 K], добавлен 25.03.2015

  • Проектирование модели базы данных в соответствии с предметной областью "Торговля". Разработка архитектуры системы безопасности приложения по ведению базы данных. Реализация приложения, обеспечивающего учет продаж и закупок предприятия. Способы его защиты.

    дипломная работа [2,5 M], добавлен 05.02.2017

  • Основные концепции разработки приложения в архитектуре MVVM. Проектирование базы данных, предназначенной для сбора информации о дорожно-транспортных происшествиях. Классификация и типы архитектуры "клиент–сервер", ее основные достоинства и недостатки.

    курсовая работа [4,1 M], добавлен 25.11.2015

  • Анализ создания удобного инструмента, максимально упрощающего процесс осуществления заказа клиентом ювелирных изделий. Изучение принципов построения web-сайта, структуры базы данных, проектирования архитектуры приложения и пользовательского интерфейса.

    дипломная работа [7,0 M], добавлен 11.02.2012

  • Характеристика объекта автоматизации. Создание многоуровневой архитектуры приложения, отладка метода безошибочной идентификации пользователей системы. Разработка нестандартного метода преобразования объектов базы данных в объекты классов приложения.

    курсовая работа [395,4 K], добавлен 28.04.2015

  • Понятие архитектуры программного обеспечения (ПО). Характеристика этапов процесса проектирования и его окончательный продукт. Языки описания и виды архитектуры ПО, базовые фреймворки. Функции разработчика архитектуры ПО и необходимые ему навыки работы.

    реферат [85,0 K], добавлен 15.02.2014

  • Разработка информационной системы "Больница" на основе Java EE-технологий. Проект и реализация трехслойного enterprise-приложения, работающего с базой данных больницы, его структура. Предметная область; визуализация архитектуры с помощью UML-диаграмм.

    курсовая работа [2,0 M], добавлен 22.10.2012

  • Постановка задач и требований к проектируемому интернет-приложению. Обоснование выбора системы управления базы данных и языков программирования. Разработка архитектуры заданного интернет-приложения, технико-экономическое обоснование его эффективности.

    дипломная работа [461,3 K], добавлен 24.02.2013

  • Проблема выбора товара в Интернете. Типы и свойства онтологий как части концепции Semantic Web. Разработка web-приложения для выбора музыкального инструмента: создание иерархии онтологий для предметной области "Гитара", формирование SPARQL-запроса.

    дипломная работа [2,2 M], добавлен 20.04.2012

  • Изучение существующих подходов к использованию компьютерных игр в образовательном процессе. Разработка и реализация проекта игрового обучающего приложения на мобильной платформе. Выбор платформы и средств реализации игрового обучающего приложения.

    дипломная работа [3,4 M], добавлен 12.08.2017

  • Ознакомление с проблемами реализации сервис-ориентированной архитектуры предприятия. Анализ активных элементов бизнес-архитектуры. Рассмотрение инструментов реализации языка ArchiMate в программном средстве Archi. Исследование мотивационных концепций.

    курсовая работа [2,0 M], добавлен 25.08.2017

  • Описания программного продукта компании 1С, предназначенного для быстрой разработки прикладных решений. Исследование типов архитектур построения баз данных. Технология с сетью и файловым сервером. Анализ особенностей трехзвенной архитектуры клиент-сервер.

    курсовая работа [401,4 K], добавлен 12.01.2015

  • Обзор существующих объектных архитектур. Архитектура программного обеспечения. Создание веб-сервиса "Библиотека", предоставляющего механизмы работы с данными на стороне клиентского приложения. WEB-сервис и трехуровневая архитектура в основе приложения.

    лабораторная работа [1,5 M], добавлен 16.06.2013

  • Обзор подходов к разработке музейных приложений с элементами дополненной реальности, формирование требований к ним. Выбор методов разработки приложения, разработка пользовательского интерфейса. Принципы тестирования. Реализация раздела "Распознавание".

    дипломная работа [2,8 M], добавлен 03.07.2017

  • Изучение существующих подходов к использованию компьютерных игр в образовательном процессе. Особенности использования мобильного обучения. Методика и этапы закрепления полученных ранее знаний с использованием игрового приложения на мобильной платформе.

    дипломная работа [813,0 K], добавлен 27.10.2017

  • Анализ архитектуры ОС Windows 8. Сравнение с предыдущими версиями (интерфейс Modern UI, работа с учетными записями, модель безопасности, диспетчер задач, история файлов, восстановление системы, Storage Spaces). Особенности различных версий Windows 8.

    курсовая работа [289,1 K], добавлен 25.01.2016

  • Создание клиент-серверного приложения "Чат" с помощью среды визуальной разработки приложений Borland C++ Builder версии 6. Описание функциональности приложения: наличие клиент-серверной архитектуры, обмен короткими сообщениями, а также передача файлов.

    курсовая работа [302,0 K], добавлен 30.01.2012

  • Проблемы создания многоядерных процессоров, новейшие классификации и перспективы развития. Особенности реализации многоядерной архитектуры: параллельные вычисления, программное обеспечение. Инструментарий для разработки многопоточных приложений.

    курсовая работа [605,4 K], добавлен 21.03.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.