-
Notifications
You must be signed in to change notification settings - Fork 308
resolve #216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
resolve #216
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<CharacterDto> findByName(@RequestParam String name) { | ||
return characterService.findByName(name); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<CharacterFromApiDto> results = new ArrayList<>(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Character, Long> { | ||
@Query("Select c FROM character c WHERE LOWER (c.name)" | ||
+ " LIKE LOWER(CONCAT('%', :searchTerm, '%'))") | ||
List<Character> findByNameContainingIgnoreCase(@Param("searchTerm") String searchTerm); | ||
|
||
@Query("FROM Character ORDER BY RAND() LIMIT 1") | ||
Character getRandomCharacter(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Character> characters = characterResponseDataDto.getResults() | ||
.stream() | ||
.map(characterMapper::toModel) | ||
.toList(); | ||
characterRepository.saveAll(characters); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating a new |
||
|
||
HttpRequest request = HttpRequest.newBuilder() | ||
.GET() | ||
.uri(URI.create(URL + "?page=" + currentPage)) | ||
.build(); | ||
|
||
try { | ||
HttpResponse<String> 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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<CharacterDto> findByName(String name); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()); | ||
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
} | ||
|
||
@Override | ||
public List<CharacterDto> findByName(String name) { | ||
return characterRepository.findByNameContainingIgnoreCase(name) | ||
.stream() | ||
.map(characterMapper::toDto) | ||
.toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
getRandomCharacter
method usesORDER BY RAND() LIMIT 1
, which is not standard JPQL syntax. JPQL does not supportLIMIT
orRAND()
directly. Consider using native SQL or a different approach to fetch a random record.