【问题标题】:Spring boot Dynamic QuerySpring Boot 动态查询
【发布时间】:2017-01-03 04:17:52
【问题描述】:

我的网络应用中有一个过滤器,允许按车辆类型、品牌、燃料、州和城市进行搜索,但所有这些过滤器都是可选的。

如何使用存储库来做到这一点。

控制器类

@RequestMapping(value = "/vehicle/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Iterable<Veiculo> findBySearch(@RequestParam Long vehicletype, @RequestParam Long brand, 
        @RequestParam Long model, @RequestParam Long year, 
        @RequestParam Long state, @RequestParam Long city) {
    return veiculoService.findBySearch(vehicletype, brand, model, year, state, city);
}

服务类

public Iterable<Vehicle> findBySearch(Long vehicletype, Long brand, Long model, Long year, Long state, Long city) {
    if(vehicletype != null){
        //TODO: filter by vehicletype
    }
    if(brand != null){
        //TODO: filter by brand
    }
    if(model != null){
        //TODO: filter by model
    }

    //OTHER FILTERS
    return //TODO: Return my repository with personal query based on filter
}

我还没有实现任何东西,因为我不明白如何做这个过滤器。

车辆类别

@Entity
@Table(name = "tb_veiculo")
public class Veiculo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "veiculo_opcionais", 
    joinColumns = @JoinColumn(name = "veiculo_id", referencedColumnName = "id"),
    inverseJoinColumns = @JoinColumn(name = "opcional_id", referencedColumnName = "id"))
    private List<Opcional> opcionais;

    @JsonIgnore
    @OneToMany(mappedBy = "veiculo", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<VeiculoImagem> veiculoImagens;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "cambio_id", foreignKey = @ForeignKey(name = "fk_cambio"))
    private Cambio cambio;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "combustivel_id", foreignKey = @ForeignKey(name = "fk_combustivel"))
    private Combustivel combustivel;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "cor_id", foreignKey = @ForeignKey(name = "fk_cor"))
    private Cor cor;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "modelo_id", foreignKey = @ForeignKey(name = "fk_modelo"))
    private Modelo modelo;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "usuario_id", foreignKey = @ForeignKey(name = "fk_usuario"))
    private Usuario usuario;

    @Column(name = "anoFabricacao", nullable = false)
    private int anoFabricacao;

    @Column(name = "anoModelo", nullable = false)
    private int anoModelo;

    @Column(name = "quilometragem", nullable = false)
    private int quilometragem;

    @Column(name = "porta", nullable = false)
    private int porta;

    @Column(name = "valor", nullable = false)
    private double valor;

    //GETTERS AND SETTERS

车辆类型和品牌来自另一张表...我是葡萄牙人,我已将代码翻译成英文...

当它发生时,我需要做什么?

【问题讨论】:

  • 如果您在谈论存储库,您是指 Spring 数据 JPA 存储库吗?如果是这种情况,那么我认为这个问题与stackoverflow.com/questions/39015244/… 重复
  • 一个你也可以使用@matrixvariable的简短说明

标签: java spring-boot


【解决方案1】:

您可以使用 Spring 的规范 API,它是 JPA 标准 API 的包装器,允许您创建更多动态查询。

在你的情况下,我假设你有一个 Vehicle 实体,它有一个字段 brandyearstatecity、...。

如果是这样,你可以编写如下规范:

public class VehicleSpecifications {
    public static Specification<Vehicle> withCity(Long city) {
        if (city == null) {
            return null;
        } else {
            // Specification using Java 8 lambdas
            return (root, query, cb) -> cb.equal(root.get("city"), city);
        }
    }

    // TODO: Implement withModel, withVehicleType, withBrand, ...
}

如果您必须进行连接(例如,如果您想检索 Vehicle.city.id),那么您可以使用:

return (root, query, cb) -> cb.equal(root.join("city").get("id"), city);

现在,在您的存储库中,您必须确保从 JpaSpecificationExecutor 扩展,例如:

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

}

通过从此接口扩展,您将可以访问findAll(Specification spec) 方法,该方法允许您执行规范。如果需要组合多个规范(通常一个过滤器 = 一个规范),可以使用Specifications 类:

repository.findAll(where(withCity(city))
    .and(withBrand(brand))
    .and(withModel(model))
    .and(withVehicleType(type))
    .and(withYear(year))
    .and(withState(state)));

在上面的代码示例中,我对Specifications.whereVehicleSpecifications.* 使用了静态导入,以使其看起来更具声明性。

您不必在此处编写 if() 语句,因为我们已经在 VehicleSpecifications.withCity() 中编写了它们。只要你从这些方法返回null,它们就会被Spring忽略。

【讨论】:

  • 无法在此 ManagedType 上找到具有给定名称 [vehicletype] 的属性,我需要做什么?
  • @FelipeA。 Vehicle 上有一个名为 vehicletype 的字段吗?
  • 另一张表中的车辆类型、品牌、城市和州......当它发生时,我需要做什么?
  • @FelipeA。您是否以某种方式链接了这些实体?根据您的问题,我不清楚车辆类型来自哪里。但就像我在回答中所说的那样,如果您必须加入另一个表/实体,则使用 root.join("veiculoImagens", JoinType.LEFT).get("id") 在这种情况下,它将检索链接到 Veiculo 的任何 VeiculoImagemid 属性。
  • @Jonny 在规范本身中,您遍历您的列表,执行cb.equal(...) 并将所有这些收集到一个数组(Predicate[]),然后您可以使用cb.or(array)
猜你喜欢
  • 2018-07-06
  • 2018-10-11
  • 2019-07-16
  • 1970-01-01
  • 1970-01-01
  • 2021-02-10
  • 2016-10-03
  • 2020-11-13
  • 1970-01-01
相关资源
最近更新 更多