How to get the next page on spring pagination - java

I have a resource in my service with pagination and I would like to know how could I process the next request to get the second page.
Here is the java resource:
#GetMapping(value = "/partner/codes")
public Page<String> getCodes(#PageableDefault(size = 5) Pageable pageable) {
final List<String> userIds = service.getIds();
int start = pageable.getOffset();
int end = (start + pageable.getPageSize()) > userIds.size() ? userIds.size() : (start + pageable.getPageSize());
return new PageImpl<String>(userIds.subList(start, end), pageable, userIds.size());
}
And the response the response with 5 results:
{
"content":[
"4a136aa6-00d4-44f0-bb48-d192fd8bc010",
"bebebaf2-b881-4733-8a65-1ecf80b5192e",
"1a0f9d07-1393-48a8-8883-37d87681e84b",
"d2580fdc-db6c-4fa3-89d4-2b52898a20bf",
"2c90e683-4ed4-45a4-b70b-614a3339670b"
],
"last":false,
"totalPages":3,
"totalElements":57,
"size":20,
"number":0,
"sort":null,
"numberOfElements":20,
"first":true
}

I'm sorry, as there was nothing explicit in the documentation, I hadn't noticed that just passing the parameters in the query string.
?page=2&size=20
And the client should create the rule using the response message.

Related

Using Object class as wrapper for input in spring boot RestController

