在使用@RequestParams 时,Spring Boot 中的Query by Example 可以用来替代条件逻辑吗?
Can Query by Example in Spring Boot be used to substitute conditional logic when using @RequestParams?
我有以下 Spring 引导应用程序代码:
实体:
@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 中的示例查询是否足以解决此问题,还是有更好的方法? (或者这段代码和我能做的一样好吗?)
我推荐Spring JPA ExampleMatcher
。它是最简单的 JPA 查询方法之一。您创建了一个 probe
变量来定义对数据库的搜索。查询中仅包含非空值,有关详细信息,Spring Data JPA Query by Example。此外,我还使用了 Lombok
库作为 @Data
注释。如果您不喜欢,可以丢弃它。
Vehicle.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 引导应用程序代码:
实体:
@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 中的示例查询是否足以解决此问题,还是有更好的方法? (或者这段代码和我能做的一样好吗?)
我推荐Spring JPA ExampleMatcher
。它是最简单的 JPA 查询方法之一。您创建了一个 probe
变量来定义对数据库的搜索。查询中仅包含非空值,有关详细信息,Spring Data JPA Query by Example。此外,我还使用了 Lombok
库作为 @Data
注释。如果您不喜欢,可以丢弃它。
Vehicle.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);
}
}