Необязательные свойства для фильтрации объектов по методу GET - PullRequest
0 голосов
/ 09 февраля 2020

В настоящее время у меня есть объект Sneaker , определенный как

@Entity(name = "sneaker")
public class Sneaker extends Product {

    @Column
    private BigDecimal size;

    @Enumerated(EnumType.STRING)
    @Column
    private BrandType brand;

    ...

    // getters, setters, constructors omitted
}

и метод @ RestController get, который принимает необязательные параметры для фильтрации объектов базы данных в зависимости от их свойств.

 @GetMapping
    public ResponseEntity<List<Sneaker>> getSneakers(
            @RequestParam Optional<List<BrandType>> brands,
            @RequestParam Optional<List<BigDecimal>> sizes
    ) {
        List<Sneaker> sneakers;

        if (brands.isPresent() && sizes.isEmpty()) {
            sneakers = sneakerService.getAllByBrands(Util.filterNullItems(brands.get()));
        } else if (brands.isEmpty() && sizes.isPresent()) {
            sneakers = sneakerService.getAllBySize(sizes.get());
        } else if (brands.isPresent() && sizes.isPresent()) {
            sneakers = sneakerService.getAllByBrandAndSize(brands.get(), sizes.get());
        } else {
            sneakers = sneakerService.getAll();
        }

        if (sneakers.isEmpty())
            throw new RuntimeException("No Sneakers were found");

        return ResponseEntity
                .ok(sneakers);
    }

Как лучше всего запрашивать базу данных в зависимости от заданных параметров? Я предполагаю, что несколько , если еще операторов в контроллере - не лучший подход, так как добавление дополнительных свойств к объекту расширит мой код в геометрической прогрессии и создаст беспорядок. Должен ли я запрашивать все (или только по некоторым свойствам) объекты и фильтровать их в стиле Java с потоками?

1 Ответ

2 голосов
/ 09 февраля 2020

Я бы предложил использовать org.springframework.data.jpa.domain.Specification

public class SneakerSpecifications {
    public static Specification<Sneaker> sizeIn(Optional<List<BigDecimal>> sizes) {
        return (root, query, builder) -> 
            sizes.isPresent() ? 
            root.get("size").in(sizes.get()) :
            builder.conjunction(); // to ignore this clause
    }

    public static Specification<Sneaker> brandIn(Optional<List<BrandType>> brands) {
        return (root, query, builder) -> 
            brands.isPresent() ? 
            root.get("brand").in(brands.get()) :
            builder.conjunction(); // to ignore this clause
    }
}

Тогда ваши SneakerRepository должны расширяться org.springframework.data .jpa.repository.JpaSpecificationExecutor

@Repository
public interface SneakerRepository 
    extends JpaRepository<Sneaker, Long>, JpaSpecificationExecutor<Sneaker> {

}

Ваш метод обслуживания:

@Service
public class SneakerService {    

   @Autowired
   SneakerRepository repository;

    public List<Sneaker> getSneakers(Optional<List<BrandType>> brands, Optional<List<BigDecimal>> sizes) {
             Specification<Sneaker> spec = 
                 Specifications.where(SneakerSpecifications.brandIn(brands))
                 .and(SneakerSpecifications.sizeIn(sizes));

             return repository.findAll(spec);        
        }
    }

Если вы не используете Spring Data Jpa, такой же подход можно использовать с Criteria API или Querydsl

Дополнительная информация здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...