From 4d078431fe9e8ce227d2509623eb18ee515832bd Mon Sep 17 00:00:00 2001 From: Mihail Date: Sun, 5 Jan 2025 17:33:16 +0200 Subject: [PATCH] resolve --- pom.xml | 49 +++++++++++++++++++ .../controller/CharacterController.java | 27 ++++++++++ .../dto/CharacterResponseDataDto.java | 11 +++++ .../dto/character/CharacterDto.java | 12 +++++ .../dto/character/CharacterFromApiDto.java | 13 +++++ .../mapper/character/CharacterMapper.java | 11 +++++ .../mapper/character/CharacterMapperImpl.java | 42 ++++++++++++++++ .../academy/rickandmorty/model/Character.java | 21 ++++++++ .../character/CharacterRepository.java | 16 ++++++ .../service/AppStartupRunner.java | 34 +++++++++++++ .../rickandmorty/service/CharacterClient.java | 43 ++++++++++++++++ .../service/character/CharacterService.java | 10 ++++ .../character/CharacterServiceImpl.java | 30 ++++++++++++ src/main/resources/application.properties | 7 +++ 14 files changed, 326 insertions(+) create mode 100644 src/main/java/mate/academy/rickandmorty/controller/CharacterController.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDataDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/character/CharacterDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/character/CharacterFromApiDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapper.java create mode 100644 src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapperImpl.java create mode 100644 src/main/java/mate/academy/rickandmorty/model/Character.java create mode 100644 src/main/java/mate/academy/rickandmorty/repository/character/CharacterRepository.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/AppStartupRunner.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/CharacterClient.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/character/CharacterService.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/character/CharacterServiceImpl.java diff --git a/pom.xml b/pom.xml index 0c754f19..e367c796 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 @@ -32,6 +34,22 @@ test + + org.springframework.boot + spring-boot-starter-web + + + + mysql + mysql-connector-java + 8.0.33 + + + + org.projectlombok + lombok + + org.springframework.boot spring-boot-starter-data-jpa @@ -41,10 +59,41 @@ com.h2database h2 + + + org.mapstruct + mapstruct + 1.5.5.Final + + + 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 + ${mapstruct.version} + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/src/main/java/mate/academy/rickandmorty/controller/CharacterController.java b/src/main/java/mate/academy/rickandmorty/controller/CharacterController.java new file mode 100644 index 00000000..df04b6b7 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/controller/CharacterController.java @@ -0,0 +1,27 @@ +package mate.academy.rickandmorty.controller; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.character.CharacterDto; +import mate.academy.rickandmorty.service.character.CharacterService; +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; + +@RestController +@RequestMapping("/characters") +@RequiredArgsConstructor +public class CharacterController { + private final CharacterService characterService; + + @GetMapping("/random") + public CharacterDto getRandom() { + return characterService.getRandomCharacter(); + } + + @GetMapping("/filter") + public List findByName(@RequestParam String name) { + return characterService.findByName(name); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDataDto.java b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDataDto.java new file mode 100644 index 00000000..e4ad445d --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDataDto.java @@ -0,0 +1,11 @@ +package mate.academy.rickandmorty.dto; + +import java.util.ArrayList; +import java.util.List; +import lombok.Data; +import mate.academy.rickandmorty.dto.character.CharacterFromApiDto; + +@Data +public class CharacterResponseDataDto { + private List results = new ArrayList<>(); +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/character/CharacterDto.java b/src/main/java/mate/academy/rickandmorty/dto/character/CharacterDto.java new file mode 100644 index 00000000..3c1e5883 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/character/CharacterDto.java @@ -0,0 +1,12 @@ +package mate.academy.rickandmorty.dto.character; + +import lombok.Data; + +@Data +public class CharacterDto { + private Long id; + private Long externalId; + private String name; + private String status; + private String gender; +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/character/CharacterFromApiDto.java b/src/main/java/mate/academy/rickandmorty/dto/character/CharacterFromApiDto.java new file mode 100644 index 00000000..3a3fcbef --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/character/CharacterFromApiDto.java @@ -0,0 +1,13 @@ +package mate.academy.rickandmorty.dto.character; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class CharacterFromApiDto { + @JsonProperty("id") + private Long externalId; + private String name; + private String status; + private String gender; +} diff --git a/src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapper.java b/src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapper.java new file mode 100644 index 00000000..9d7f3a81 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapper.java @@ -0,0 +1,11 @@ +package mate.academy.rickandmorty.mapper.character; + +import mate.academy.rickandmorty.dto.character.CharacterDto; +import mate.academy.rickandmorty.dto.character.CharacterFromApiDto; +import mate.academy.rickandmorty.model.Character; + +public interface CharacterMapper { + CharacterDto toDto(Character character); + + Character toModel(CharacterFromApiDto character); +} diff --git a/src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapperImpl.java b/src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapperImpl.java new file mode 100644 index 00000000..3cffea14 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/mapper/character/CharacterMapperImpl.java @@ -0,0 +1,42 @@ +package mate.academy.rickandmorty.mapper.character; + +import mate.academy.rickandmorty.dto.character.CharacterDto; +import mate.academy.rickandmorty.dto.character.CharacterFromApiDto; +import mate.academy.rickandmorty.model.Character; +import org.springframework.stereotype.Component; + +@Component +public class CharacterMapperImpl implements CharacterMapper { + @Override + public CharacterDto toDto(Character character) { + if (character == null) { + return null; + } + + CharacterDto characterDto = new CharacterDto(); + + characterDto.setId(character.getId()); + characterDto.setExternalId(character.getExternalId()); + characterDto.setName(character.getName()); + characterDto.setStatus(character.getStatus()); + characterDto.setGender(character.getGender()); + + return characterDto; + } + + @Override + public Character toModel(CharacterFromApiDto character) { + if (character == null) { + return null; + } + + Character newCharacter = new Character(); + + newCharacter.setExternalId(character.getExternalId()); + newCharacter.setName(character.getName()); + newCharacter.setStatus(character.getStatus()); + newCharacter.setGender(character.getGender()); + + return newCharacter; + } +} 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..aa8db69d --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/model/Character.java @@ -0,0 +1,21 @@ +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.Data; + +@Data +@Entity +@Table(name = "characters") +public class Character { + @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/repository/character/CharacterRepository.java b/src/main/java/mate/academy/rickandmorty/repository/character/CharacterRepository.java new file mode 100644 index 00000000..4afc3e95 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/repository/character/CharacterRepository.java @@ -0,0 +1,16 @@ +package mate.academy.rickandmorty.repository.character; + +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("Select c FROM character c WHERE LOWER (c.name)" + + " LIKE LOWER(CONCAT('%', :searchTerm, '%'))") + List findByNameContainingIgnoreCase(@Param("searchTerm") String searchTerm); + + @Query("FROM Character ORDER BY RAND() LIMIT 1") + Character getRandomCharacter(); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/AppStartupRunner.java b/src/main/java/mate/academy/rickandmorty/service/AppStartupRunner.java new file mode 100644 index 00000000..204aa2c3 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/AppStartupRunner.java @@ -0,0 +1,34 @@ +package mate.academy.rickandmorty.service; + +import java.util.List; +import mate.academy.rickandmorty.dto.CharacterResponseDataDto; +import mate.academy.rickandmorty.mapper.character.CharacterMapper; +import mate.academy.rickandmorty.model.Character; +import mate.academy.rickandmorty.repository.character.CharacterRepository; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class AppStartupRunner implements CommandLineRunner { + private final CharacterClient characterClient; + private final CharacterMapper characterMapper; + private final CharacterRepository characterRepository; + + public AppStartupRunner(CharacterClient characterClient, + CharacterMapper characterMapper, + CharacterRepository characterRepository) { + this.characterClient = characterClient; + this.characterMapper = characterMapper; + this.characterRepository = characterRepository; + } + + @Override + public void run(String... args) throws Exception { + CharacterResponseDataDto characterResponseDataDto = characterClient.getAllCharacters(); + List characters = characterResponseDataDto.getResults() + .stream() + .map(characterMapper::toModel) + .toList(); + characterRepository.saveAll(characters); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/service/CharacterClient.java b/src/main/java/mate/academy/rickandmorty/service/CharacterClient.java new file mode 100644 index 00000000..65f26839 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/CharacterClient.java @@ -0,0 +1,43 @@ +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 lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.CharacterResponseDataDto; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CharacterClient { + private static final String URL = "https://rickandmortyapi.com/api/character"; + private final ObjectMapper objectMapper; + + public CharacterResponseDataDto getAllCharacters() { + CharacterResponseDataDto allCharacters = new CharacterResponseDataDto(); + + for (int currentPage = 1; currentPage <= 42; currentPage++) { + HttpClient client = HttpClient.newHttpClient(); + + HttpRequest request = HttpRequest.newBuilder() + .GET() + .uri(URI.create(URL + "?page=" + currentPage)) + .build(); + + try { + HttpResponse response = client.send(request, + HttpResponse.BodyHandlers.ofString()); + CharacterResponseDataDto pageData = objectMapper + .readValue(response.body(), CharacterResponseDataDto.class); + + allCharacters.getResults().addAll(pageData.getResults()); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } + return allCharacters; + } +} diff --git a/src/main/java/mate/academy/rickandmorty/service/character/CharacterService.java b/src/main/java/mate/academy/rickandmorty/service/character/CharacterService.java new file mode 100644 index 00000000..3e6abdad --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/character/CharacterService.java @@ -0,0 +1,10 @@ +package mate.academy.rickandmorty.service.character; + +import java.util.List; +import mate.academy.rickandmorty.dto.character.CharacterDto; + +public interface CharacterService { + CharacterDto getRandomCharacter(); + + List findByName(String name); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/character/CharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/character/CharacterServiceImpl.java new file mode 100644 index 00000000..d5fe4dec --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/character/CharacterServiceImpl.java @@ -0,0 +1,30 @@ +package mate.academy.rickandmorty.service.character; + +import java.util.List; +import lombok.AllArgsConstructor; +import mate.academy.rickandmorty.dto.character.CharacterDto; +import mate.academy.rickandmorty.mapper.character.CharacterMapper; +import mate.academy.rickandmorty.repository.character.CharacterRepository; +import mate.academy.rickandmorty.service.CharacterClient; +import org.springframework.stereotype.Component; + +@AllArgsConstructor +@Component +public class CharacterServiceImpl implements CharacterService { + private final CharacterRepository characterRepository; + private final CharacterMapper characterMapper; + private final CharacterClient characterClient; + + @Override + public CharacterDto getRandomCharacter() { + return characterMapper.toDto(characterRepository.getRandomCharacter()); + } + + @Override + public List findByName(String name) { + return characterRepository.findByNameContainingIgnoreCase(name) + .stream() + .map(characterMapper::toDto) + .toList(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b137891..6e9f23cd 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,8 @@ +spring.datasource.url=jdbc:mysql://localhost:3306/rick_morty +spring.datasource.username=root +spring.datasource.password=123456789 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true +server.port=8082