I am bit new to spring boot and I am trying to design a search on user history which will provide 3 attributes to search user history {userId, searchKey, SearchValue}.
The search value datatype may differ based on search.
E.g
Userid=100, SearchKey=userAddress, searchValue='10 Downing Street'
Userid=100, SearchKey=external, searchValue=true
Userid=100, SearchKey=companyId, searchValue=25
I am trying to design a rest endpoint as below. This endpoint will integrate with react front end.
#GetMapping(value = "/searchUserHistoryByKeyValue")
public ResponseEntity<Object> searchUserHistoryByKeyValue(
#RequestParam(value = "userId") int userId,
#RequestParam(value = "searchKey") String searchKey,
#RequestBody Object searchValue) {
List<org.json.simple.JSONObject> entities =
userHistoryService.searchUserHisotryByKeyValue(userId, searchKey, searchValue);
return new ResponseEntity<>(entities, HttpStatus.OK);
}
I have implemented a dynamodb search on userhistory object which takes input as generic searchValue object as search filter as below.
Dynamo DB Querying - https://www.tutorialspoint.com/dynamodb/dynamodb_querying.htm
public List<JSONObject> searchUserHistoryByKeyValue(
int userId, String searchKey, Object searchValue) throws DataAccessException {
Table table = dynamoDB.getTable(userHistoryTable.getName());
Map<String, String> expressionAttributeNames =
DEFAULT_USER_FILTERS.stream()
.collect(
Collectors.toMap(attrib -> attrib, attrib -> attrib.substring(1), (a, b) -> b));
Optional<String> projectionExpression =
createProjectionExpression(
Collections.singletonList(searchKey), expressionAttributeNames);
Optional<String> filterProjectionExpression =
buildCustomProjectionExpression(
Collections.singletonList(searchKey), expressionAttributeNames);
QuerySpec querySpec =
new QuerySpec()
.withProjectionExpression(projectionExpression.orElse(StringUtils.EMPTY))
.withKeyConditionExpression("#userId = :userId")
.withFilterExpression(
String.format(
"%s = :searchValue",
filterProjectionExpression.orElseThrow(
() -> new IllegalArgumentException("Invalid Search Attributes"))))
.withNameMap(expressionAttributeNames)
.withValueMap(Map.of(":userId", userId, ":searchValue", searchValue))
.withScanIndexForward(false);
When I am trying use swagger or postman to test this endpoint , I am not able to pass in
#RequestBody Object searchValue . it just shows as empty braces - {}
Also it shows below error as -
'TypeError: Failed to execute 'fetch' on 'Window': Request with
GET/HEAD method cannot have body. '
I am not able to make this work? Appreciate your insights on this.
It's HTTP protocol.
You cannot pass any body object with the Get method. You have to use Post or Put method for using a body in HTTP request.
#RequestBody not for single value it is intended for your custom object that is used with POST or PUT but in you case you can #RequestParam also if #RequestParam take attribute required with boolean vlue which tell your endpoint caller which params is optional if you set it False and which is required if you set it True

Pagination in CosmosDB Java SDK with continuation token

I'm trying to create from an async client a method to retrieve items from a CosmosDB but I'm afraid I'm full of questions and little to no documentation from Microsoft side
I've created a function that will read from a cosmosDB a list of items, page by page, which continuation will depend on a continuityToken. The methos looks like this. Please, be aware there could be some minor mistakes non related to the core functionality which is reading page by page:
#FunctionName("Feed")
public HttpResponseMessage getFeed(
#HttpTrigger(
name = "get",
methods = { HttpMethod.GET },
authLevel = AuthorizationLevel.ANONYMOUS,
route = "Feed"
) final HttpRequestMessage<Optional<String>> request,
#CosmosDBInput(
name = "Feed",
databaseName = Constants.DATABASE_NAME,
collectionName = Constants.LOG_COLLECTION_NAME,
sqlQuery = "SELECT * FROM c", // This won't be used actually as we use our own query
connectionStringSetting = Constants.CONNECTION_STRING_KEY
) final LogEntry[] logEntryArray,
final ExecutionContext context
) {
context
.getLogger()
.info("Query with paging and continuation token");
String query = "SELECT * FROM c"
int pageSize = 10; //No of docs per page
int currentPageNumber = 1;
int documentNumber = 0;
String continuationToken = null;
double requestCharge = 0.0;
// First iteration (continuationToken = null): Receive a batch of query response pages
// Subsequent iterations (continuationToken != null): Receive subsequent batch of query response pages, with continuationToken indicating where the previous iteration left off
do {
context
.getLogger()
.info("Receiving a set of query response pages.");
context
.getLogger()
.info("Continuation Token: " + continuationToken + "\n");
CosmosQueryRequestOptions queryOptions = new CosmosQueryRequestOptions();
Flux<FeedResponse<LogEntry>> feedResponseIterator =
container.queryItems(query, queryOptions, LogEntry.class).byPage(continuationToken,pageSize);
try {
feedResponseIterator.flatMap(fluxResponse -> {
context
.getLogger()
.info("Got a page of query result with " +
fluxResponse.getResults().size() + " items(s)"
+ " and request charge of " + fluxResponse.getRequestCharge());
context
.getLogger()
.info("Item Ids " + fluxResponse
.getResults()
.stream()
.map(LogEntry::getDate)
.collect(Collectors.toList()));
return Flux.empty();
}).blockLast();
} catch (Exception e) {
}
} while (continuationToken != null);
context
.getLogger()
.info(String.format("Total request charge: %f\n", requestCharge));
return request
.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "application/json")
.body("ALL READ")
.build();
}
For simplicity the read items are merely logged.
First question: We are using an async document client that returns a Flux. Will the client keep track of the token? It is a stateless client in principle. I understand that the sync client could take easily care of this case, but wouldn't the async client reset its memory of tokens after the first page and token has been generated?
Second: Is the while loop even appropriated? My assumption is a big no, as we need to send back the token in a header and the frontend UI will need to send the token to the Azure Function in a header or other similar fashion. The token should be extracted from the context then
Third: Is the flatMap and blockList way to read the flux appropriate? I was trying to play with the subscribe method but again I don't see how it could work for an async client.
Thanks a lot,
Alex.
UPDATE:
I have observed that Flux only uses the items per page value to set the number of items to be retrieved per batch, but after retrieval of one page it doesn't stop and keeps retrieving pages! I don't know how to stop it. I have tried substituting the Flux.empty() per Mono.empty() and setting a LIMIT clause in the sql query. The first option does the same and the second freezes the query and never returns apparently. How can I return one page an only one page along with the continuation token to do the following query once the user clicks on the next page button?

Spring Pageable object in get request from React using Axios

I have an endpoint looking like this
#GetMapping("/page") Page<Event> getEventPage( #PageableDefault(page = 0, size = 20) #SortDefault(sort = "createdDateTime", direction = Sort.Direction.DESC) Pageable pageable)
How am I supposed to pass the Pageable object from my React frontend using Axios, I got this so far:
fetchEvents(pageable) {
return axios.get("http://localhost:8080/api/events/page", pageable, this.setupAxiosInterceptors());
}
Where pageable is the last fetched page. Now it just resorts to the default values.
You simply do this by adding query parameters to the url. Like http://localhost:8080/api/events/page?page=1&size=20
The axios way to do this would be something like this:
const querystring = require('querystring');
axios.get('http://localhost:8080/api/events/page', querystring.stringify({ page: 1, size: 20 }));

