Spring boot with querydsl create a query with function - java

i am using Spring Boot with querydsl. I need to build this query somehow, but i can't do it:
SELECT address.id, address.city FROM address WHERE earth_box( ll_to_earth(48.97300592, 8.32746506), 3100) #> ll_to_earth(address.lattitude, address.longitude);
I try to customize the binding method of that parameter in my customize() method
How can i build this query?
EDIT:
My customize() method in ArticleRepositoryImpl
#Override
public void customize(QuerydslBindings bindings, QArticle root) {
bindings.bind(root.address.city).first((path, value) -> {
Predicate city = root.address.city.eq(value); // Here i need to build my Predicate, which is my SqL query in the top
return city;
});
And my Rest Controller:
#RequestMapping(method = RequestMethod.GET, value = "/article")
public ResponseEntity<Page<QArticle>> findAll(#QuerydslPredicate(root = Article.class) Predicate predicate,
Pageable p) {
System.out.println(predicate.toString());
Page<QArticle> resultPage = repo.findAll(predicate, p);
return new ResponseEntity<Page<QArticle>>(resultPage, HttpStatus.OK);
}

Related

How to do Pagination with filter

I want to make paginable service with filter but its fail to resultset
Here is my controller
#GetMapping(path = "/PageFilter")
public DataResponsePagination<HistoryBankWrapper, HistoryBank> pageFilter(
#RequestParam("filter") String keyfilter ,
#RequestParam("sortField") String field ,
#RequestParam("sortOrder") String order ,
#RequestParam("page") int page,
#RequestParam("size") int size) {
return new DataResponsePagination<HistoryBankWrapper, HistoryBank>(historyBankService.findByFilter(keyfilter,field,order, page, size));
}
Here is my service
public PaginationList<HistoryBankWrapper, HistoryBank> findByFilter(String keyfilter,String sortField,String sortOrder, int page, int size) {
Pageable paging = PageRequest.of(page, size);
Page<HistoryBank> historyPage = historyBankRepository.findAllFilter(keyfilter, sortField, sortOrder, paging);
List<HistoryBank> historyList = historyPage.getContent();
List<HistoryBankWrapper> historyWrapperList = toWrapperList(historyList);
return new PaginationList<HistoryBankWrapper, HistoryBank>(historyWrapperList, historyPage);
}
here is my Repository
#Query(value = "SELECT * FROM HISTORY_BANK WHERE :sortField LIKE '%' || :keyFilter || '%' ORDER BY :sortField :sortOrder",
countQuery = "SELECT count(*) FROM HISTORY_BANK",
nativeQuery = true)
Page<HistoryBank> findAllFilter(#Param("keyFilter") String keyfilter, #Param("sortOrder") String sortOrder,#Param("sortField") String sortField, #Param("paging") Pageable paging);
Ditch your own method and use the framework. Use specifications to create a dynamic query.
Your repository should extend the JpaSpecificationExecutor and then you should invoke the findAll(Specification, Pageable) from your service. Your service should prepare the Specification it needs to build the query.
public interface YourRepository extends JpaRepository<HistoryBank, Long>,
JpaSpecificationExecutor<HistoryBank> {}
Your service can then use the aforementioned findAll method.
public PaginationList<HistoryBankWrapper, HistoryBank> findByFilter(String keyfilter,String sortField,String sortOrder, int page, int size) {
Sort sort = Sort.by(Sort.Direction.fromString(sortOrder), sortField);
Pageable paging = PageRequest.of(page, size);
Specification<HistoryBank> spec = (r, c, b) -> b.like(r.get(sortField), "%" + keyFilter + "%"));
Page<HistoryBank> historyPage = historyBankRepository.findAllFilter(spec, paging);
List<HistoryBank> historyList = historyPage.getContent();
List<HistoryBankWrapper> historyWrapperList = toWrapperList(historyList);
return new PaginationList<HistoryBankWrapper, HistoryBank>(historyWrapperList, historyPage);
}
You can even make this easier by modifying your controller to directly bind to a Pageable object, that saves you creating it.
public DataResponsePagination<HistoryBankWrapper, HistoryBank> pageFilter(
#RequestParam("filter") String keyfilter ,
Pageable page) {
{
Now you only need to create the Specification and can just pass along the Pageable.
In the Jpa repository you use the symbol of OR (||) try with a keyword or
and modified your query for filtering you have to use and instead of or

How to query same table with same parameter but with different where conditions and get combined result at last

I have a global search I will search with one keyword but need to get results with all the matching columns of a table.
Page<A> a = null;
a = zRepo.getResultByNameSearch(searchText)
a = zRepo.getResultByNumberSeach(searchText)
a = zRepo.getRsultByProjectSearch(searchText)
#Query("select * from a_table x where x.name like :searchText")
Page<A> getResultByNameSearch(#Param("searchText") String searchText, Pageable pageable);
#Query("select * from a_table where x.number like :searchText")
Page<A> getResultByNumberSearch(#Param("searchText") String searchText, Pageable pageable);
#Query("select * from a_table where x.project like :searchText")
Page<A> getResultByProjectSearch(#Param("searchText") String searchText, Pageable pageable);
So each repository call queries and fetches the same table but according to the searchText.
Let's assume name = "Company910", number = "XX910", project = "910".
Now I'm searching for "910" and want to get results with all the 3 values. Page<a> will be having all the columns of a_table with the list of results as per "Company910", "XX910", "910".
How to implement this or is there any other way where I can maintain a single query instead of three different for name, number and project?
For the first part of how to get the combined result. I will do something like this.
Create repository interface as you wrote but using spring data jpa intead of raw query
user CompletableFuture with each method call
combine the result into a dto
return this combined result
#Repository
public interface SampleDocumentRepository extends JpaRepository<SampleDocument, Integer> {
Page<SampleDocument> findByNameContains(String name, Pageable pageable);
Page<SampleDocument> findByNumberContains(String number, Pageable pageable);
Page<SampleDocument> findByProjectContains(String project, Pageable pageable);
}
Service class where result are combined together
#Service
#AllArgsConstructor
public class SampleDocumentService {
private final SampleDocumentRepository repository;
#Transactional(readOnly = true)
public CompletableFuture<ResultDto> search(String query) {
PageRequest page = PageRequest.of(0, 20);
CompletableFuture<Page<SampleDocument>> nameSearch = CompletableFuture.supplyAsync(() -> repository.findByNameContains(query, page));
CompletableFuture<Page<SampleDocument>> numberSearch = CompletableFuture.supplyAsync(() -> repository.findByNumberContains(query, page));
CompletableFuture<Page<SampleDocument>> projectSearch = CompletableFuture.supplyAsync(() -> repository.findByProjectContains(query, page));
return CompletableFuture.allOf(nameSearch, numberSearch, projectSearch)
.thenApply(unused -> new ResultDto(nameSearch.join(), numberSearch.join(), projectSearch.join()));
}
}
Then the call from the service
#GetMapping("/search")
public CompletableFuture<ResultDto> search(#RequestParam("query") String query) {
return service.search(query);
}
call using your query argument
http://localhost:8080/sample/search?query=hello
To answer the second part, if you want to check if the query is present in any of the columns you can write JPA query combining the Or operator like this.
Page<SampleDocument> findByNameContainsOrNumberContainsOrProjectContains(String name, String number, String project, Pageable pageable);
Caller would be something like this
#Transactional(readOnly = true)
public CompletableFuture<ResultDto> searchAll(String query) {
PageRequest page = PageRequest.of(0, 20);
CompletableFuture<Page<SampleDocument>> nameSearch = CompletableFuture.supplyAsync(() ->
repository.findByNameContainsOrNumberContainsOrProjectContains(query, query, query, page));
return CompletableFuture.supplyAsync(() -> new ResultDto(nameSearch.join(), null, null));
}
If you want to use Async with spring data and completable please follow this link

How to sorting repository entity with pagination in spring boot

I am writing an REST API with Spring Boot.Here,I am trying to sort the list using the 'PagingAndSortingRepository'.This is what I have tried
Method in my Controller class
#GetMapping public ResponseEntity
<PagedModel<ComplainDTO>> getComplains(#RequestParam(defaultValue = "0",value = "page",required =false)int page, #RequestParam(value="sortBy" ,required = false,defaultValue = "complainId") String sortBy, PagedResourcesAssembler assembler) {
return ResponseEntity.status(HttpStatus.OK)
.body(assembler.toModel(complainService.getAllComplains(page,sortBy)));
}
Method on my service
#Override
public Page<ComplainDTO> getAllComplains(int page,String sortBy) {
Pageable pageable = PageRequest.of(page,20, Sort.by(sortBy));
Page<ComplainEntity> result =complainRepository.findAll(pageable);
return result.map(complainEntity -> toDTO(complainEntity));
}
I am taking input from the consumer to sort the list based on given attribute however the default behavior of Sort is Ascending .So,how can I implement this taking user params whether it being ascending or descending aside from using if-else.
The one option is asking the user to provide the sorting order using #RequestParam
#GetMapping public ResponseEntity
<PagedModel<ComplainDTO>> getComplains(#RequestParam(defaultValue = "0",value = "page",required =false)int page,
#RequestParam(value="sortBy" ,required = false,defaultValue = "complainId") String sortBy,
#RequestParam(value="orderBy" ,required = false,defaultValue = "ASC") String orderBy, PagedResourcesAssembler assembler) {
return ResponseEntity.status(HttpStatus.OK)
.body(assembler.toModel(complainService.getAllComplains(page,sortBy,orderBy)));
}
And then in the service pass the sorting order to Sort method
#Override
public Page<ComplainDTO> getAllComplains(int page,String sortBy, String orderBy) {
Pageable pageable = PageRequest.of(page,20, Sort.by(Sort.Direction.valueOf(orderBy),sortBy));
Page<ComplainEntity> result =complainRepository.findAll(pageable);
return result.map(complainEntity -> toDTO(complainEntity));
}

Jpa Hibernate #Query annotation with filters

I have an Angular based Application for Front End and Spring Boot for Back End.
My componaent had a variable that contains filters like that
search:any={
name:'',
surname:'',
address:'',
phone:'',
city:''
}
i pass it to my Api with Post Method like that:
getPeoplesByFilters(filter){
return this.http.post("http://localhost:8080/search", filter)
.map (resp => resp.json())
}
I receive this in my Spring Boot Controller by this method:
#RequestMapping(value="/search", method= RequestMethod.POST )
public Page<People> searchFilters(#RequestBody() People p,
#RequestParam(value="page", defaultValue="0") int page ,
#RequestParam(value="size", defaultValue="5") int size){
p.setName("%"+p.getName()+"%");
p.setSurname("%"+p.getSurname()+"%");
p.setAddress("%"+p.getAddress()+"%");
p.setPhone("%"+p.getPhone()+"%");
System.out.println(p.getName());
return poepleRepository.searchFilters( p , new PageRequest(page, size));
}
And in my Jpa Repository interface I have this query:
#Query("select p from poeple p where p.name like :#{#x.name} and p.surname like :#{#x.surname} and p.address like :#{#x.address} and p.phone like :#{#x.phone} and p.mobile like :#{#x.phone}")
public Page<People> searchFilters(#Param("x") People x, Pageable pageable);
But I don't have any result
I tried just with one field and i fill it in my front end App and it work
But when I fill just one field and let another empty i have zero result.
What's Wrong!
Thanks
My previous experience shows that using specifications is best for your case. Because it is more extendable and understandable. You can write specification like below.
public class Spec{
public static Specification<Person> filter(FilterParams filterParams) {
return (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if(filterParams.getName()!=null){
predicates.add(cb.equal(root.get("name"),filterParams.getName()));
}
if(filterParams.getSurname()!=null){
predicates.add(cb.equal(root.get("surname"),filterParams.getSurname()));
}
....
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
}
}
}
Then you can use like below:
#Service
public TestService{
#Autowired
PersonRepository personRepository;
void test(){
FilterParam filterParam = new FilterParam();
filterParam.setName("test);
...
personRepository.findAll(Spec.filter(filterParam));
}
}

Using Pagination in Spring JPA

I have a Spring Boot 1.5.2 project which up till now has been sending lists back to the view. I would like to use pagination instead of lists. I began to change the code in the service layer and repository, but it has not been a simple case of changing from List<T> to Page<T>.
In particular on the service layer I was returning different List<T> based on user role and then passing this list to a method that converts to Dto before sending it back to controller.
Spring Boot 1.5.2 appears to use Spring-data-jpa:1.11
Controller
#GetMapping("/dashboard/sale")
public String dashboard(#RequestParam(name = "p", defaultValue = "1") int pageNumber, Model model, HttpServletRequest request) {
List<SaleDashboard> listSaleDashboard = saleService.getPage(pageNumber);
model.addAttribute("listSaleDashboard", listSaleDashboard);
return "dashboard";
}
Service Layer
public List<SaleDashboard> getPage(int pageNumber) {
PageRequest request = new PageRequest(pageNumber - 1, PAGESIZE, Sort.Direction.ASC, "id");
List<Sale> listSale = new ArrayList<>();
if (roles.contains("ROLE_ADMIN")) {
listSale = saleRepository.findBySomeProperty(user.getUserDetails().getReportDept());
}
if (roles.contains("ROLE_USER")) {
listSale = saleRepository.findByListOfCreatingUser(userList);
}
List<SaleDashboard> listSaleDashboard = createSaleDashboard(listSale);
return listSaleDashboard;
}
public List<SaleDashboard> createSaleDashboard(List<Sale> sales) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
List<SaleDashboard> listSaleDashboard = new ArrayList<>();
for (Sale sale: sales) {
SaleDashboard saleDashboard = new SaleDashboard();
saleDashboard.setSaleId(sale.getId());
// ETC
listSaleDashboard.add(saleDashboard);
}
return listSaleDashboard;
}
In the service layer above I began to use PageRequest but thats as far as I got.
Repository
public interface SaleRepository extends JpaRepository<Sale, Long> , PagingAndSortingRepository<Sale, Long> {
#Query("SELECT e FROM Sale e WHERE e.creatingUser in (:userList)")
Page<Sale> findByListOfCreatingUser(#Param("userList") List<User> users, Pageable pageable);
}
How would I implement a similar service layer but use Page<T> instead of List<T>?

Categories

Resources