How to do paged request - Spring boot - java

in my system (Spring boot project) I need to make a request to every 350 people that I search for my data, I need to page and go sending. I looked for a lot of ways to do it and found a lot of it with JPA but I'm using Jooq, so I asked for help with the user's tool and they guided me to use the options of limit and offset.
This is the method where I do the research, I set up my DTO and in the end I return the list of people.
public static ArrayList getAllPeople(Connection connection) {
ArrayList<peopleDto> peopleList = new ArrayList<>();
DSLContext ctx = null;
peopleDto peopleDto;
try {
ctx = DSL.using(connection, SQLDialect.MYSQL);
Result<Record> result = ctx.select()
.from(people)
.orderBy(people.GNUM)
.offset(0)
.limit(350)
.fetch();
for (Record r : result) {
peopleDto = new peopleDto();
peopleDto.setpeopleID(r.getValue(people.GNUM));
peopleDto.setName(r.get(people.SNAME));
peopleDto.setRM(r.get(people.SRM));
peopleDto.setRG(r.get(people.SRG));
peopleDto.setCertidaoLivro(r.get(people.SCERT));
peopleDto.setCertidaoDistrito(r.get(people.SCERTD));
peopleList.add(peopleDto);
}
} catch (Exception e) {
log.error(e.toString());
} finally {
if (ctx != null) {
ctx.close();
}
}
return peopleList;
}
This search without the limitations returns 1,400 people.
The question is how do I send up the limit number then return to this method to continue where I left off last until I reach the total value of records?

Feed your method with a Pageable parameter and return a Page from your method. Something along the lines of ...
public static ArrayList getAllPeople(Connection connection, Pageable pageable) {
ArrayList<peopleDto> peopleList = new ArrayList<>();
DSLContext ctx = null;
peopleDto peopleDto;
try {
ctx = DSL.using(connection, SQLDialect.MYSQL);
Result<Record> result = ctx.select()
.from(people)
.orderBy(people.GNUM)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
for (Record r : result) {
peopleDto = new peopleDto();
peopleDto.setpeopleID(r.getValue(people.GNUM));
peopleDto.setName(r.get(people.SNAME));
peopleDto.setRM(r.get(people.SRM));
peopleDto.setRG(r.get(people.SRG));
peopleDto.setCertidaoLivro(r.get(people.SCERT));
peopleDto.setCertidaoDistrito(r.get(people.SCERTD));
peopleList.add(peopleDto);
}
} catch (Exception e) {
log.error(e.toString());
} finally {
if (ctx != null) {
ctx.close();
}
}
return new PageImpl(peopleList, pageable, hereyoushouldQueryTheTotalItemCount());
}
Now you can do something with those 350 Users. With the help of the page you can now iterate over the remaining people:
if(page.hasNext())
getAllPeople(connection, page.nextPageable());
Inspired by this article Sorting and Pagination with Spring and Jooq

Related

Modify HashMap when CompletableFuture is finished

I have a multi-module system, where one module handles my database storage. This is the method which saves a document:
public CompletableFuture<?> runTransaction() {
return CompletableFuture.runAsync(() -> {
TransactionBody txnBody = (TransactionBody<String>) () -> {
MongoCollection<Document> collection = transaction.getDatabase().getCollection(transaction.getCollection().toString());
collection.insertOne(session, Document.parse(json));
return "Completed";
};
try {
session.withTransaction(txnBody);
} catch (MongoException ex) {
throw new UncheckedMongoException(ex);
}
});
}
the json instance is passed down in the object constructor. However, since this will be used by several modules, with each individual caching system, I'm trying to figure out how the caller can modify data structure, if this method completed without any errors.
For example
public void createClan(Transaction transaction, int id, int maxPlayers) {
MongoTransaction mongoTransaction = (MongoTransaction) transaction;
Clan clan = new Clan(id, maxPlayers);
String json = gson.toJson(clan);
TransactionExecutor executor = new MongoTransactionExecutor(mongoTransaction, json);
executor.runTransaction(); //Returns the completableFuture instance generated by the method. Modify hashmap here.
}
I've tried reading the docs, however it was a bit confusing, any help is appreciated!
As given in the comments, two options can be considered.
First option is to convert the async nature into sync nature using CompletableFuture#get. This way, the code execution is in a blocking context.
public void createClan(Transaction transaction, int id, int maxPlayers) {
MongoTransaction mongoTransaction = (MongoTransaction) transaction;
Clan clan = new Clan(id, maxPlayers);
String json = gson.toJson(clan);
TransactionExecutor executor = new MongoTransactionExecutor(mongoTransaction, json);
try {
Object obj = executor.runTransaction().get();
// HashMap update here
} catch(Exception e) {
//handle exceptions
}
}
Second option is to keep the async nature as is and chain using thenRun (there are many then options available). This way is more a non-blocking context.
public void createClan(Transaction transaction, int id, int maxPlayers) {
MongoTransaction mongoTransaction = (MongoTransaction) transaction;
final Clan clan = new Clan(id, maxPlayers);
String json = gson.toJson(clan);
TransactionExecutor executor = new MongoTransactionExecutor(mongoTransaction, json);
try {
executor.runTransaction().thenRun(() -> updateHashMap(clan));
} catch(Exception e) {
//handle exceptions
}
}

