• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Spring MVC - pomoc w implementacji metody

Object Storage Arubacloud
0 głosów
313 wizyt
pytanie zadane 1 października 2018 w Java przez must Bywalec (2,980 p.)
edycja 2 października 2018 przez must

Cześć. Korzystam z książki "Spring MVC - Przewodnik dla początkujacych"

Mam za zadanie:

Wyobraź sobie, że chcesz użyć wielu kryteriów, by wyświetlić pożądany produkt, np. produkt z kategorii tablet o cenie od 200 PLN do 400 PLN, którego producentem jest Google.

Tutaj cała instrukcja:

Ogólnie mam wszystkie metody, getProductsByPriceFilter, getProductsByManufacturer, getProductsByCategory a także products.jsp.

Nie wiem jak mam skleić tę metode kontrolera:

public class ProductController {

    private final ProductService productService;

    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;
    }
@RequestMapping("/{category}/{price}")
    public String filterProducts(Model model, @PathVariable("category") String productCategory, @MatrixVariable(pathVar = "price") Map<String, List<String>> filterParams, @RequestParam("manufacturer") String manufacturer) {

...
        return "products";
    }

Pomoże ktoś?

 

///EDIT

Dodaje te 3 metody, może są potrzebne, aczkolwiek nie wydaje mi się. Chodzi mi bardziej tutaj o ten ostatni akapit "Pamiętaj, że metoda wywołana...."

public Set<Product> getProductsByFilter(Map<String, List<String>> filterParams) {
        Set<Product> productsByBrand = new HashSet<>();
        Set<Product> productsByCategory = new HashSet<>();
        Set<String> criterias = filterParams.keySet();
        if (criterias.contains("brand")) {
            for (String brandName : filterParams.get("brand")) {
                for (Product product : listOfProducts) {
                    if (brandName.equalsIgnoreCase(product.getManufacturer())) {
                        productsByBrand.add(product);
                    }
                }
            }
        }
        if (criterias.contains("category")) {
            for (String category : filterParams.get("category")) {
                productsByCategory.addAll(this.getProductsByCategory(category));
            }
        }
        productsByCategory.retainAll(productsByBrand);
        return productsByCategory;
    }

@Override
    public List<Product> getProductsByCategory(String category) {
        List<Product> productsByCategory = new ArrayList<>();
        for (Product product : listOfProducts) {
            if (category.equalsIgnoreCase(product.getCategory())) {
                productsByCategory.add(product);
            }
        }
        return productsByCategory;
    }

    @Override
    public List<Product> getProductsByManufacturer(String manufacturer) {
        List<Product> productsByManufacturer = new ArrayList<>();
        for (Product product : listOfProducts) {
            if (manufacturer.equalsIgnoreCase(product.getManufacturer())) {
                productsByManufacturer.add(product);
            }
        }
        return productsByManufacturer;
    }

 

1 odpowiedź

+1 głos
odpowiedź 2 października 2018 przez mbabane Szeryf (79,280 p.)
wybrane 2 października 2018 przez must
 
Najlepsza

Chodzi o to, że musisz pozbierać jakoś wyniki ze wszystkich metod tak aby zwrocić je przez kontroler do widoku. W zadaniu zasugerowali Ci Set bo dzięki temu masz bardzo łatwo zrealizowane zwalczanie duplikatów:

Set<String> strings = new HashSet<>();

strings.add("a");
strings.add("a");
strings.add("a");

System.out.println(strings);

W powyższym przykładzie mimo że dodaje 3 razy "a" to w zbiorze znajduje się tylko jedno "a".

Więc u Ciebie najprawdopodobniej wystarczy coś takiego:

List<Product> productsByCategory = service.getProductsByCategory(category);
List<Product> productsByManufacture = service.getProductsByManufacturer(manufacture);
Set<Product> productsByPrice = service.getProductsByFilter(filter);

Set<Product> result = new HashSet<>();

productsByCategory.forEach( product -> {result.add(product) } );
productsByManufacture.forEach( product -> { result.add(product) } );
productsByPrice.forEach( product -> {result.add(product) } );

model.addAttribute("products", result);

 

 

komentarz 2 października 2018 przez mbabane Szeryf (79,280 p.)
Chociaż tak po prawdzie to powyższe zdaje się da się rozwiązać jednym zapytaniem SQL (i tak należałoby zrobić w prawdziwym świecie. Jeśli chodzi o przetwarzanie danych to bazy danych są tak optymalizowane aby robić to jak najwydajniej).

Jednak takie ćwiczenia mają co innego sprawdzać i utrwalać - w tym przypadku zdaje się pracę w springu mvc.
komentarz 2 października 2018 przez NIMuser Stary wyjadacz (11,030 p.)
Jedno zapytanie SQL, jasne. Ale czy tego nie załatwia ORM? W Django czy ASP.net tak jest, że szukasz, zawężasz, filtrujesz, filtrujesz kolejny raz i na końcu wysyłane jest zapytanie do  bazy danych.
komentarz 2 października 2018 przez must Bywalec (2,980 p.)
edycja 2 października 2018 przez must

Tak, pewnie o coś takiego wychodziło.

Choć zaobserwowałem ciekawy przypadek, a mianowicie jak zmienie sobie link na:

http://localhost:8080/products/laptop/price;low=200;high=300?manufacturer=Apple

czyli najniższa cena to 200, najwyzsza 300, kategoria laptop, producent Apple, to pojawiają mi się dwa produkty: 

Nie wiedzieć czemu, laptop się pojawia z tego powodu ze jest kategoria laptop, a iphone bo jest taki producent. Cena się kompletnie nie zgadza, bo jest do 300. Dlaczego tak się dzieje? Metody, które używam podałem w pytaniu.

