From 5dc32715f76798ec7e27b5de330d5d72bc46ba4d Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 22 Aug 2024 09:16:17 +0300 Subject: [PATCH 1/4] first working version --- pom.xml | 65 +++++++++++++++++++ .../rickandmorty/config/AppConfig.java | 26 ++++++++ .../rickandmorty/config/MapperConfig.java | 13 ++++ .../controller/RickandmortyapiController.java | 28 ++++++++ .../external/RickandmortyapiCharacterDto.java | 9 +++ .../dto/external/RickandmortyapiInfoDto.java | 10 +++ .../RickandmortyapiResponseDataDto.java | 12 ++++ .../dto/internal/CharacterDto.java | 10 +++ .../internal/CreateCharacterRequestDto.java | 9 +++ .../rickandmorty/mapper/CharacterMapper.java | 16 +++++ .../academy/rickandmorty/model/Character.java | 23 +++++++ .../repository/CharacterRepository.java | 12 ++++ .../service/CharacterService.java | 15 +++++ .../service/RickandmortyapiClient.java | 47 ++++++++++++++ .../service/impl/CharacterServiceImpl.java | 47 ++++++++++++++ src/main/resources/application.properties | 9 +++ .../rickandmorty/ApplicationTests.java | 6 +- 17 files changed, 354 insertions(+), 3 deletions(-) create mode 100644 src/main/java/mate/academy/rickandmorty/config/AppConfig.java create mode 100644 src/main/java/mate/academy/rickandmorty/config/MapperConfig.java create mode 100644 src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiCharacterDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiInfoDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/internal/CharacterDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/internal/CreateCharacterRequestDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java create mode 100644 src/main/java/mate/academy/rickandmorty/model/Character.java create mode 100644 src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/CharacterService.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java diff --git a/pom.xml b/pom.xml index 0c754f19..262e6436 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,8 @@ https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml + 0.2.0 + 1.5.5.Final @@ -37,10 +39,37 @@ spring-boot-starter-data-jpa + + com.mysql + mysql-connector-j + runtime + + com.h2database h2 + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-web + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.6.0 + @@ -48,7 +77,16 @@ org.springframework.boot spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + org.apache.maven.plugins maven-checkstyle-plugin @@ -66,6 +104,33 @@ true true false + src + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + ${lombok.mapstruct.binding.version} + + diff --git a/src/main/java/mate/academy/rickandmorty/config/AppConfig.java b/src/main/java/mate/academy/rickandmorty/config/AppConfig.java new file mode 100644 index 00000000..6e16dfad --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/config/AppConfig.java @@ -0,0 +1,26 @@ +package mate.academy.rickandmorty.config; + +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.mapper.CharacterMapper; +import mate.academy.rickandmorty.repository.CharacterRepository; +import mate.academy.rickandmorty.service.RickandmortyapiClient; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor +public class AppConfig { + private final CharacterRepository repository; + private final RickandmortyapiClient client; + private final CharacterMapper mapper; + + @Bean + public ApplicationRunner fetchDataToDB() { + return args -> { + repository.saveAll(client.getCharacters().stream() + .map(mapper::toModel) + .toList()); + }; + } +} diff --git a/src/main/java/mate/academy/rickandmorty/config/MapperConfig.java b/src/main/java/mate/academy/rickandmorty/config/MapperConfig.java new file mode 100644 index 00000000..450e58db --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/config/MapperConfig.java @@ -0,0 +1,13 @@ +package mate.academy.rickandmorty.config; + +import org.mapstruct.InjectionStrategy; +import org.mapstruct.NullValueCheckStrategy; + +@org.mapstruct.MapperConfig( + componentModel = "spring", + injectionStrategy = InjectionStrategy.CONSTRUCTOR, + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + implementationPackage = ".impl" +) +public class MapperConfig { +} diff --git a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java new file mode 100644 index 00000000..77d8c153 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java @@ -0,0 +1,28 @@ +package mate.academy.rickandmorty.controller; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.internal.CharacterDto; +import mate.academy.rickandmorty.service.CharacterService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class RickandmortyapiController { + private final CharacterService characterService; + + @GetMapping("/random") + public CharacterDto getRandomCharacter() { + int numberDbRecords = characterService.getAll().size(); + Long randomNumber = (long) (Math.random() * numberDbRecords); + + return characterService.getById(randomNumber); + } + + @GetMapping("/search/{name}") + public List getCharactersByName(@PathVariable String name) { + return characterService.findAllByName(name); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiCharacterDto.java b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiCharacterDto.java new file mode 100644 index 00000000..b351a388 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiCharacterDto.java @@ -0,0 +1,9 @@ +package mate.academy.rickandmorty.dto.external; + +public record RickandmortyapiCharacterDto( + Integer id, + String name, + String status, + String gender +) { +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiInfoDto.java b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiInfoDto.java new file mode 100644 index 00000000..2bc44f54 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiInfoDto.java @@ -0,0 +1,10 @@ +package mate.academy.rickandmorty.dto.external; + +import java.math.BigDecimal; + +public record RickandmortyapiInfoDto( + BigDecimal count, + BigDecimal pages, + String next +) { +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java new file mode 100644 index 00000000..45d7e8cf --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java @@ -0,0 +1,12 @@ +package mate.academy.rickandmorty.dto.external; + +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RickandmortyapiResponseDataDto { + private RickandmortyapiInfoDto info; + private List results; +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/internal/CharacterDto.java b/src/main/java/mate/academy/rickandmorty/dto/internal/CharacterDto.java new file mode 100644 index 00000000..8480eb89 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/internal/CharacterDto.java @@ -0,0 +1,10 @@ +package mate.academy.rickandmorty.dto.internal; + +public record CharacterDto( + Long id, + Integer externalId, + String name, + String status, + String gender +) { +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/internal/CreateCharacterRequestDto.java b/src/main/java/mate/academy/rickandmorty/dto/internal/CreateCharacterRequestDto.java new file mode 100644 index 00000000..abde5309 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/internal/CreateCharacterRequestDto.java @@ -0,0 +1,9 @@ +package mate.academy.rickandmorty.dto.internal; + +public record CreateCharacterRequestDto( + Integer externalId, + String name, + String status, + String gender +) { +} diff --git a/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java b/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java new file mode 100644 index 00000000..66d92ec9 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java @@ -0,0 +1,16 @@ +package mate.academy.rickandmorty.mapper; + +import mate.academy.rickandmorty.config.MapperConfig; +import mate.academy.rickandmorty.dto.external.RickandmortyapiCharacterDto; +import mate.academy.rickandmorty.dto.internal.CharacterDto; +import mate.academy.rickandmorty.model.Character; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapperConfig.class) +public interface CharacterMapper { + @Mapping(source = "id", target = "externalId") + Character toModel(RickandmortyapiCharacterDto characterDto); + + CharacterDto toDto(Character character); +} diff --git a/src/main/java/mate/academy/rickandmorty/model/Character.java b/src/main/java/mate/academy/rickandmorty/model/Character.java new file mode 100644 index 00000000..5edf98c9 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/model/Character.java @@ -0,0 +1,23 @@ +package mate.academy.rickandmorty.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +@Setter +@Table(name = "characters") +public class Character { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Integer externalId; + private String name; + private String status; + private String gender; +} diff --git a/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java b/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java new file mode 100644 index 00000000..650aacdd --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java @@ -0,0 +1,12 @@ +package mate.academy.rickandmorty.repository; + +import java.util.List; +import mate.academy.rickandmorty.model.Character; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface CharacterRepository extends JpaRepository { + @Query("FROM Character ch WHERE ch.name LIKE %:name%") + List findAllByName(@Param("name") String name); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/CharacterService.java b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java new file mode 100644 index 00000000..206f5d8b --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java @@ -0,0 +1,15 @@ +package mate.academy.rickandmorty.service; + +import java.util.List; +import mate.academy.rickandmorty.dto.external.RickandmortyapiCharacterDto; +import mate.academy.rickandmorty.dto.internal.CharacterDto; + +public interface CharacterService { + void saveAll(List requestDtos); + + List getAll(); + + CharacterDto getById(Long id); + + List findAllByName(String name); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java new file mode 100644 index 00000000..dc225415 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java @@ -0,0 +1,47 @@ +package mate.academy.rickandmorty.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.LinkedList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.external.RickandmortyapiCharacterDto; +import mate.academy.rickandmorty.dto.external.RickandmortyapiResponseDataDto; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class RickandmortyapiClient { + private String url = "https://rickandmortyapi.com/api/character"; + private final ObjectMapper objectMapper; + private final List characters = new LinkedList<>(); + + public List getCharacters() { + HttpClient httpClient = HttpClient.newHttpClient(); + try { + while (url != null) { + HttpRequest httpRequest = HttpRequest.newBuilder() + .GET() + .uri(URI.create(url)) + .build(); + HttpResponse response = httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString()); + RickandmortyapiResponseDataDto dataDto = objectMapper.readValue( + response.body(), + RickandmortyapiResponseDataDto.class); + characters.addAll(dataDto.getResults()); + url = dataDto.getInfo().next(); + } + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + System.out.println(characters); + + return characters; + } +} diff --git a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java new file mode 100644 index 00000000..18b782d8 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java @@ -0,0 +1,47 @@ +package mate.academy.rickandmorty.service.impl; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.external.RickandmortyapiCharacterDto; +import mate.academy.rickandmorty.dto.internal.CharacterDto; +import mate.academy.rickandmorty.mapper.CharacterMapper; +import mate.academy.rickandmorty.model.Character; +import mate.academy.rickandmorty.repository.CharacterRepository; +import mate.academy.rickandmorty.service.CharacterService; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CharacterServiceImpl implements CharacterService { + private final CharacterRepository characterRepository; + private final CharacterMapper characterMapper; + + @Override + public void saveAll(List requestDtos) { + List characters = requestDtos.stream() + .map(characterMapper::toModel) + .toList(); + characterRepository.saveAll(characters); + } + + @Override + public List getAll() { + return characterRepository.findAll().stream() + .map(characterMapper::toDto) + .toList(); + } + + @Override + public CharacterDto getById(Long id) { + Character character = characterRepository.findById(id).orElseThrow( + () -> new RuntimeException("can't find character by id " + id)); + return characterMapper.toDto(character); + } + + @Override + public List findAllByName(String name) { + return characterRepository.findAllByName(name).stream() + .map(characterMapper::toDto) + .toList(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b137891..bbe3796a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,10 @@ +spring.application.name=book-store +spring.datasource.url=jdbc:mysql://localhost:3306/characters?serverTimeZone=UTC +spring.datasource.username=root +spring.datasource.password=1423 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true + +server.servlet.context-path=/api diff --git a/src/test/java/mate/academy/rickandmorty/ApplicationTests.java b/src/test/java/mate/academy/rickandmorty/ApplicationTests.java index 8fec6af0..09b17308 100644 --- a/src/test/java/mate/academy/rickandmorty/ApplicationTests.java +++ b/src/test/java/mate/academy/rickandmorty/ApplicationTests.java @@ -6,8 +6,8 @@ @SpringBootTest class ApplicationTests { - @Test - void contextLoads() { - } + @Test + void contextLoads() { + } } From 02717ca4cf13fa324a813e8eaad10c7c153f3aff Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 22 Aug 2024 09:40:32 +0300 Subject: [PATCH 2/4] moved getting of random character to service level --- .../controller/RickandmortyapiController.java | 5 +---- .../rickandmorty/service/CharacterService.java | 2 ++ .../rickandmorty/service/RickandmortyapiClient.java | 11 ++++------- .../service/impl/CharacterServiceImpl.java | 6 ++++++ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java index 77d8c153..77f5737b 100644 --- a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java +++ b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java @@ -15,10 +15,7 @@ public class RickandmortyapiController { @GetMapping("/random") public CharacterDto getRandomCharacter() { - int numberDbRecords = characterService.getAll().size(); - Long randomNumber = (long) (Math.random() * numberDbRecords); - - return characterService.getById(randomNumber); + return characterService.getRandomCharacter(); } @GetMapping("/search/{name}") diff --git a/src/main/java/mate/academy/rickandmorty/service/CharacterService.java b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java index 206f5d8b..c1138ead 100644 --- a/src/main/java/mate/academy/rickandmorty/service/CharacterService.java +++ b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java @@ -12,4 +12,6 @@ public interface CharacterService { CharacterDto getById(Long id); List findAllByName(String name); + + CharacterDto getRandomCharacter(); } diff --git a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java index dc225415..974cbce0 100644 --- a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java +++ b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java @@ -28,20 +28,17 @@ public List getCharacters() { .GET() .uri(URI.create(url)) .build(); - HttpResponse response = httpClient.send( - httpRequest, + HttpResponse response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); - RickandmortyapiResponseDataDto dataDto = objectMapper.readValue( - response.body(), + RickandmortyapiResponseDataDto dataDto = objectMapper.readValue(response.body(), RickandmortyapiResponseDataDto.class); + characters.addAll(dataDto.getResults()); url = dataDto.getInfo().next(); } } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); + throw new RuntimeException("can't get data from client", e); } - System.out.println(characters); - return characters; } } diff --git a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java index 18b782d8..f3ba16bc 100644 --- a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java @@ -44,4 +44,10 @@ public List findAllByName(String name) { .map(characterMapper::toDto) .toList(); } + + @Override + public CharacterDto getRandomCharacter() { + Long randomNumber = (long) (Math.random() * characterRepository.count()); + return getById(randomNumber); + } } From 46ab57255fd793a7c83d7a6ff2d40bbcc9670c9b Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 22 Aug 2024 10:02:10 +0300 Subject: [PATCH 3/4] added Swagger --- pom.xml | 10 ++++++++++ .../controller/RickandmortyapiController.java | 5 +++++ .../exception/EntityNotFoundException.java | 7 +++++++ .../rickandmorty/service/RickandmortyapiClient.java | 2 +- .../service/impl/CharacterServiceImpl.java | 3 ++- 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/main/java/mate/academy/rickandmorty/exception/EntityNotFoundException.java diff --git a/pom.xml b/pom.xml index 262e6436..b462055f 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,16 @@ springdoc-openapi-starter-webmvc-ui 2.6.0 + + + org.springframework.boot + spring-boot-starter-validation + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.6.0 + diff --git a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java index 77f5737b..aa42de60 100644 --- a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java +++ b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java @@ -1,5 +1,7 @@ package mate.academy.rickandmorty.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import lombok.RequiredArgsConstructor; import mate.academy.rickandmorty.dto.internal.CharacterDto; @@ -8,16 +10,19 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "Rick and Morty management", description = "Endpoints for managing characters") @RestController @RequiredArgsConstructor public class RickandmortyapiController { private final CharacterService characterService; + @Operation(summary = "Get random", description = "get random hero from all characters") @GetMapping("/random") public CharacterDto getRandomCharacter() { return characterService.getRandomCharacter(); } + @Operation(summary = "Get by name", description = "get all characters by name") @GetMapping("/search/{name}") public List getCharactersByName(@PathVariable String name) { return characterService.findAllByName(name); diff --git a/src/main/java/mate/academy/rickandmorty/exception/EntityNotFoundException.java b/src/main/java/mate/academy/rickandmorty/exception/EntityNotFoundException.java new file mode 100644 index 00000000..99612fdf --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/exception/EntityNotFoundException.java @@ -0,0 +1,7 @@ +package mate.academy.rickandmorty.exception; + +public class EntityNotFoundException extends RuntimeException { + public EntityNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java index 974cbce0..13aa4bcc 100644 --- a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java +++ b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java @@ -37,7 +37,7 @@ public List getCharacters() { url = dataDto.getInfo().next(); } } catch (IOException | InterruptedException e) { - throw new RuntimeException("can't get data from client", e); + throw new RuntimeException("Can't get data from client", e); } return characters; } diff --git a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java index f3ba16bc..d756f92d 100644 --- a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java @@ -1,5 +1,6 @@ package mate.academy.rickandmorty.service.impl; +import jakarta.persistence.EntityNotFoundException; import java.util.List; import lombok.RequiredArgsConstructor; import mate.academy.rickandmorty.dto.external.RickandmortyapiCharacterDto; @@ -34,7 +35,7 @@ public List getAll() { @Override public CharacterDto getById(Long id) { Character character = characterRepository.findById(id).orElseThrow( - () -> new RuntimeException("can't find character by id " + id)); + () -> new EntityNotFoundException("Can't find character by id " + id)); return characterMapper.toDto(character); } From 89284eaf19381910cc45ec26e255679be2d74c02 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 22 Aug 2024 22:46:50 +0300 Subject: [PATCH 4/4] added mapstruct for listDto, request param for searching by name --- .../controller/RickandmortyapiController.java | 8 +++++--- .../external/RickandmortyapiResponseDataDto.java | 11 ++++------- .../rickandmorty/mapper/CharacterMapper.java | 6 ++++++ .../rickandmorty/service/RickandmortyapiClient.java | 4 ++-- .../service/impl/CharacterServiceImpl.java | 13 +++---------- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java index aa42de60..9a8e97f3 100644 --- a/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java +++ b/src/main/java/mate/academy/rickandmorty/controller/RickandmortyapiController.java @@ -7,11 +7,13 @@ import mate.academy.rickandmorty.dto.internal.CharacterDto; import mate.academy.rickandmorty.service.CharacterService; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Tag(name = "Rick and Morty management", description = "Endpoints for managing characters") @RestController +@RequestMapping(value = "/characters") @RequiredArgsConstructor public class RickandmortyapiController { private final CharacterService characterService; @@ -23,8 +25,8 @@ public CharacterDto getRandomCharacter() { } @Operation(summary = "Get by name", description = "get all characters by name") - @GetMapping("/search/{name}") - public List getCharactersByName(@PathVariable String name) { + @GetMapping("/search") + public List getCharactersByName(@RequestParam String name) { return characterService.findAllByName(name); } } diff --git a/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java index 45d7e8cf..4ffaa336 100644 --- a/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java +++ b/src/main/java/mate/academy/rickandmorty/dto/external/RickandmortyapiResponseDataDto.java @@ -1,12 +1,9 @@ package mate.academy.rickandmorty.dto.external; import java.util.List; -import lombok.Getter; -import lombok.Setter; -@Getter -@Setter -public class RickandmortyapiResponseDataDto { - private RickandmortyapiInfoDto info; - private List results; +public record RickandmortyapiResponseDataDto( + RickandmortyapiInfoDto info, + List results +) { } diff --git a/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java b/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java index 66d92ec9..816357bc 100644 --- a/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java +++ b/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java @@ -1,5 +1,6 @@ package mate.academy.rickandmorty.mapper; +import java.util.List; import mate.academy.rickandmorty.config.MapperConfig; import mate.academy.rickandmorty.dto.external.RickandmortyapiCharacterDto; import mate.academy.rickandmorty.dto.internal.CharacterDto; @@ -12,5 +13,10 @@ public interface CharacterMapper { @Mapping(source = "id", target = "externalId") Character toModel(RickandmortyapiCharacterDto characterDto); + @Mapping(source = "id", target = "externalId") + List toModelList(List characterDtos); + CharacterDto toDto(Character character); + + List toDtoList(List characters); } diff --git a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java index 13aa4bcc..0e36c0ab 100644 --- a/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java +++ b/src/main/java/mate/academy/rickandmorty/service/RickandmortyapiClient.java @@ -33,8 +33,8 @@ public List getCharacters() { RickandmortyapiResponseDataDto dataDto = objectMapper.readValue(response.body(), RickandmortyapiResponseDataDto.class); - characters.addAll(dataDto.getResults()); - url = dataDto.getInfo().next(); + characters.addAll(dataDto.results()); + url = dataDto.info().next(); } } catch (IOException | InterruptedException e) { throw new RuntimeException("Can't get data from client", e); diff --git a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java index d756f92d..d5ce6be7 100644 --- a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java @@ -19,17 +19,12 @@ public class CharacterServiceImpl implements CharacterService { @Override public void saveAll(List requestDtos) { - List characters = requestDtos.stream() - .map(characterMapper::toModel) - .toList(); - characterRepository.saveAll(characters); + characterRepository.saveAll(characterMapper.toModelList(requestDtos)); } @Override public List getAll() { - return characterRepository.findAll().stream() - .map(characterMapper::toDto) - .toList(); + return characterMapper.toDtoList(characterRepository.findAll()); } @Override @@ -41,9 +36,7 @@ public CharacterDto getById(Long id) { @Override public List findAllByName(String name) { - return characterRepository.findAllByName(name).stream() - .map(characterMapper::toDto) - .toList(); + return characterMapper.toDtoList(characterRepository.findAllByName(name)); } @Override