Можно ли использовать Query by Example в Spring Boot для замены условной логики при использовании @RequestParams?

У меня есть следующий код для приложения Spring Boot:

Сущность:

@Proxy(lazy = false)
public class Vehicle {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String type;
  private String make;
  private String model;
  private Integer year;

Контроллер:

@RequestMapping("/vehicles")
public class VehicleController {

  @Autowired
  private VehicleService vehicleService;

  //GET method to get all vehicles, or specify a parameter
  @GetMapping
  @ResponseStatus(HttpStatus.OK)
  public List<Vehicle> getAllVehicles(
      @RequestParam(required = false) Map<String, String> allParams) {
    return vehicleService.getVehicles(allParams);
  }

Услуга:

  private VehicleRepository vehicleRepository;

  /**
   * Gets the full list of vehicles based on the provided parameters. If no parameters are
   * presented, then returns the entire list of vehicles
   *
   * @param allParams A map of all possible parameters that can be passed through
   * @return list of vehicles
   */
  @Override
  public List<Vehicle> getVehicles(Map<String, String> allParams) {
    //gather all of the possible parameters that can be passed through
    String type = allParams.get("type");
    String make = allParams.get("make");
    String model = allParams.get("model");
    Integer year;
    try {
      year = Integer.parseInt(allParams.get("year"));
    } catch (NumberFormatException n) {
      year = 0;
    }

    if (type != null && make != null && model != null && year != 0) {
      return vehicleRepository.findByTypeAndMakeAndModelAndYear(type, make, model, year);
    }
    if (make != null && type == null && model != null && year != 0) {
      return vehicleRepository.findByMakeAndModelAndYear(make, model, year);
    }
    if (type != null && make == null && model != null && year != 0) {
      return vehicleRepository.findByTypeAndModelAndYear(type, model, year);
    }
    if (type != null && make != null && model == null && year != 0) {
      return vehicleRepository.findByTypeAndMakeAndYear(type, make, year);
    }
    if (model != null && type == null && make == null && year != 0) {
      return vehicleRepository.findByModelAndYear(model, year);
    }
    if (make != null && type == null && model == null && year != 0) {
      return vehicleRepository.findByMakeAndYear(make, year);
    }
    if (type != null && make == null && model == null && year != 0) {
      return vehicleRepository.findByTypeAndYear(type, year);
    }
    if (type != null && make != null && model != null) {
      return vehicleRepository.findByTypeAndMakeAndModel(type, make, model);
    }
    if (make != null && type == null && model != null) {
      return vehicleRepository.findByMakeAndModel(make, model);
    }
    if (type != null && make == null && model != null) {
      return vehicleRepository.findByTypeAndModel(type, model);
    }
    if (type != null && make != null) {
      return vehicleRepository.findByTypeAndMake(type, make);
    }
    if (type != null) {
      return vehicleRepository.findByType(type);
    }
    if (make != null) {
      return vehicleRepository.findByMake(make);
    }
    if (model != null) {
      return vehicleRepository.findByModel(model);
    }
    if (year != 0) {
      return vehicleRepository.findByYear(year);
    }

    return vehicleRepository.findAll();
  }

Репозиторий:

public interface VehicleRepository extends JpaRepository<Vehicle, Long> {

  List<Vehicle> findByTypeAndMakeAndModelAndYear(String type, String make, String model,
      Integer year);

  List<Vehicle> findByMakeAndModelAndYear(String make, String model, Integer year);

  List<Vehicle> findByTypeAndModelAndYear(String type, String model, Integer year);

  List<Vehicle> findByTypeAndMakeAndYear(String type, String make, Integer year);

  List<Vehicle> findByModelAndYear(String model, Integer year);

  List<Vehicle> findByMakeAndYear(String make, Integer year);

  List<Vehicle> findByTypeAndYear(String type, Integer year);

  List<Vehicle> findByTypeAndMakeAndModel(String type, String make, String model);

  List<Vehicle> findByMakeAndModel(String make, String model);

  List<Vehicle> findByTypeAndModel(String type, String model);

  List<Vehicle> findByTypeAndMake(String type, String make);

  List<Vehicle> findByType(String type);

  List<Vehicle> findByMake(String make);

  List<Vehicle> findByModel(String model);

  List<Vehicle> findByYear(Integer year);

}

Очевидно, что сервисный уровень имеет много условной логики для покрытия нескольких комбинаций переданных параметров. Хотя это достигает моей цели учета любых пропущенных запросов (например, http://localhost:8080/vehicles?make=&model=&year=&type=), я хочу выяснить, есть ли способ реорганизовать код, чтобы сделать его более эффективным. Будет ли запрос на примере из Spring достаточным способом решить эту проблему или есть лучший способ? (или этот код настолько хорош, насколько я могу его сделать?)

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
140
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Рекомендую Spring JPA ExampleMatcher. Это один из самых простых методов запроса JPA. Вы создаете переменную probe, которая определяет поиск в базе данных. В запросы включаются только ненулевые значения, для получения дополнительной информации Spring Data JPA Query by Example. Кроме того, я использовал библиотеку Lombok для аннотации @Data. Вы можете отказаться от него, если вы не предпочитаете.

Автомобиль.java

@Data
@Entity
@Table
public class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String type;
    private String make;
    private String model;
    private Integer year;
}

VehicleController.java

@RequestMapping("/vehicles")
@RestController
public class VehicleController{

    @Autowired
    private VehicleService vehicleService;

    //GET method to get all vehicles, or specify a parameter
    @GetMapping
    @ResponseStatus(HttpStatus.OK)
    public List<Vehicle> getAllVehicles(
            @RequestParam(required = false) Map<String, String> allParams) {
        return vehicleService.getVehicles(allParams);
    }
}

VehicleRepository.java

public interface VehicleRepository extends JpaRepository<Vehicle, Long> {
}

VehicleService.java

@Service
public class VehicleService {
    @Autowired
    private VehicleRepository vehicleRepository;

    public List<Vehicle> getVehicles(Map<String, String> allParams) {
        if (allParams.isEmpty()) {
            return vehicleRepository.findAll();
        }
        Vehicle probe = new Vehicle();
        if (allParams.containsKey("type")) {
            probe.setType(allParams.get("type"));
        }
        if (allParams.containsKey("make")) {
            probe.setMake(allParams.get("make"));
        }
        if (allParams.containsKey("year")) {
            probe.setYear(Integer.parseInt(allParams.get("year")));
        }
        if (allParams.containsKey("model")) {
            probe.setModel(allParams.get("model"));
        }
        Example<Vehicle> example = Example.of(probe,
                ExampleMatcher.matchingAll()
                        .withIgnoreCase());
        return vehicleRepository.findAll(example);
    }
}

Это то, о чем я думал, но я все еще новичок в Spring и не совсем понял эту концепцию. Но я могу подтвердить, что это все еще делает то, что мне нужно! Спасибо!

Cody Walker 24.12.2020 17:19

Другие вопросы по теме