remove hal+json and add pageable

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2024-10-30 12:02:30 +01:00
parent 46dd36a846
commit a184f4a038
7 changed files with 64 additions and 56 deletions

View File

@@ -54,6 +54,10 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.modulith</groupId> <groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-starter-test</artifactId> <artifactId>spring-modulith-starter-test</artifactId>
@@ -82,10 +86,6 @@
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.github.ben-manes.caffeine</groupId> <groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId> <artifactId>caffeine</artifactId>

View File

@@ -1,19 +1,18 @@
package dev.mars3142.fhq.timezone_service.timezone.controllers; package dev.mars3142.fhq.timezone_service.timezone.controllers;
import static org.springframework.beans.support.PagedListHolder.DEFAULT_PAGE_SIZE;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.LocationResponse;
import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.TimezoneResponse; import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.TimezoneResponse;
import dev.mars3142.fhq.timezone_service.timezone.service.TimezoneService; import dev.mars3142.fhq.timezone_service.timezone.service.TimezoneService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.springdoc.core.converters.models.Pageable; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -35,18 +34,20 @@ public class TimezoneController {
val response = new TimezoneResponse(); val response = new TimezoneResponse();
response.setTimezone(timezoneInfo.timezone()); response.setTimezone(timezoneInfo.timezone());
response.setPosix_tz(posix); response.setPosix_tz(posix);
response.add(linkTo(TimezoneController.class).slash(ip).withSelfRel());
return response; return response;
} }
@GetMapping("{area}") @GetMapping("{area}")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public LocationResponse getLocations(@PathVariable String area) { public Page<String> getLocations(@PathVariable String area,
val locations = timeZoneService.getLocations(area); @RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize,
val result = new LocationResponse(); @RequestParam(value = "page", required = false, defaultValue = "0") int page,
result.setLocations(locations); @RequestParam(value = "direction", required = false) String direction) {
result.add(linkTo(TimezoneController.class).slash(area).withSelfRel()); var pageRequest = PageRequest.of(page, pageSize);
return result; if (direction != null && !direction.isEmpty()) {
pageRequest = PageRequest.of(page, pageSize, Direction.fromString(direction), "location");
}
return timeZoneService.getPagedLocations(area, pageRequest);
} }
@GetMapping("{area}/{location}") @GetMapping("{area}/{location}")
@@ -57,7 +58,6 @@ public class TimezoneController {
val response = new TimezoneResponse(); val response = new TimezoneResponse();
response.setTimezone(timezone); response.setTimezone(timezone);
response.setPosix_tz(posix); response.setPosix_tz(posix);
response.add(linkTo(TimezoneController.class).slash(area).slash(location).withSelfRel());
return response; return response;
} }
} }

View File

@@ -1,17 +0,0 @@
package dev.mars3142.fhq.timezone_service.timezone.domain.model.response;
import java.util.List;
import lombok.Getter;
import org.springframework.hateoas.RepresentationModel;
@Getter
public class LocationResponse extends RepresentationModel<LocationResponse> {
private int count;
private List<String> locations;
public void setLocations(List<String> locations) {
this.count = locations.size();
this.locations = locations;
}
}

View File

@@ -2,11 +2,10 @@ package dev.mars3142.fhq.timezone_service.timezone.domain.model.response;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.springframework.hateoas.RepresentationModel;
@Getter @Getter
@Setter @Setter
public class TimezoneResponse extends RepresentationModel<TimezoneResponse> { public class TimezoneResponse {
private String timezone; private String timezone;
private String posix_tz; private String posix_tz;

View File

@@ -2,7 +2,8 @@ package dev.mars3142.fhq.timezone_service.timezone.service;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.IPApiResponse; import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.IPApiResponse;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.TimeApiTimezoneZoneResponse; import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.TimeApiTimezoneZoneResponse;
import java.util.List; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
public interface TimezoneService { public interface TimezoneService {
@@ -14,5 +15,5 @@ public interface TimezoneService {
String getPosixTimeZone(String timezone); String getPosixTimeZone(String timezone);
List<String> getLocations(String area); Page<String> getPagedLocations(String area, PageRequest pageRequest);
} }

View File

@@ -15,6 +15,9 @@ import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import lombok.val; import lombok.val;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatusCode; import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClient;
@@ -97,19 +100,41 @@ public class TimezoneServiceImpl implements TimezoneService {
} }
@Override @Override
@Cacheable(value = "locations", key = "{#area}") @Cacheable(value = "locations", key = "{#area, #pageRequest}")
public List<String> getLocations(String area) { public Page<String> getPagedLocations(String area, PageRequest pageRequest) {
val directory = new File("/usr/share/zoneinfo/" + area); val directory = new File("/usr/share/zoneinfo/" + area);
if (!directory.exists()) { if (!directory.exists()) {
throw new NotFoundException(); throw new NotFoundException();
} }
return Stream.of(Objects.requireNonNull(directory.listFiles())) return toPage(Stream.of(Objects.requireNonNull(directory.listFiles()))
.filter(file -> !file.isDirectory()) .filter(file -> !file.isDirectory())
.map(file -> { .map(file -> {
val path = file.getPath().split("/"); val path = file.getPath().split("/");
return path[path.length - 2] + "/" + path[path.length - 1]; return path[path.length - 2] + "/" + path[path.length - 1];
}) })
.sorted() .toList(), pageRequest);
.toList(); }
Page<String> toPage(List<String> list, PageRequest pageRequest) {
val pageSize = pageRequest.getPageSize();
val pageNumber = pageRequest.getPageNumber();
val totalPages = list.size() / pageSize;
int max = pageNumber >= totalPages ? list.size() : pageSize * (pageNumber + 1);
int min = pageNumber > totalPages ? max : pageSize * pageNumber;
var content = list.stream().sorted((left, right) -> {
if (!pageRequest.getSort().isSorted()) {
return 0;
}
if (Objects.requireNonNull(pageRequest.getSort().getOrderFor("location")).isAscending()) {
return left.compareTo(right);
} else {
return right.compareTo(left);
}
}
);
return new PageImpl<>(content.toList().subList(min, max), pageRequest, list.size());
} }
} }

View File

@@ -59,6 +59,6 @@ class TimezoneServiceImplTest {
} }
@Test @Test
void getLocations() { void getPagedLocations() {
} }
} }