Implementation of for loop using java8 features

Can somebody please help me to restructure the following code using java8 features.
Here is my code.
private List<CreateChildItemResponse> createChildItems(String[] childUpcNumbers, String[] childItemNbrs,
ItemVo parentItem, UserVo user, boolean isEnableReverseSyncFlag, Integer parentItemNbr, Long parentUpcNbr,int childUpcNbrsize, ItemManagerDelegate managerDelegate) throws NumberFormatException, ValidationException,ChildNotFoundException, ResourceException, ChildItemException {
List<ItemVo> resultList = new ArrayList<ItemVo>();
List<CreateChildItemAssortmentResponse> relations = null;
CreateChildItemResponse response = new CreateChildItemResponse();
try {
for (int i = 0; i < childUpcNumbers.length; i++) {
// parentItem.setItemNbr(itemNumberList.get(i));
logger.info("-------Item Nbrs-----" + parentItem.getItemNbr());
ItemVo child = createItemForMigration(
populateChildItemVo(parentItem, getGtin(childUpcNumbers[i]), Integer.valueOf(childItemNbrs[i])),
user, isEnableReverseSyncFlag, managerDelegate);// null scales for all except scales integration
resultList.add(child);
}
relations = this.populateAssortmentRelationVo(parentItem.getItemNbr(), resultList);
response = getSuccessResponse(parentItemNbr, relations, parentUpcNbr);
// utx.commit();
} catch (Exception e) {
logger.info("Exception occurs while creating child item", e);
relations = this.populateAssortmentRelationVoForException(e, resultList);
response = getFailureResponseForException(parentItemNbr, relations, parentUpcNbr, e, resultList.size(),
childUpcNbrsize);
finalResponse.add(response);
throw new ChildItemException(e.getMessage(), finalResponse, e);
}
finalResponse.add(response);
return finalResponse;
}
here I am calling the below method in the above code
relations = this.populateAssortmentRelationVo(parentItem.getItemNbr(), resultList);
And the implementation is
private List<CreateChildItemAssortmentResponse> populateAssortmentRelationVo(Integer parentItemNumber,
List<ItemVo> childs) {
List<CreateChildItemAssortmentResponse> relationList = new ArrayList<CreateChildItemAssortmentResponse>();
for (ItemVo child : childs) {
CreateChildItemAssortmentResponse relation = new CreateChildItemAssortmentResponse();
relation.setItemNbr(child.getItemNbr());
relation.setUpcNbr(convertUpcToString(child.getEachGtin().getGtinNbr()));
relation.setStatus("SUCCESS");
relation.setMessage("");
relationList.add(relation);
}
return relationList;
}
Here I want to take a constructor for the populateAssortmentRelationVo() and how to use stream and mapper inside this.
First declare a mapping function:
private CreateChildItemAssortmentResponse> itemVoToResponse(ItemVo item) {
CreateChildItemAssortmentResponse response = new CreateChildItemAssortmentResponse();
response.setItemNbr(item.getItemNbr());
response.setUpcNbr(convertUpcToString(item.getEachGtin().getGtinNbr()));
response.setStatus("SUCCESS");
response.setMessage("");
return relationList;
}
and simply map all the elements of one list into another one:
relations = resultList.stream()
.map(this::itemVoToResponse)
.collect(toList());

why jpa not save data at a time

