multiple requestparam in springboot pageable - spring-boot

i know that this question may be duplicated but i tried a lot with no success
I need to make multiple RequestParam in spring boot rest controller as following :
#GetMapping("/prd-products/test")
#Timed
public ResponseEntity<List<Test>> getAllTests(#RequestParam (required = false) String search, #RequestParam (required = false) Pageable pageable) {
Page<Test> page = prdProductsService.findAllTest(search, pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/prd-products");
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
when i try to call this service by url like :
http://localhost:9116/api/prd-products/test?search=id==1,id==2&pageable=0&size=2
it give me following error
"title": "Bad Request",
"status": 400,
"detail": "Failed to convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.data.domain.Pageable': no matching editors or conversion strategy found",
when i try to send one request param it successfully work .
Note : id==1,id==2 is the way that fields is parsed in search

With Spring Boot you can just register PageableHandlerMethodArgumentResolver bean
#Bean
public PageableHandlerMethodArgumentResolver pageableResolver() {
return new PageableHandlerMethodArgumentResolver();
}
In controller
public ResponseEntity<List<Test>> getAllTests(
#RequestParam (required = false) String search,
#PageableDefault(page = 0, size = 100) Pageable pageable
) {
...
}
And then adjust your query parameters to
...&page=0&size=2

Spring cannot convert a String to a Pageable. You should create a Pageable object from the request parameters, for example, with PageRequest.of.
Example:
#GetMapping("/prd-products/test")
#Timed
public ResponseEntity<List<Test>> getAllTests(
#RequestParam (required = false) String search,
#RequestParam (required = false) Integer pageIndex,
#RequestParam (required = false) Integer pageSize) {
Pageable pageable = PageRequest.of(pageIndex, pageSize);
Page<Test> page = prdProductsService.findAllTest(search, pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/prd-products");
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}

Your QueryString seems strange.
In order to use Spring Data REST to create and inject a Pageable, you need to do something like this:
?page=0&size=2&ids=1,2
Your REST Controller:
public ResponseEntity <List<Test>> getAllTests(#RequestParam(required = false) String search, #RequestParam(required = false) Pageable pageable) {
Page<Test> page = prdProductsService.findAllTest(search, pageable);
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
This way, Spring Data REST will create a Pageable object.
See reference documentation.

Related

Creating custom requestParam in springboot controller

i have a use case where the user can send following params with get request
GET localhost/8080/users?filter=alex
OR
GET localhost/8080/users?suffixFilter=lex
OR
GET localhost/8080/users?prefixFilter=a
is it possible to add only one request param instead of 3 in controller
e.g.
instead of
#GetMapping("/users")
#ResponseBody
public String getFoos(#RequestParam String filter, #RequestParam String prefixFilter , #RequestParam String suffixFilter) {
return "ID: " + id;
}
is it possible to create a dynamic one which includes those three variantes? I was thinking creating class like this
public class FilterCreteria {
private String filter;
private String suffixFilter;
private String prefixFilter;
}
and then passing this to controller
#GetMapping("/users")
#ResponseBody
public String getFoos(#RequestParam FilterCreateria filter) {
return "ID: " + id;
}
the problem is if i send filter=alex the other attributes in the class FilterCreteria is null and i want to avoid this null.
What i searching for:
is there other way of making this possible?
if my suggestion is ok, how to avoid null attributes when the user only sends one queryparam like filter=alex?

With spring-data-elasticsearch and searching for similar documents, how to get similarity score?

I am using the latest version of elasticsearch (in docker) and a spring boot (latest version) app where I attempt to search for similar documents. My document class has a String field:
#Field(
name = "description",
type = FieldType.Text,
fielddata = true,
analyzer = "icu_analyzer",
termVector = TermVector.with_positions_offsets,
similarity = Similarity.BM25)
private String description;
I get plenty of results for my query when I use the built-in searchSimilar method:
public Page<BookInfo> findSimilarDocuments(final long id) {
return bookInfoRepository.findById(id)
.map(bookInfo -> bookInfoRepository.searchSimilar(bookInfo, new String[]{"description"}, pageable))
.orElse(Page.empty());
}
However, I have no idea how similar the documents are, because it is just a page of my Document object. It would be great to be able to see the similarity score, or to set a similarity threshold when performing the query. Is there something different that I should be doing?
I just had a look, the existing method Page<T> searchSimilar(T entity, #Nullable String[] fields, Pageable pageable) was added to the ElasticsearchRepository interface back in 2013, it just returns a Page<T> which does not contain any score information.
Since Spring Data Elasticsearch version 4.0 the score information is available and when you look at the implementation you see that it is stripped from the return value of the function in order to adhere to the method signature from the interface:
public Page<T> searchSimilar(T entity, #Nullable String[] fields, Pageable pageable) {
Assert.notNull(entity, "Cannot search similar records for 'null'.");
Assert.notNull(pageable, "'pageable' cannot be 'null'");
MoreLikeThisQuery query = new MoreLikeThisQuery();
query.setId(stringIdRepresentation(extractIdFromBean(entity)));
query.setPageable(pageable);
if (fields != null) {
query.addFields(fields);
}
SearchHits<T> searchHits = execute(operations -> operations.search(query, entityClass, getIndexCoordinates()));
SearchPage<T> searchPage = SearchHitSupport.searchPageFor(searchHits, pageable);
return (Page<T>) SearchHitSupport.unwrapSearchHits(searchPage);
}
You could implement a custom repository fragment (see https://docs.spring.io/spring-data/elasticsearch/docs/4.2.6/reference/html/#repositories.custom-implementations) that provides it's own implementation of the method that returns a SearchPage<T>:
public SearchPage<T> searchSimilar(T entity, #Nullable String[] fields, Pageable pageable) {
Assert.notNull(entity, "Cannot search similar records for 'null'.");
Assert.notNull(pageable, "'pageable' cannot be 'null'");
MoreLikeThisQuery query = new MoreLikeThisQuery();
query.setId(stringIdRepresentation(extractIdFromBean(entity)));
query.setPageable(pageable);
if (fields != null) {
query.addFields(fields);
}
SearchHits<T> searchHits = execute(operations -> operations.search(query, entityClass, getIndexCoordinates()));
SearchPage<T> searchPage = SearchHitSupport.searchPageFor(searchHits, pageable);
return searchPage;
}
A SearchPage<T> is a page containing SearchHit<T> instances; these contain the entity and the additional information like the score.

Spring MVC forward appending request parameter values comma separated when we have same parameter name for topRequest and forward request

Spring MVC forward appending request parameter values comma separated when we have same parameter name for topRequest and forward request
#RequestMapping(path = "/details")
public ModelAndView details(#ModelAttribute final DetailsForm detailsForm){
//DetailsForm contain a parameter called destinationId with value 1234
final ModelAndView mav = new ModelAndView();
//Some logic to get targeted destinationId (7890) using destinationId (1234) from detailForm
mav.setViewName("forward:/search?destinationId=7890");
return mav;
}
#RequestMapping(path = "/search")
public ModelAndView details(#ModelAttribute final SearchForm searchForm){
//Here I tried to get destinationId from model-attribute searchForm
final Integer destinationId = searchForm.getDestinationId();
//Then it returned me 1234,7890
}
Can someone please help me out how to resolve this. I want to get only 7890.
I am interested in the answer also. I also hit this problem hacked it by adding a method:
private String getLastPartFromFormValue(final String value) {
if (value == null)
return null;
String[] parts = value.split(",");
return parts[parts.length -1];
}
Just for sake of knowledge.
If you have a method, and you have a query param named thing and have an object annotated with #ModelAttribute and, in that object you have a field with the same name of your query param, you can expect that behavior.
For example:
#PostMapping(value = "/my-awesome-path")
public String myAwesomeMethod(
#RequestParam(name = "token", required = false) final String token,
#ModelAttribute("formData") final MyFormData formData) {
//class fields and members...
And, in the MyFormData you have this:
public class MyFormData{
private String token;
//other fields, getters and setters...
You will receive the query param token with the value duplicated and comma separated as well as in the MyFormData object.
The alternative is check the casuistic and change the parameter name or redesign if it's necessary.
In the example the query param name is changed like this:
#PostMapping(value = "/my-awesome-path")
public String myAwesomeMethod(
#RequestParam(name = "custom-token", required = false) final String customToken,
#ModelAttribute("formData") final MyFormData formData) {
//class fields and members...
And the values are not more duplicated nor comma separated.
Cheers.

Springboot JPA Pageable not working for page number greater then 0

I want to get the Results Paginated, The below code works fine if the request is made with page parameter set to 0 but it doesn't work for page>0 like page=1 or page=2 or page=3 etc.
Here is my RequestMapping
MyResponse getSample(#ModelAttribute MyRequest MyRequest) {
Pageable pageRequest = new PageRequest(MyRequest.page, MyRequest.size)
MyModule.findSamples(MyRequest, pageRequest)
}
class MyRequest {
MyQueryType queryType
String searchTerm
#Min(value = 0L, message = 'Offset must be greater than or equal to 0')
int offset = 0
#Min(value = 0L, message = 'Offset must be greater than or equal to 0')
int page = 0
#Min(value = 1L, message = 'Limit must be greater than or equal to 1')
int limit = 100
#Min(value = 1L, message = 'Limit must be greater than or equal to 1')
int size = 5
}
MyModule:Code inside my Module
MyResponse findSamples(MyRequest MyRequest, Pageable pageRequest) {
log.info("Page Information Set "+pageRequest.pageNumber+pageRequest.pageSize)
Page<SamplesPO> pages = null
pages = MyRepository.findAllById(MyRequest.Id, pageRequest)
}
Repository Code:
public interface SampleRepository extends JpaRepository<Sample, Long> {
#Query('''
select e.Samples
from ParentSampleTable e
where e.Id = :Id
''')
Page<Sample> findAllById(#Param('Id') String Id, Pageable pageRequest)
}
Read PageRequest java docs before Using below code. PageRequest
request works on page number(starts from index 0 to 1,2,3 and so
on) and the size( limit you want)
Sort sort = new Sort(Sort.Direction.DESC, "mfgDate");
Pageable pageable = new PageRequest(pageNumber, pageSize, sort);
#Repository
public interface BikeRepository extends MongoRepository<Bike, String> {
Page<Bike> findByCompanyId(String companyId, Pageable pageable);
}
You could try extracting the id with #PathParam
Method getSample annotated with #GetMapping with params (#PathParam("id") String id, Pageable pageable) and it could return sampleRepository.findAllById(id, pageable)
Url might look like: /samples/id?page=pageNr&size=nrOfElemOnPage
Your repository should return
Page<Sample> findAllById(String id, Pageable pageable)
Also please consider refactoring(indention) the code before posting it to stackoverflow
Also this might be a duplicate: Using findAll PagingAndSortingRepository with filter

Spring rest controller and paging

I use spring 4.2 and rest and I would like to use paging.
What is the way to use paging with spring rest controller?
#RequestMapping(value = "/members/{memberId}/payments", method = RequestMethod.GET)
public Page<PaymentDto> getPaymentByMemberId(#PathVariable("memberId") Long memberId, Pageable pageable) {
return paymentService.getPaymentByMemberId(memberId, pageable);
}
Is it a good way to manage this?
If for some area in the application, we don't want to use paging, We need to create another url?
if I want all payments for a member, I will do:
/members/{memberId}/payments
and for the paging, it's there a way to said to spring to do something like:
/members/{memberId}/payments?pageNumber=1&PageSize=10
One way to do this is:
#RequestMapping(value = "/members/{memberId}/payments", method = RequestMethod.GET)
public List<PaymentDto> getPaymentByMemberId(#PathVariable("memberId") Long memberId, #RequestParam(value = "pageNumber", required = false) final Integer pageNumber,#RequestParam(value = "pageSize", required = false) final Integer pageSize) {
PageRequest pageReq = new PageRequest((pageNumber == null ? 0 : pageNumber), (pageSize == null ? 0 : pageSize));
Page<PaymentDto> page = paymentService.getPaymentByMemberId(memberId, pageReq);
return page.getContent();
}
You need write annotation #RestController for your controller
#RestController
public class PaymentController {
...
#RequestMapping(value = "/members/{memberId}/payments", method = RequestMethod.GET)
public Page<PaymentDto> getPaymentByMemberId(#PathVariable("memberId") Long memberId, Pageable pageable) {
return paymentService.getPaymentByMemberId(memberId, pageable);
}
}
Request example: /members/12345/payments?page=0&size=50

Resources