From e6f660684a21b5af8ae2d2c0181e4c2c0d71aec2 Mon Sep 17 00:00:00 2001 From: ivan hromovyi Date: Wed, 18 Oct 2023 12:54:32 +0200 Subject: [PATCH] Saved necessary data from an external DB and implemented two methods in controller. --- pom.xml | 60 ++++++++++++++++++- .../rickandmorty/config/MapperConfig.java | 13 ++++ .../controller/RickAndMortyController.java | 35 +++++++++++ .../external/CharacterResponseDataDto.java | 9 +++ .../external/RickAndMortyCharacterDto.java | 11 ++++ .../dto/internal/RickAndMortyCharacter.java | 22 +++++++ .../rickandmorty/mapper/CharacterMapper.java | 14 +++++ .../RickAndMortyCharacterRepository.java | 12 ++++ .../service/RickAndMortyClient.java | 39 ++++++++++++ .../RickAndMortyCharacterService.java | 10 ++++ .../RickAndMortyCharacterServiceImpl.java | 40 +++++++++++++ src/main/resources/application.properties | 8 +++ .../rickandmorty/ApplicationTests.java | 8 +-- 13 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 src/main/java/mate/academy/rickandmorty/config/MapperConfig.java create mode 100644 src/main/java/mate/academy/rickandmorty/controller/RickAndMortyController.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/external/CharacterResponseDataDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/external/RickAndMortyCharacterDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/internal/RickAndMortyCharacter.java create mode 100644 src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java create mode 100644 src/main/java/mate/academy/rickandmorty/repository/character/RickAndMortyCharacterRepository.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/RickAndMortyClient.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterService.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterServiceImpl.java diff --git a/pom.xml b/pom.xml index 0c754f19..e78821d8 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,8 @@ https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml + 1.5.5.Final + 0.2.0 @@ -41,6 +43,34 @@ com.h2database h2 + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-jdbc + 6.0.13 + + + mysql + mysql-connector-java + 8.0.33 + + + org.projectlombok + lombok + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + io.springfox + springfox-boot-starter + 3.0.0 + @@ -62,13 +92,41 @@ + + ${project.build.sourceDirectory} + ${project.build.testSourceDirectory} + ${maven.checkstyle.plugin.configLocation} true true false + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.projectlombok + lombok-mapstruct-binding + ${lombok.mapstruct.binding.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + + - 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/RickAndMortyController.java b/src/main/java/mate/academy/rickandmorty/controller/RickAndMortyController.java new file mode 100644 index 00000000..8464e85f --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/controller/RickAndMortyController.java @@ -0,0 +1,35 @@ +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.RickAndMortyCharacter; +import mate.academy.rickandmorty.service.character.RickAndMortyCharacterService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Actions with characters", + description = "Endpoints which indicates on a specific action with Character") +@RequiredArgsConstructor +@RestController +@RequestMapping("/rickandmorty") +public class RickAndMortyController { + private final RickAndMortyCharacterService service; + + @GetMapping("/random") + @Operation(summary = "Get random Character", + description = "Get random Character which is stored in internal DB") + public RickAndMortyCharacter getRandomCharacter() { + return service.getRandomCharacter(); + } + + @Operation(summary = "Get Characters by search param(name)", + description = "Receive all Characters containing name") + @GetMapping("/find") + public List getByNameContaining(@RequestParam String name) { + return service.findByNameContaining(name); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/external/CharacterResponseDataDto.java b/src/main/java/mate/academy/rickandmorty/dto/external/CharacterResponseDataDto.java new file mode 100644 index 00000000..90c58833 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/external/CharacterResponseDataDto.java @@ -0,0 +1,9 @@ +package mate.academy.rickandmorty.dto.external; + +import java.util.List; +import lombok.Data; + +@Data +public class CharacterResponseDataDto { + private List results; +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/external/RickAndMortyCharacterDto.java b/src/main/java/mate/academy/rickandmorty/dto/external/RickAndMortyCharacterDto.java new file mode 100644 index 00000000..31aa59eb --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/external/RickAndMortyCharacterDto.java @@ -0,0 +1,11 @@ +package mate.academy.rickandmorty.dto.external; + +import lombok.Data; + +@Data +public class RickAndMortyCharacterDto { + private Long id; + private String name; + private String status; + private String gender; +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/internal/RickAndMortyCharacter.java b/src/main/java/mate/academy/rickandmorty/dto/internal/RickAndMortyCharacter.java new file mode 100644 index 00000000..b9d74e9b --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/internal/RickAndMortyCharacter.java @@ -0,0 +1,22 @@ +package mate.academy.rickandmorty.dto.internal; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +@Data +@Entity +@Table(name = "rick_and_morty_characters") +public class RickAndMortyCharacter { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Long externalId; + private String name; + private String status; + private 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..3a858208 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java @@ -0,0 +1,14 @@ +package mate.academy.rickandmorty.mapper; + +import mate.academy.rickandmorty.config.MapperConfig; +import mate.academy.rickandmorty.dto.external.RickAndMortyCharacterDto; +import mate.academy.rickandmorty.dto.internal.RickAndMortyCharacter; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapperConfig.class) +public interface CharacterMapper { + @Mapping(target = "id", ignore = true) + @Mapping(target = "externalId", source = "id") + RickAndMortyCharacter toModel(RickAndMortyCharacterDto characterDto); +} diff --git a/src/main/java/mate/academy/rickandmorty/repository/character/RickAndMortyCharacterRepository.java b/src/main/java/mate/academy/rickandmorty/repository/character/RickAndMortyCharacterRepository.java new file mode 100644 index 00000000..408857d3 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/repository/character/RickAndMortyCharacterRepository.java @@ -0,0 +1,12 @@ +package mate.academy.rickandmorty.repository.character; + +import java.util.List; +import mate.academy.rickandmorty.dto.internal.RickAndMortyCharacter; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface RickAndMortyCharacterRepository + extends JpaRepository, + JpaSpecificationExecutor { + List findByNameContaining(String name); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/RickAndMortyClient.java b/src/main/java/mate/academy/rickandmorty/service/RickAndMortyClient.java new file mode 100644 index 00000000..802ffb7f --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/RickAndMortyClient.java @@ -0,0 +1,39 @@ +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.List; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.external.CharacterResponseDataDto; +import mate.academy.rickandmorty.dto.external.RickAndMortyCharacterDto; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +public class RickAndMortyClient { + private static final String BASE_URL = "https://rickandmortyapi.com/api"; + private static final String ALL_CHARACTERS = "/character"; + private final ObjectMapper objectMapper; + + public List getAllCharacter() { + HttpClient httpClient = HttpClient.newHttpClient(); + String url = BASE_URL + ALL_CHARACTERS; + HttpRequest httpRequest = HttpRequest.newBuilder() + .GET() + .uri(URI.create(url)) + .build(); + try { + HttpResponse response = + httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + CharacterResponseDataDto responseDataDto = + objectMapper.readValue(response.body(), CharacterResponseDataDto.class); + return responseDataDto.getResults(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException("Couldn't send httpRequest"); + } + } +} diff --git a/src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterService.java b/src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterService.java new file mode 100644 index 00000000..8ce75e74 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterService.java @@ -0,0 +1,10 @@ +package mate.academy.rickandmorty.service.character; + +import java.util.List; +import mate.academy.rickandmorty.dto.internal.RickAndMortyCharacter; + +public interface RickAndMortyCharacterService { + RickAndMortyCharacter getRandomCharacter(); + + List findByNameContaining(String name); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterServiceImpl.java new file mode 100644 index 00000000..c02612a8 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/character/RickAndMortyCharacterServiceImpl.java @@ -0,0 +1,40 @@ +package mate.academy.rickandmorty.service.character; + +import jakarta.annotation.PostConstruct; +import java.util.List; +import java.util.Random; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.internal.RickAndMortyCharacter; +import mate.academy.rickandmorty.mapper.CharacterMapper; +import mate.academy.rickandmorty.repository.character.RickAndMortyCharacterRepository; +import mate.academy.rickandmorty.service.RickAndMortyClient; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class RickAndMortyCharacterServiceImpl implements RickAndMortyCharacterService { + private final RickAndMortyClient client; + private final RickAndMortyCharacterRepository repository; + private final CharacterMapper characterMapper; + + @PostConstruct + public void saveAllCharacters() { + List list = + client.getAllCharacter() + .stream() + .map(characterMapper::toModel) + .toList(); + repository.saveAll(list); + } + + @Override + public RickAndMortyCharacter getRandomCharacter() { + List all = repository.findAll(); + return all.get(new Random().nextInt(all.size())); + } + + @Override + public List findByNameContaining(String name) { + return repository.findByNameContaining(name); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b137891..23267607 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,9 @@ +spring.datasource.url=jdbc:mysql://localhost:3306/rick-and-morty +spring.datasource.username=root +spring.datasource.password=1234 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.jpa.hibernate.ddl-auto=create-drop +spring.mvc.log-request-details=true +spring.thymeleaf.check-template-location=false +spring.jpa.open-in-view=false diff --git a/src/test/java/mate/academy/rickandmorty/ApplicationTests.java b/src/test/java/mate/academy/rickandmorty/ApplicationTests.java index 8fec6af0..4fe47c0d 100644 --- a/src/test/java/mate/academy/rickandmorty/ApplicationTests.java +++ b/src/test/java/mate/academy/rickandmorty/ApplicationTests.java @@ -5,9 +5,7 @@ @SpringBootTest class ApplicationTests { - - @Test - void contextLoads() { - } - + @Test + void contextLoads() { + } }