To jest moja atrapa bazy danych:

@Repository
public class InMemoryProductRepository implements ProductRepository {
    private List<Product> listOfProducts = new ArrayList<>();

    public InMemoryProductRepository() {
        Product iphone = new Product("P1234", "iPhone 5s", new BigDecimal(500));
        iphone.setDescription("Apple iPhone 5s, smartfon z 4-calowym ekranem o rozdzielczości 6401136 i 8-megapikselowym aparatem");
        iphone.setCategory("Smartfon");
        iphone.setManufacturer("Apple");
        iphone.setUnitsInStock(1000);
        Product laptop_dell = new Product("P1235", "Dell Inspiron", new BigDecimal(700));
        laptop_dell.setDescription("Dell Inspiron, 14-calowy laptop (czarny) procesorem Intel Core 3. generacji");
        laptop_dell.setCategory("Laptop");
        laptop_dell.setManufacturer("Dell");
        laptop_dell.setUnitsInStock(1000);
        Product tablet_Nexus = new Product("P1236", "Nexus 7", new BigDecimal(300));
        tablet_Nexus.setDescription("Google Nexus 7 jest najlżejszym 7-calowym tabletem z 4-rdzeniowym procesorem Qualcomm Snapdragon™ S4 Pro");
        tablet_Nexus.setCategory("Tablet");
        tablet_Nexus.setManufacturer("Google");
        tablet_Nexus.setUnitsInStock(1000);
        listOfProducts.add(iphone);
        listOfProducts.add(laptop_dell);
        listOfProducts.add(tablet_Nexus);
    }

Metoda wyglada finalnie tak

@RequestMapping("/{category}/{price}")
public String filterProducts(Model model, @PathVariable("category") String productCategory, @MatrixVariable(pathVar = "price") Map<String, List<String>> filterParams, @RequestParam("manufacturer") String manufacturer) {
    List<Product> productsByCategory = productService.getProductsByCategory(productCategory);
    List<Product> productsByManufacture = productService.getProductsByManufacturer(manufacturer);
    Set<Product> productsByPrice = productService.getProductsByFilter(filterParams);

    Set<Product> result = new HashSet<>();

    result.addAll(productsByCategory);
    result.addAll(productsByManufacture);
    result.addAll(productsByPrice);

    model.addAttribute("products", result);

    return "products";
}
komentarz 2 października 2018 przez paytakht Nowicjusz (100 p.)
edycja 2 października 2018 przez ScriptyChris
List productsByCategory = service.getProductsByCategory(category); 
List productsByManufacture = service.getProductsByManufacturer(manufacture); 
Set productsByPrice = service.getProductsByFilter(filter); 
Set result = new HashSet<>(); 
productsByCategory.forEach( product -> {result.add(product) } ); 
productsByManufacture.forEach( product -> { result.add(product) } ); 
productsByPrice.forEach( product -> {result.add(product) } ); 
model.addAttribute("products", result);

 

komentarz 2 października 2018 przez mbabane Szeryf (79,280 p.)

NIMuser 

Aż tak, super szczegółowo tego nie znam więc, nie potrafię na to pytanie odpowiedzieć. W książkach czy tutorialach, które do tej pory czytałem nic takiego nie było wspominane. Być może jest jakiś orm pod jave, który tak działa. jedyne co jest wykorzystywane to nie SQL a JPQL, wyglądem przypomina SQL, ale nie działa na tabelach bazy danych tylko na klasach Javy i ORM to zmienia na odpowiedni SQL.

@must

Powodem tego jest to, że wyniki poszczególnych metod getProductBy... są niezależne. Tzn. dany produkt zostaje wyszukany według kategorii, ale nie istnieje dla przedziału cenowego, więc przy złączeniu w kontrolerze, w końcowym zbiorze będzie znajdować się produkt, ktory nie pasuje do przedziału cenowego, ale pasuje do kategorii (to tak jakby pomiędzy kryteriami nie było AND tylko OR w zapytaniu SQL). Jeśli chcesz żeby było tak, że bierze wszystkie kryteria na raz pod uwagę, to trzeba zrobić albo dodatkowe filtrowanie przy złączeniu w kontrolerze, które pod uwagę bierze wszystkie kryteria, albo nową metodę w servicie, która od razu wyszuka produkty według wszystkich kryteriów na raz (wydajniejsze zdaje się będzie to drugie).

komentarz 2 października 2018 przez mbabane Szeryf (79,280 p.)

Aha  Hibernate ma coś takaiego jak API Criteria, w którym zapytania pisze się javowo, ale nie umiem jeszcze za bardzo z tego korzystać. Jakiś przykładzik z dokumentacji:

 List cats = session.createCriteria(Cat.class)
     .add( Restrictions.like("name", "Iz%") )
     .add( Restrictions.gt( "weight", new Float(minWeight) ) )
     .addOrder( Order.asc("age") )
     .list();

 

komentarz 2 października 2018 przez must Bywalec (2,980 p.)
do hibernata daleko, ale dzieki :P

Podobne pytania

0 głosów
1 odpowiedź 508 wizyt
pytanie zadane 14 października 2021 w Java przez Tajniakkk Użytkownik (600 p.)
+1 głos
1 odpowiedź 431 wizyt
pytanie zadane 14 sierpnia 2021 w Java przez DziQu Początkujący (420 p.)
0 głosów
1 odpowiedź 348 wizyt
pytanie zadane 4 maja 2020 w Java przez scrxts Nowicjusz (150 p.)

92,551 zapytań

141,397 odpowiedzi

319,528 komentarzy

61,936 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...