Spring&Hibernate paggination - spring

i want to make pagination for my site (current just practice)
I using Spring and Hibernate. I understand that i can use Critera to retrive example 5 by 5 Person name. But how to send that to JSP page and make pagination.

You can use Spring Data for this:
interface BookRepository extends JpaRepository<Book, Integer> {
}
#RestController
class BookController {
#Autowired
BookRepository bookRepository;
#GetMapping("/books")
public Page<Book> getAllBooks(Pageable pageable){
return bookRepository.findAll(pageable);
}
}
By adding Pageable to controller method Spring adds three request parameters: page, size and sort. And request will look like: curl 'http://localhost:8080/books?page=0&size=20&sort=title%2Cdesc'
Spring automatically will create that Pageable object.
Spring Data can work with this object and returns Page<T> in response, which contains among requested entities (in content array) a lot of pagination information such as totalPages, numberOfElements.

Related

REST with Spring: Where to place logic for mapping from frontend DTO to JPA Specification and Pageable?

I want to use a rather complex DTO (from the frontend) which contains filtering and pagination parameters to map/build a Specification and a Pageable to use in query in the underlying JPA Repository. The call stack is as follows: controller -> view -> service -> repository.
What would be conceptually the cleanest approach to place the DTO-to-Specification/Pageable method(s)?
For comparison: so far, I placed it as a private method in the service class, like so (not an actual code snippet). Is that architecturally clean or would e.g. a separate class (like a FooSpecificationBuilder) be more appropriate?
#Service
public class FooService {
private final FooRepository repository;
public Page<Foo> getFooPage(FrontendSearchDto searchDto) {
Specification<Foo> spec = buildSpec(searchDto);
Pageable pageable = buildPageable(searchDto);
return repository.findAll(spec, pageable);
}
private Specification<Foo> buildSpec(FrontendSearchDto searchDto) {
// do the mapping
}
private Pageable buildPageable(FrontendSearchDto searchDto) {
// do the mapping
}
}

Returning only the first 10 record - Redis OM

I’m using Redis OM for spring boot, I am having trouble querying objects because it only returns the first 10 records.
Repository Class:
public interface RedisBillerRepository extends RedisDocumentRepository<Biller, Long> {
List<Biller> findByClientIds(String clientId);
}
Is there a way to return ALL the objects with the specific clientId? Not the first 10 only.
The only way which i found was with the interface Page. For example your Repository would look like this:
public interface RedisBillerRepository extends RedisDocumentRepository<Biller, Long> {
Page<Biller> findByClientIds(String clientId, Pageable pageable);
}
And your class could look like this
public class BillerService {
#Autowired
RedisBillerRepository redisBillerRepository;
public List<Biller> getAllClientsById(String clientId){
Pageable pageRequest = PageRequest.of(0, 500000);
Page<Biller> foundBillers = redisBillerRepository.findByClientIds(clientId, pageRequest);
List<Biller> billersAsList = foundBillers.getContent();
return billersAsList;
}
}
You have to set the limit for now.
I'm the author of the library... #member2 is correct. RediSearch currently has a default for the underlying FT.SEARCH (https://redis.io/commands/ft.search/) method of returning the first 10 records found. To override that, the only way to do so currently is to use the Pagination constructs in Spring.
I will expose a configuration parameter in upcoming versions to set the MAX globally.

How to separate PATCH and PUT swagger documentation for Spring Data Rest?

I use Spring Data Rest + Springfox (swagger). I want to provide documentation separately for PATCH and PUT but they are both mapped to one function call:
#RepositoryRestResource
public interface OrderRepository extends JpaRepository<Order, Long> {
#ApiOperation(value = "Create new order")
Order save(Order order);
}
How do I separate it into two function calls? I don't have a controller because SDR generates it.
If you need two different API documentations for each request method then you also need two separate endpoints. Use the default method feature for interfaces to enable desired functionality.
#RepositoryRestResource
public interface OrderRepository extends JpaRepository<Order, Long> {
// this method is hidden for Swagger
Order save(Order order);
#PatchMapping
#ApiOperation(value = "Partialy modify order")
default Order modify(Order order) {
return save(order);
}
#PutMapping
#ApiOperation(value = "Create new or replace existing order")
default Order update(Order order) {
return save(order);
}
}

Add custom header to REST PUT request

