Θα δημιουργήσουμε το search-page component, το οποίο περιέχει τα αποτελέσματα της αναζήτησης του χρήστη. Όταν ο client θέλει τα προϊόντα της αναζήτησης, κάνει ένα HTTP GET request στο url http://localhost:8080/api/search?keyword=shampoo&page=0&order=asc και το Spring Boot θα του επιστρέφει τα προϊόντα ανά εξάδα. Ουσιαστικά πραγμαποιούμε το ερώτημα "Select prod from Product prod where prod.name like '%shampoo%'".
Δημιουργούμε τα SearchService και SearchServiceImpl.
package springeshop.service;
public interface SearchService{
...
Page ProductPage findBySearchTerms(String[] searchTerms, int page, List<Brand> brands , List<double[]> priceRanges, String order);
int findSearchProductsNumberByRange(String[] searchTerms, double min, double max, List<Brand> brands);
int findSearchProductsNumberByBrand(String[] searchTerms, Brand brand, List<double[]> priceRanges);
List<Brand> findSearchBrands(String[] searchTerms);
}
package springeshop.service;
@Service("searchService")
@Transactional
public class SearchServiceImpl implements SearchService{
@Autowired
private EntityManager entityManager;
}
Υλοποιούμε τη μέθοδο Page ProductPage findBySearchTerms(String[] searchTerms, int page, List<Brand> brands , List<double[]> priceRanges, String order);
@Override
public Page ProductPage findBySearchTerms(String[] searchTerms, int page, List<Brand> brands , List<double[]> priceRanges, String order);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Product> criteriaQuery = criteriaBuilder.createQuery(Product.class);
Root<Product> productsRoot = criteriaQuery.from(Product.class);
Δημιουργούμε συνθήκες του WHERE, "prod.name like '%' + :searchTerm + '%' ", "prod.price between :range1 and :range2" και "prod.brand = :brand"
List<Predicate> searchPredicatesList = new ArrayList<>();
List<Predicate> brandPredicateList = new ArrayList<>();
List<Predicate> priceRangePredicateList = new ArrayList<>();
if(searchTerms.length > 0){
for(String term : searchTerms){
searchPredicatesList.add(criteriaBuilder.like(productsRoot.get("name"), "%" + term +"%"));
}
}
if(!brands.isEmpty()){
for(int i=0; i < brands.size(); i++){
brandPredicateList.add(criteriaBuilder.equal(productsRoot.get("brand"), brands.get(i)));
}
}
if(!priceRanges.isEmpty()){
for(double[] range : priceRanges){
priceRangePredicateList.add(criteriaBuilder.between(productsRoot.get("price"), range[0], range[1]));
}
}
Predicate[] searchPredicatesArray = new Predicate[searchPredicatesList.size()];
searchPredicatesList.toArray(searchPredicatesArray);
Predicate[] brandsPredicateArray = new Predicate[brandPredicateList.size()];
brandPredicateList.toArray(brandsPredicateArray);
Predicate[] priceRangePredicateArray = new Predicate[priceRangePredicateList.size()];
priceRangePredicateList.toArray(priceRangePredicateArray);
Predicate brandsPredicate = criteriaBuilder.or(brandsPredicateArray);
Predicate priceRangePredicate = criteriaBuilder.or(priceRangePredicateArray);
Predicate searchPredicate = criteriaBuilder.or(searchPredicatesArray);
Δημιουργούμε το κατάλληλο ερώτημα, ανάλογα με το αν είναι επιλεγμένα τα φίλτρα ή όχι
if(!brands.isEmpty() && !priceRanges.isEmpty()){
criteriaQuery.where(searchPredicate, brandsPredicate, priceRangePredicate);
}else if(brands.isEmpty() && priceRanges.isEmpty()){
criteriaQuery.where(searchPredicate);
}else{
if(brands.isEmpty()){
criteriaQuery.where(criteriaBuilder.and(searchPredicate, priceRangePredicate));
else{
criteriaQuery.where(criteriaBuilder.and(searchPredicate, brandsPredicate));
}
}
Ταξινομούμε τα προϊόντα με βάση την παράμετρο order, βρίσκουμε τον αριθμό των συνολικών προϊόντων και επιστρέφουμε την κατάλληλη σελίδα
Order orderCriterion = order.equals("asc") ? criteriaBuilder.asc(productsRoot.get("price")) : criteriaBuilder.desc(productsRoot.get("price"));
criteriaQuery.orderBy(orderCriterion);
ProductPage productPage = new ProductPage();
int totalProducts = entityManager.createQuery(criteriaQuery).getResultList().size();
int startProductPosition = page * 6;
productPage.setTotalElements(totalProducts);
productPage.setTotalPages(getProductPages(totalProducts));
List<Product> wantedProducts = entityManager.createQuery(criteriaQuery).setFirstResult(startProductPosition).setMaxResults(6).getResultList();
productPage.setContent(wantedProducts);
productPage.setNumber(page);
productPage.setNumberOfElements(wantedProducts.size());
return productPage;
Δημιουργούμε τoν SearchApiController στο πακέτο springeshop.controller
package springeshop.controller;
@RestController
@RequestMapping("/api")
public class SearchApiController{
public static final Logger logger = LoggerFactory.getLogger(SearchApiController.class);
@Autowired
private BrandService brandService;
@Autowired
private SearchService searchService;
@Autowired
private InventoryService inventoryService;
@Autowired
private ProductImageService productImageService;
...
Προσθέτουμε τη μέθοδο στον CategoryApiController.
@RequestMapping(value = "/search", method = RequestMethod.GET)
public ResponseEntity<?> getSearchProducts(@RequestParam((value = "keyword") String[] keywords,
@RequestParam( (value = "brand", required = false) int String[] brands,
@RequestParam( (value = "range", required = false) int String[] ranges,
@RequestParam( (value = "page", required = true) int page,
@RequestParam((value = "order", required = true) String order){
ProductPage productPage = new ProductPage();
List<double[]> priceRangeList = new ArrayList<>();
List<Brand> brandPredicateList = new ArrayList<>();
if(brands != null){
brandList = brandService.findSpecificBrands(brands);
}
if(ranges != null){
for(String range : ranges){
rangeValues[0] = getRangeMin(range);
rangeValues[1] = getRangeMax(range);
priceRangeList.add(rangeValues);
}
}
productPage = searchService.findBySearchTerms(keywords, page, brandList, priceRangeList, order);
if(productPage.getContent().isEmpty()){
logger.error("No products found.");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
addImagesAndQuantityToProducts(productPage.getContent());
return new ResponseEntity<>(productPage, HttpStatus.OK);
}
Δημιουργούμε το component search-page και το search service.
ng generate component category-page
ng generate service service
Θα χρησιμοποιήσουμε τη μέθοδο getSearchProducts() του SearchService, για να πραγματοποιήσουμε το HTTP αίτημα και να πάρουμε το προϊόντα.
Κάθε φορά που αλλάζει ο χρήστης αλλάζει όρους αναζήτηση ή επιλέγει φίλτρα, παίρνουμε τις τιμές τους και πραγματοποιούμε το HTTP αίτημα, για να πάρουμε τα προϊόντα της αναζήτησης.
search-page.component.ts
search-page.component.html
search-page.component.css