i want save data and check the data after call save method
but the value is not present in same request
i have two method depend each other
the two function communcation with each other by kafka
the first method save the data and after save using jpa call second method
find the recourd from database using jpa
and check the instanse using isPresent()
but in the second method i cant find the data save
but after this request i can find data
return exciption NoSuchElement
Try out several ways like:
1-use flush and saveAndFlush
2-sleep method 10000 milsec
3-use entityManger with #Transactional
but all of them not correct
i want showing you my two method from code:
i have producer and consumer
and this is SaveOrder method (first method):
note : where in the first method have all ways i used
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void saveOrder(Long branchId,AscOrderDTO ascOrderDTO) throws Exception {
ascOrderDTO.validation();
if (ascOrderDTO.getId() == null) {
ascOrderDTO.setCreationDate(Instant.now());
ascOrderDTO.setCreatedBy(SecurityUtils.getCurrentUserLogin().get());
//add user
ascOrderDTO.setStoreId(null);
String currentUser=SecurityUtils.getCurrentUserLogin().get();
AppUser appUser=appUserRepository.findByLogin(currentUser);
ascOrderDTO.setAppUserId(appUser.getId());
}
log.debug("Request to save AscOrder : {}", ascOrderDTO);
AscOrder ascOrder = ascOrderMapper.toEntity(ascOrderDTO);
//send notify to branch
if(!branchService.orderOk())
{
throw new BadRequestAlertException("branch not accept order", "check order with branch", "branch");
}
ascOrder = ascOrderRepository.save(ascOrder);
/*
* log.debug("start sleep"); Thread.sleep(10000); log.debug("end sleep");
*/
entityManager.setFlushMode(FlushModeType.AUTO);
entityManager.flush();
entityManager.clear();
//ascOrderRepository.flush();
try {
producerOrder.addOrder(branchId,ascOrder.getId(),true);
stateMachineHandler.stateMachine(OrderEvent.EMPTY, ascOrder.getId());
stateMachineHandler.handling(ascOrder.getId());
//return ascOrderMapper.toDto(ascOrder);
}
catch (Exception e) {
// TODO: handle exception
ascOrderRepository.delete(ascOrder);
throw new BadRequestAlertException("cannot deliver order to Branch", "try agine", "Try!");
}
}
in this code go to producer :
producerOrder.addOrder(branchId,ascOrder.getId(),true);
and this is my producer:
public void addOrder(Long branchId, Long orderId, Boolean isAccept) throws Exception {
ObjectMapper obj = new ObjectMapper();
try {
Map<String, String> map = new HashMap<>();
map.put("branchId", branchId.toString());
map.put("orderId", orderId.toString());
map.put("isAccept", isAccept.toString());
kafkaTemplate.send("orderone", obj.writeValueAsString(map));
}
catch (Exception e) {
throw new Exception(e.getMessage());
}
}
and in this code go to consumer:
kafkaTemplate.send("orderone", obj.writeValueAsString(map));
this is my consumer:
#KafkaListener(topics = "orderone", groupId = "groupId")
public void processAddOrder(String mapping) throws Exception {
try {
log.debug("i am in consumer add Order");
ObjectMapper mapper = new ObjectMapper(); Map<String, String> result = mapper.readValue(mapping,
HashMap.class);
branchService.acceptOrder(Long.parseLong(result.get("branchId")),Long.parseLong(result.get("orderId")),
Boolean.parseBoolean(result.get("isAccept")));
log.debug(result.toString());
}
catch (Exception e) {
throw new Exception(e.getMessage());
}
}
**and this code go to AcceptOrder (second method) : **
branchService.acceptOrder(Long.parseLong(result.get("branchId")),Long.parseLong(result.get("orderId")),
Boolean.parseBoolean(result.get("isAccept")));
this is my second method :
public AscOrderDTO acceptOrder(Long branchId, Long orderId, boolean acceptable) throws Exception {
ascOrderRepository.flush();
try {
if (branchId == null || orderId == null || !acceptable) {
throw new BadRequestAlertException("URl invalid query", "URL", "Check your Input");
}
if (!branchRepository.findById(branchId).isPresent() || !ascOrderRepository.findById(orderId).isPresent()) {
throw new BadRequestAlertException("cannot find branch or Order", "URL", "Check your Input");
}
/*
* if (acceptable) { ascOrder.setStatus(OrderStatus.PREPARING); } else {
* ascOrder.setStatus(OrderStatus.PENDING); }
*/
Branch branch = branchRepository.findById(branchId).get();
AscOrder ascOrder = ascOrderRepository.findById(orderId).get();
ascOrder.setDiscount(50.0);
branch.addOrders(ascOrder);
branchRepository.save(branch);
log.debug("///////////////////////////////Add order sucess////////////////////////////////////////////////");
return ascOrderMapper.toDto(ascOrder);
} catch (Exception e) {
// TODO: handle exception
throw new Exception(e.getMessage());
}
}
Adding Thread.sleep() inside saveOrder makes no sense.
processAddOrder executes on a completely different thread, with a completely different persistence context. All the while, your transaction from saveOrder might still be ongoing, with none of the changes made visible to other transactions.
Try splitting saveOrder into a transactional method and sending the notification, making sure that the transaction ends before the event handling has a chance to take place.
(Note that this approach introduces at-most-once semantics. You have been warned)

