I'm new with Spring Data and Spring MVC and I don't understand why am I getting empty content:
#RequestMapping(value="/pages", method=RequestMethod.GET)
#ResponseBody
public Page<Client> contactsPages(#RequestParam int page, #RequestParam int size) {
Pageable pageable = new PageRequest(page, size, new Sort("id"));
Page<Client> pageResult = clientRepository.findAll(pageable);
return pageResult;
}
The result of my json when I test the url is:
{"content":[],"last":true,"totalElements":2,"totalPages":1,"size":5,"number":1,"sort":[{"direction":"ASC","property":"id","ignoreCase":false,"nullHandling":"NATIVE","ascending":true}],"first":false,"numberOfElements":0}
And if you have good example making pageable request using Spring Data and Spring MVC and AngularJS; It will be a big help for me.
Ensure that your PageRequest object is requesting 0 for small sets, not 1.
The pagination begins from 0.
This is a common mistake for beginners and is a common redherring when using #Query in conjunction with Spring pagination. If your #Query works without pagination and then returns nothing when using it, check the page number.
I had a similar issue and with mine it was due to the fact that I modify the data after doing a select such that the modified field is the same field I use for searching. This means each time I run the query it will match less and less records so page zero will always have new data, so in that instance using page 0 always will not hurt as new records will always fill page zero. In the other instance I did not modify the search field and my query will match the same records each time I execute my select statement so in this instance requesting the exact page was important.
Dharman's answer helps me find out the reason.
If you use pagination to get data from DB, and also you update the search field after you retrieve it, then the page info will get messed up.
Related
I am working on a spring boot app where I have multiple fetch apis which are basically filter apis taking in params and sending response from db.
Now under load they are acting pretty slow,Is there any way I can fasten these with cache?
Can filter apis results be cached? as they may have different filters everytime.
Currently I did this:
#Cacheable(value = "sku-info-cache", unless = "#result == null")
public SkuGroupPagedResponseMap fetchSkuGroupsByDatesAndWarehouseId(Integer warehouseId,
Integer pageNumber,
Integer pageSize,
String startDate,
String endDate){
log.info("fetching from db");
SkuGroupPagedResponseMap skuGroupPagedResponseMap = locationInventoryClientService.fetchSkuGroupsByDatesAndWarehouseId(warehouseId,pageNumber,pageSize,startDate,endDate);
updateLotDetailsInSkuGroup(skuGroupPagedResponseMap);
return skuGroupPagedResponseMap;
}
The best way to handle this particular scenario is using a smart key. As per your case, you can make a smart key using the combination of requested filter parameters which will lead to formation of 5! combination of keys (in your case) which can be updated at time of database update using prefix deletion strategy of cache update and hence proves to be very fast. I have tried this and found to be very fast.
I am currently doing migration from spring data elastic search 3.2.X to 4.0.0.
I had been relying on obtaining inner hits result through raw SearchResponse class by utilizing the now deprecated low level function org.springframework.data.elasticsearch.core.ElasticsearchOperations.query(SearchQuery query, ResultsExtractor resultsExtractor);
https://docs.spring.io/spring-data/elasticsearch/docs/4.0.0.RELEASE/reference/html/#elasticsearch-migration-guide-3.2-4.0
Basically what I did was creating custom resultExtractor which will expose the low level SearchResponse so that I could then extract the inner hits result.
Now with version 4.0.0 that functionality is no longer there, Both ElasticSearchOperations and ElasticSearchRestTemplate utilize new result class called SearchHits which AFAIK does not store inner hits information.
The workaround I could think of besides using the restHighLevelClient directly (which of course is undesirable since I'd lose the object mapping and stuff) is to extend ElasticSearchRestTemplate and basically creating new implementation of search(Query query, Class clazz, IndexCoordinates index) which will return SearchHits and the raw search response (similar to what my custom ResultExtractor used to do).
Afterwards, since all api returning page instance has been deprecated, I would now have to rely on SearchHitSupport.searchPageFor(SearchHits searchHits, #Nullable Pageable pageable) to get the usual paging functionalities.
I felt that this is not very straightforward and clean solution and certainly felt more like a workaround. Would there be any more straightforward way to obtain innerHitsResult and map result content to page at version 4.0.0?
There is an open issue about inner_hits. Returning the inner_hits should be done in the SearchHit<T> class and not by exposing internal Elasticsearch data.
As for the paging: When you have a SearchHits<T> object as the result of a query that use a Pageable, you can call
SearchHits<Entity> searchHits = operations.search(query, Entity.class);
SearchPage<Entity> page = SearchHitSupport.searchPageFor(searchHits, query.getPageable)
SearchPage implements the Page interface.
Edit:
The issue is fixed, inner hits are returned from the next version (4.1) on.
Utilizing the Spring Framework's Page interface I'm able to retrieve 50 users at a time with the code below:
int page = 0;
int pageSize = 50;
Page<User> userPage = userRepo.findByFirstName("Bob", page, pageSize);
List<User> userList = userPage.getContent();
This runs some query in the background to give me my first 50 users in my database. What I want to do is populate my userList without paging so that every is returned from the underlying query - is this possible?
I've tried the hasNext() method on my Page object but it runs in an endless loop
while(userPage.hasNext()){
logger.info("Next page found");
}
Any ideas?
If you don't want paging you can ignore spring Page and directly call userRepo.findByFirstName("Bob");
This will return all users in database whose firstName is bob
Your method signature should be
List<User> users = userRepo.findByFirstName("Bob");
Hope this solves your question
If you always want all users and not them by page, you need to adjust this on the Repository side. Change the signature of findByFirstName to return List<User> instead of Page<User>, and remove the Pageable parameter. Then, it will always return all. See more information on how parameters are handled in the Spring Data documentation.
If you need to sometimes paginate and sometimes get all data, then just add the List<User> version. The return type will depend on whether you pass a Pageable parameter or not based on Java's usual overloading.
The hasNext() method on Page merely tells you if a next page is available (for use in presenting navigation), it doesn't run another query. You would need to construct a new Pageable object and iterate through several calls to the Page<User> version in order to access all data through the Pageable interface, which is less efficient than just querying for what you actually want in the first place.
I have a Spring CrudRepository called 'ImportReceiptRepository'.
I'm simply trying to compose a method which grabs the first row in an order by clause.
Here's what I'm using currently:
ImportReceipt importReceipt = this.importReceiptRepository.getOneByImportTypeOrderByTimestampDesc(importType);
The issue is that when there is more than a single row returned, Spring throws a:
org.springframework.dao.IncorrectResultSizeDataAccessException: result returns more than one elements; nested exception is javax.persistence.NonUniqueResultException: result returns more than one elements
How should I rename this CrudRepository function to simply grab the first row when there are 0-n rows returned?
Simply using Pageable was the key:
List<ImportReceipt> findByImportType(String importType, Pageable pageable);
and calling it like:
List<ImportReceipt> importReceipts = this.importReceiptRepository.findByImportType(importType, new PageRequest(0, 1, Direction.DESC, "Timestamp"));
ImportReceipt importReceipt = importReceipts.get(0);
Credit: How to combine pagination with a criteria query in Spring Data JPA?
You can make it even simpler by findFirst:
ImportReceipt findFirstByImportType(String importType);
For more info: Limiting Query Results
As of the upcoming version 1.7 of Spring Data JPA, the query method as you originally declared it works out of the box. See this ticket for details. The support has already been published in the first milestone of the release.
Hi all question I'm having problems finding an answer for...
Use Case:
Reading in an Excel spreadsheet in a controller. A 4 row sheet was processed and row 2 and 3 had some errors in it, so I skip them and move on with the rest of the processing. But I want to retain these rows to display to the user after the processing is complete. I'd like to retain all the values in the row to display back to the user just to provide enough information.
So what I tried to do was this:
#RequestMapping(value = "/bulk-create", method = RequestMethod.POST)
public String bulkCreate(Model model, SpreadSheetFile spreadSheetFile){
...some code...
List<Row> errorRows = new LinkedList<Row>();
...some code to process rows...
//Error Found
errorRows.add(row);
...more code to wrap up processing (possibly more errors)...
model.addAttribute("erroRows", errorRows);
return "redirect:/bulk-review"
}
#RequestMapping(value = "/bulk-review", method = RequestMethod.GET)
public String bulkReview(Model model,
#ModelAttribute("errorRows")
LinkedList<Row> errorRows){
model.addAttribute("errorRows", errorRows);
return "bulk-review";
}
So basically I'm trying to pass a LinkedList from one MVC method to another without actually hitting a page first (unless I'm misunderstanding how "redirect:" works... it calls the controller method first correct?)
When I but a break point into the bulkReview method, errorRows is empty... So how do I retain this value between the two methods?
Thanks for the help! Let me know if I need to clarify anything! :)
Kris
I don't think the redirect mechanism works the way you think it does. The first controller sends back a URL to the user's browser which the browser then follows. And by default, Spring places any data in the model at the time of a redirect in the redirect URL, so that the page-being-redirected to can "see" the model data. However, this doesn't work well when you have complex data in the model.
So, you need to think about how the data will be passed in the redirect URL that the browser sends back to the user. How does a List get serialized to the URL? probably not very well.
Another option would be to put the data in session from one controller and access it in the second.