get 400K data from tables in Spring MVC within some sec

I'm using Spring MVC and I need to get more than 400k datas by my table where i also using JOIN in mysql query.
What I actually have is a Controller that returns which contains a List. I call the Controller using AJAX.
The problem with my solution is that I'm not able to get the data of List with in seconds it take more than 5 minutes to load on JSP page.
In page Jquery..
$(document).ready(function ajaxPost() {
$.ajax({
type: "GET",
data: page,
url: "allListAjax",
success: function(list) {
//here i get responce list and page which takes 5 minutes
}//success
}//ajax
}//ready
In Controller..
#RequestMapping(value="/allListAjax")
public #ResponseBody IVRRouteReportWrapper dashoardAjax(Model model, #RequestParam(required = false) Integer page) {
IVRRouteReportWrapper wrappObj= new IVRRouteReportWrapper();
List<IVRRouteReport> list = ivrRouteServiceInterface.getAllIVRRouteReport(page);
wrappObj.setIVRouteReportList(list);
wrappObj.setPage(page);
return wrappObj;
}
here, IVRRouteReportWrapper is a Domain model which contains setters and getters of List and page.
In Service Implementation...
public List<IVRRouteReport> getAllIVRRouteReport(Integer page) {
return ivrRouteDAOInterface.getAllIVRRouteReport(page);
}
In Dao Implementation...
public List<IVRRouteReport> getAllIVRRouteReport(Integer page) {
if(page==null) {
page = 0;
}else {
page = page*200;
}
String strqry= "SELECT c.caller_id_number as caller_id_number, c.destination_number as destination_number,"
+" c.created_time as created_time, vbDtmf.digit as dtmf FROM VoiceBroadcastDTMF vbDtmf "
+"LEFT JOIN cdr c ON vbDtmf.uuid=c.orig_id ORDER BY c.created_time DESC";
Query query = getSession().createSQLQuery(strqry)
.addScalar("caller_id_number", new StringType())
.addScalar("destination_number", new StringType())
.addScalar("created_time", new StringType())
.addScalar("dtmf", new StringType())
.setResultTransformer(Transformers.aliasToBean(IVRRouteReport.class))
.setFirstResult(page)
.setMaxResults(200);
List<IVRRouteReport> ivrRouteReportList =(List<IVRRouteReport>) query.getResultList();
getSession().flush();
return ivrRouteReportList;
}
Is there any way to return this List Fast on jsp page ? Thanks in advance.
Index the "created_time" column and also omit not required fields by specifying only the required fields in the query as below
String strqry= "SELECT c.caller_id_number as caller_id_number, c.destination_number as destination_number,"
+" c.created_time as created_time, vbDtmf.digit as dtmf FROM VoiceBroadcastDTMF vbDtmf "
+"LEFT JOIN (SELECT caller_id_number , destination_number , created_time FROM cdr) as c ON vbDtmf.uuid=c.orig_id ORDER BY c.created_time DESC";
Go for pagination.
Refer spring-mvc-pagination

How to set communicate spring with server in RestController

From the client to the server is sended json, which have the value - the page number that is required to be imaging for user in client side, page by page:
19 17 * * * curl -d '{"explorerId":'1', "pageNumber":'1',"turnOff":true}' -H "Content-Type: application/json" -X POST http://localhost:8080/types
I have method, which get to client large list of entities. In method I split him (using pageNumber value and question to database) and want return to client page by page.
#RestController
public class WPRestController extends GeneralController {
private final int COUNT_VALUE = 50;
#RequestMapping(value = "/types")
public Page typeprocess(#RequestBody PostTemplate postTemplate) {
long pageNumber = postTemplate.getPageId() - 1;
List<Words> wordsList = getWordsListOffset(postTemplate.getExplorerId(), pageNumber, COUNT_VALUE);
int[] count = new int[]{1};
String result = wordsList.stream()
.map(p -> (count[0]++) + " " + p.toString())
.collect(Collectors.joining("\n"));
Page page = new Page();
page.setNumber(pageNumber++);
page.setContent(result);
return result;
}
}
How to make is so, that user on client side, pressed key and resend query to server?
i.e. - client must to get the content, also get pageNumber value and resend him in curl query automatically.
It is possible?

Categories

Resources