I have an application that uses Spring Boot 2.1.8 with an Angular front end. I have defined my repositories using #RepositoryRestResource. The Spring Boot app basically provides a REST API for the Angular piece. The application defines several business entities and the REST respo provides CRUD functionality for each entity. Here is a typical repo interface for one of those entities:
// REST resouce /api/privgroups
#RepositoryRestResource(collectionResourceRel = "privgroups", path = "privgroups")
public interface PrivGroupRepository extends CrudRepository<PrivGroup, Long>
{
List<PrivGroup> findAll();
}
GETing and single entity, POSTing (creating an entity) and PUTing (updating an entity) are all working fine, but I would like to return a custom header when updating (HTTP PUT) an entity. The header would be consumed by the Angular side to display a custom toastr message specific to that entity. Since the repositories also implement the REST interface I am unsure how to add a specific header that would change based on the target entity.
I have developed applications that include a REST controller that calls against a service which in turn calls against a repository. In this case, I have more control and can easily return custom headers like so:
#PutMapping("/{id}")
public ResponseEntity<MyEntity> updateMyEntity(#PathVariable("id") Long id, #RequestBody MyEntity myEntity)
{
MyEntity updatedEntity = this.MyEntityService.updateMyEntity(MyEntity);
return ResponseEntity.ok()
.header("X-Save", "MyEntity")
.body(updatedEntity);
}
Is there a newer "built-in" technique I can use to achieve this? I know I can add headers using a filter and I've read a couple posts on the subject. I think it would be difficult to identify the entity being updated and I'm unsure this is the best approach.
NOTE that this post:
Rest API - how add custom headers?
is really old.
The spring data rest docs https://docs.spring.io/spring-data/rest/docs/current/reference/html/
don't have anything specific on the subject.
I have used Spring Data Rest recently and I didn't find any "built-in" technique for that. However you can achieve that by implementing the ResponseBodyAdvice interface in a class annotated with #ControllerAdvice. This is how I got it:
#ControllerAdvice
public class PutMyEntityBodyAdvice implements ResponseBodyAdvice<Object> {
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// Write the condition to check if beforyBodyWrite should be called
return returnType.getParameterType().equals(ResponseEntity.class);
}
#Override
public Object beforeBodyWrite(Object object, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
// Check if it is a PUT request for MyEntity object
if (HttpMethod.PUT.equals(request.getMethod()) && object instanceof PersistentEntityResource) {
PersistentEntityResource persistentEntityResource = (PersistentEntityResource) object;
if (persistentEntityResource.getContent().getClass().equals(MyEntity.class)) {
// Add custom header or manipulate response object
response.getHeaders().add("X-Save", "MyEntity");
}
}
return object;
}
}
The answer by #pepevalbe looks promising.
An alternative might be - as you suggested - using a standard Servlet Filter or Spring HandlerInterceptor.
To address the issue of getting a reference to the modified entity in that case you could register a Spring Data Rest event listener that would simply store a reference to the modified entity in ThreadLocal storage from where it could be retrieved in the Filter or HandlerInterceptor.
https://www.baeldung.com/java-threadlocal
https://docs.spring.io/spring-data/rest/docs/current/reference/html/#events.application-listener

How is a custom derived query POST added to spring data REST?

I have a Spring data REST project I am using to learn.
Right now I want to set up a query in this repository:
#RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Long>
namely, this guy:
#RestResource(path = "login", rel = "login")
User findByUsernameAndPassword(String username, String password);
A basic repository is easy to set up. So are custom GET requests like:
List<Item> findByType(#Param("type") String type);
or
#RestResource(path = "byMaxPrice")
#Query("SELECT i FROM Item i WHERE i.price <= :maxPrice")
List<Item> findItemsLessThan(#Param("maxPrice") double maxPrice);
But these are still GET requests. I would like to use a POST request. The method = RequestMapping.POST markup isn't accepted by #RestResource .. and I dont see any mention of different request types in the documentation. how do I do this?
You need to define a custom Controller to handle POST requests. If you just want to do POST for the default Repository methods, unfortunately, you still have to make a pass through Controller
#RepositoryRestController
public class MyController implements Serializable {
...
#RequestMapping(value = "/myConstroller/myPostMethod", method = RequestMethod.POST
, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody List<MyObjects> updateMyObjectList(
#RequestBody List<MyObjects> objects) {
// Call your repository method here, or a custom service, or whatever
}
See Spring MVC docs for further information, specifically section 5.2.1, which describes the default HTTP Method support for Repositories, and 16.4, which gives a custom Controller example.
From 5.2.1:
POST
Creates a new entity from the given request body.
Thus, POST is supported, but not to do what you are trying to do. If you want to "hide" URL parameters by using POST instead of GET, you need a custom Controller.

Resources