From bacf6b8483a10bf7790275be66b40c009b1f999b Mon Sep 17 00:00:00 2001 From: GlebPashko Date: Fri, 13 Sep 2024 12:20:31 +0300 Subject: [PATCH 1/3] solution --- pom.xml | 191 ++++++++++++------ .../academy/rickandmorty/Application.java | 16 ++ .../rickandmorty/config/MapperConfig.java | 13 ++ .../controller/CharactersController.java | 31 +++ .../rickandmorty/dto/CharacterDto.java | 13 ++ .../dto/CharacterResponseDataDto.java | 10 + .../dto/CharacterResponseInfoDto.java | 10 + .../rickandmorty/mapper/CharacterMapper.java | 21 ++ .../rickandmorty/model/CharacterEntity.java | 21 ++ .../repository/CharacterRepository.java | 15 ++ .../service/CharacterService.java | 12 ++ .../service/CharactersClient.java | 8 + .../service/impl/CharacterServiceImpl.java | 40 ++++ .../service/impl/CharactersClientImpl.java | 50 +++++ src/main/resources/application.properties | 9 + 15 files changed, 394 insertions(+), 66 deletions(-) create mode 100644 src/main/java/mate/academy/rickandmorty/config/MapperConfig.java create mode 100644 src/main/java/mate/academy/rickandmorty/controller/CharactersController.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/CharacterDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDataDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/dto/CharacterResponseInfoDto.java create mode 100644 src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java create mode 100644 src/main/java/mate/academy/rickandmorty/model/CharacterEntity.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/CharactersClient.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java create mode 100644 src/main/java/mate/academy/rickandmorty/service/impl/CharactersClientImpl.java diff --git a/pom.xml b/pom.xml index 0c754f19..1a915b5a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,74 +1,133 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.1.4 - - - mate.academy - jv-rick-and-morty - 0.0.1-SNAPSHOT - jv-rick-and-morty - jv-rick-and-morty - - 17 - 3.1.1 - - https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml - - - - - org.springframework.boot - spring-boot-starter - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.4 + + + mate.academy + jv-rick-and-morty + 0.0.1-SNAPSHOT + jv-rick-and-morty + jv-rick-and-morty + + 17 + 3.1.1 + + https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml + + + + + org.springframework.boot + spring-boot-starter + - - org.springframework.boot - spring-boot-starter-test - test - + + org.springframework.boot + spring-boot-starter-test + test + - - org.springframework.boot - spring-boot-starter-data-jpa - + + org.springframework.boot + spring-boot-starter-data-jpa + - - com.h2database - h2 - - + + org.springframework.boot + spring-boot-starter-web + - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.3.0 - - - compile - - check - - - - - ${maven.checkstyle.plugin.configLocation} - true - true - false - - - - + + org.projectlombok + lombok + + + + org.apache.commons + commons-dbcp2 + 2.9.0 + + + + org.hibernate.orm + hibernate-core + 6.5.2.Final + compile + + + + org.hibernate.validator + hibernate-validator + + + + mysql + mysql-connector-java + 8.0.33 + + + + com.h2database + h2 + test + + + + org.mapstruct + mapstruct + 1.5.5.Final + + + + org.mapstruct + mapstruct-processor + 1.5.5.Final + provided + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.1.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.3.0 + + + compile + + check + + + + + ${maven.checkstyle.plugin.configLocation} + true + true + false + + + + diff --git a/src/main/java/mate/academy/rickandmorty/Application.java b/src/main/java/mate/academy/rickandmorty/Application.java index cdea84fc..bb9b52cb 100644 --- a/src/main/java/mate/academy/rickandmorty/Application.java +++ b/src/main/java/mate/academy/rickandmorty/Application.java @@ -1,12 +1,28 @@ package mate.academy.rickandmorty; +import mate.academy.rickandmorty.service.CharacterService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; @SpringBootApplication public class Application { + private final CharacterService characterService; + + @Autowired + public Application(CharacterService characterService) { + this.characterService = characterService; + } + public static void main(String[] args) { SpringApplication.run(Application.class, args); } + + @EventListener(ApplicationReadyEvent.class) + public void runAfterStartup() { + characterService.saveAll(); + } } 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/CharactersController.java b/src/main/java/mate/academy/rickandmorty/controller/CharactersController.java new file mode 100644 index 00000000..5ce9a262 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/controller/CharactersController.java @@ -0,0 +1,31 @@ +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.model.CharacterEntity; +import mate.academy.rickandmorty.service.CharacterService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Сharacters management", description = "Endpoints for managing Сharacters") +@RestController +@RequestMapping("/characters") +@RequiredArgsConstructor +public class CharactersController { + private final CharacterService characterService; + + @Operation(summary = "Get one random character") + @GetMapping("/randomly") + public CharacterEntity randomCharacter() { + return characterService.findRandom(); + } + + @Operation(summary = "Search characters by name") + @GetMapping("/search") + public List searchByName(String name) { + return characterService.findByName(name); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/CharacterDto.java b/src/main/java/mate/academy/rickandmorty/dto/CharacterDto.java new file mode 100644 index 00000000..8bf9ec92 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/CharacterDto.java @@ -0,0 +1,13 @@ +package mate.academy.rickandmorty.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class CharacterDto { + @JsonProperty("id") + private long externalId; + private String name; + private String status; + private String gender; +} 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..7215e4c4 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDataDto.java @@ -0,0 +1,10 @@ +package mate.academy.rickandmorty.dto; + +import java.util.List; +import lombok.Data; + +@Data +public class CharacterResponseDataDto { + private CharacterResponseInfoDto info; + private List results; +} diff --git a/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseInfoDto.java b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseInfoDto.java new file mode 100644 index 00000000..bb7dd226 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseInfoDto.java @@ -0,0 +1,10 @@ +package mate.academy.rickandmorty.dto; + +import lombok.Data; + +@Data +public class CharacterResponseInfoDto { + private int pages; + private String next; + private String prev; +} 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..21823068 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java @@ -0,0 +1,21 @@ +package mate.academy.rickandmorty.mapper; + +import java.util.List; +import mate.academy.rickandmorty.config.MapperConfig; +import mate.academy.rickandmorty.dto.CharacterDto; +import mate.academy.rickandmorty.model.CharacterEntity; +import org.mapstruct.AfterMapping; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; + +@Mapper(config = MapperConfig.class) +public interface CharacterMapper { + CharacterEntity toModel(CharacterDto requestDto); + + List toListModel(List requestDto); + + @AfterMapping + default void setExternalId(CharacterDto requestDto, @MappingTarget CharacterEntity entity) { + entity.setExternalId(requestDto.getExternalId()); + } +} diff --git a/src/main/java/mate/academy/rickandmorty/model/CharacterEntity.java b/src/main/java/mate/academy/rickandmorty/model/CharacterEntity.java new file mode 100644 index 00000000..28caf7ad --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/model/CharacterEntity.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 lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Entity +public class CharacterEntity { + @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/CharacterRepository.java b/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java new file mode 100644 index 00000000..cd80398c --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java @@ -0,0 +1,15 @@ +package mate.academy.rickandmorty.repository; + +import java.util.List; +import mate.academy.rickandmorty.model.CharacterEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; + +public interface CharacterRepository extends JpaRepository, + JpaSpecificationExecutor { + + @Query("SELECT c FROM CharacterEntity c WHERE UPPER(c.name) " + + "LIKE UPPER(CONCAT('%', :name, '%'))") + List findByName(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..b0e8cc6a --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java @@ -0,0 +1,12 @@ +package mate.academy.rickandmorty.service; + +import java.util.List; +import mate.academy.rickandmorty.model.CharacterEntity; + +public interface CharacterService { + void saveAll(); + + CharacterEntity findRandom(); + + List findByName(String name); +} diff --git a/src/main/java/mate/academy/rickandmorty/service/CharactersClient.java b/src/main/java/mate/academy/rickandmorty/service/CharactersClient.java new file mode 100644 index 00000000..dfdb1e96 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/CharactersClient.java @@ -0,0 +1,8 @@ +package mate.academy.rickandmorty.service; + +import java.util.List; +import mate.academy.rickandmorty.dto.CharacterDto; + +public interface CharactersClient { + List findAll(); +} 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..b04c83cf --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java @@ -0,0 +1,40 @@ +package mate.academy.rickandmorty.service.impl; + +import java.util.List; +import java.util.Random; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.mapper.CharacterMapper; +import mate.academy.rickandmorty.model.CharacterEntity; +import mate.academy.rickandmorty.repository.CharacterRepository; +import mate.academy.rickandmorty.service.CharacterService; +import mate.academy.rickandmorty.service.CharactersClient; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CharacterServiceImpl implements CharacterService { + private final CharactersClient charactersClient; + private final CharacterRepository characterRepository; + private final CharacterMapper characterMapper; + + @Override + public void saveAll() { + characterRepository.saveAll(characterMapper.toListModel(charactersClient.findAll())); + } + + @Override + public CharacterEntity findRandom() { + return characterRepository.findById(getRandomId()) + .orElseThrow(() -> new RuntimeException("No character found")); + } + + @Override + public List findByName(String name) { + return characterRepository.findByName(name); + } + + private long getRandomId() { + return new Random().nextLong(characterRepository.count()); + } +} + diff --git a/src/main/java/mate/academy/rickandmorty/service/impl/CharactersClientImpl.java b/src/main/java/mate/academy/rickandmorty/service/impl/CharactersClientImpl.java new file mode 100644 index 00000000..abce2a30 --- /dev/null +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharactersClientImpl.java @@ -0,0 +1,50 @@ +package mate.academy.rickandmorty.service.impl; + +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.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import mate.academy.rickandmorty.dto.CharacterDto; +import mate.academy.rickandmorty.dto.CharacterResponseDataDto; +import mate.academy.rickandmorty.service.CharactersClient; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CharactersClientImpl implements CharactersClient { + private static final String URL_BASE = "https://rickandmortyapi.com/api/character/"; + + private final ObjectMapper objectMapper; + + @Override + public List findAll() { + String url = URL_BASE; + List allCharacters = new ArrayList<>(); + 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()); + CharacterResponseDataDto dataDto = objectMapper.readValue(response.body(), + CharacterResponseDataDto.class); + + allCharacters.addAll(dataDto.getResults()); + url = dataDto.getInfo().getNext(); + } + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + return allCharacters; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b137891..1633d505 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/filmsdb?serverTimeZone=UTC +spring.datasource.username=root +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true +spring.jpa.open-in-view=false + From bd3fca8bbb8247452f9362f883bf2fe43affba36 Mon Sep 17 00:00:00 2001 From: GlebPashko Date: Fri, 13 Sep 2024 12:42:47 +0300 Subject: [PATCH 2/3] excluded mapper from validation style --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 1a915b5a..a2d50c1b 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,7 @@ ${maven.checkstyle.plugin.configLocation} true + src/main/java/mate/academy/rickandmorty/mapper/CharacterMapper.java true false From 248aef7165bfa9c729cb42b81591bc4c781b32e2 Mon Sep 17 00:00:00 2001 From: GlebPashko Date: Mon, 16 Sep 2024 08:32:12 +0300 Subject: [PATCH 3/3] Changed Controller and Service --- .../academy/rickandmorty/controller/CharactersController.java | 4 ++-- .../rickandmorty/service/impl/CharacterServiceImpl.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/mate/academy/rickandmorty/controller/CharactersController.java b/src/main/java/mate/academy/rickandmorty/controller/CharactersController.java index 5ce9a262..bcfe3c29 100644 --- a/src/main/java/mate/academy/rickandmorty/controller/CharactersController.java +++ b/src/main/java/mate/academy/rickandmorty/controller/CharactersController.java @@ -18,13 +18,13 @@ public class CharactersController { private final CharacterService characterService; @Operation(summary = "Get one random character") - @GetMapping("/randomly") + @GetMapping("/random") public CharacterEntity randomCharacter() { return characterService.findRandom(); } @Operation(summary = "Search characters by name") - @GetMapping("/search") + @GetMapping public List searchByName(String name) { return characterService.findByName(name); } 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 b04c83cf..1131e953 100644 --- a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java +++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java @@ -16,6 +16,7 @@ public class CharacterServiceImpl implements CharacterService { private final CharactersClient charactersClient; private final CharacterRepository characterRepository; private final CharacterMapper characterMapper; + private final Random random = new Random(); @Override public void saveAll() { @@ -34,7 +35,6 @@ public List findByName(String name) { } private long getRandomId() { - return new Random().nextLong(characterRepository.count()); + return random.nextLong(characterRepository.count()); } } -