Parse.com How to return a value from a query in Android

I'm using the Parse API to query some data for an Android application and I would like to know how to return a value (for example a Boolean) from a Parse Query. For example I would like a function that returns true if some data exists and false otherwise like so :
public Boolean myFunction(){
ParseQuery<ParseObject> query = ParseQuery.getQuery();
query.findInBackground("someData",new GetCallback<ParseObject>() {
#Override
public void done(ParseObject lan, ParseException e) {
if(e==null){
return true;
} else {
return false;
}
});
}
I do know that this cannot be done this way because the query is processed in a background thread and I'm not very familiar with Callbacks.
I am aware that there is a similar question here Parse.com how to get return value of query but this is for JavaScript.
Do you have any idea on how to do that ?
You are almost there. When you get the Parse Object extract it with:
boolean myBoolean = myParseObject.getBoolean("myBooleanColumn");
Full example (finding an object via id, it can be adapted for other type of queries):
ParseQuery<ParseObject> query = ParseQuery.getQuery("YourClass");
query.getInBackground("id", new GetCallback<ParseObject>() {
public void done(ParseObject myParseObject, ParseException e) {
if (e == null) {
boolean myBoolean = myParseObject.getBoolean("myBooleanColumn");
} else {
// something went wrong
}
}
});
Update: if you only want to check if some data exists in a row you can do it with
query.whereEqualTo("columnToFind", "searchterm");
You can even find compare an array with the data in row with
query.whereContainsAll("columnToFind", arrayOfThingsToSearch);
After some research and thanks to #buckettt, the easiest way to accomplish that is to use Parse Cloud Code. Define your function in the main.js file inside parse-server folder :
Parse.Cloud.define("myFunction",function(req,res){
var userId = req.params.userId; //params passed in Client code
var myQuery = new Parse.Query(Parse.User);
myQuery.equalTo("userId", userId);
myQuery.find({
success: function(results) {
res.success(results.get("userName"));
}
error: function() {
res.error("Failed !");
}
}
});
And in your Client's code :
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("userId",userId);
ParseCloud.callFunctionInBackground("myFunction", params, new FunctionCallback<String>() {
public void done(String res,ParseException e){
if (e == null) {
Log.i("Results :",res);
} else {
Log.i("Error",e.getMessage());
}
}
});
This way you return the desired value and the function is executed directly on your server. Hope this helps

ElasticSearch Multi Type Search using Java API or Spring Data Elasticsearch

I want to Search My Index in all Types and all fields for the query.
I know how to do it using REST way.
I want to know how to do it using JAVA API and more specifically in Spring Data Elasticsearch.
This is some code i have written but seams to be pretty messed in terms of return Type.
#Override
public Page<Object> searchInAll(String searchQuery) {
MatchQueryBuilder matchQueryBuilder =QueryBuilders.matchQuery("_all", "trump");
SearchQuery searchQueryFinal = new NativeSearchQueryBuilder().withQuery(matchQueryBuilder).withIndices("booksearchserver").withTypes("authors","books").build();
return elasticsearchTemplate.queryForPage(searchQueryFinal, Author.class, new SearchResultMapper(){
#SuppressWarnings("unchecked")
public <T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
long totalHits = response.getHits().getTotalHits();
List<Book> content = new ArrayList<Book>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}else if(searchHit.getType().equals("books")){
logger.info("Creating Book,Mapping Book,Adding Book to Page");
}
else if(searchHit.getType().equals("author")){
logger.info("Creating Author,Mapping Author,Adding Author to Page");
}
logger.info(searchHit.getType());
}
List<FacetResult> facets = new ArrayList<FacetResult>();
if (response.getFacets() != null) {
for (Facet facet : response.getFacets()) {
FacetResult facetResult = DefaultFacetMapper.parse(facet);
if (facetResult != null) {
facets.add(facetResult);
}
}
}
return new FacetedPageImpl<T>((List<T>)content, pageable, totalHits, facets);
}
});

Categories