programing

스프링 부트 동적 쿼리

javajsp 2023. 9. 1. 20:35

스프링 부트 동적 쿼리

제 웹 앱에는 차량 종류, 브랜드, 연료, 주 및 도시별로 검색할 수 있는 필터가 있지만 이 모든 필터는 선택 사항입니다.

리포지토리를 사용하여 이 작업을 수행하려면 어떻게 해야 합니까?

컨트롤러 클래스

@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의 API 규격을 사용할 수 있습니다. 이 규격은 JPA의 API 기준을 둘러싼 래퍼로, 보다 동적인 쿼리를 만들 수 있습니다.

당신의 경우, 저는 당신이 가지고 있다고 가정합니다.Vehicle필드가 있는 엔티티brand,year,state,city, ... .

그렇다면 다음과 같은 사양을 작성할 수 있습니다.

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> {

}

이 인터페이스에서 확장하면 사양을 실행할 수 있는 방법에 액세스할 수 있습니다.여러 규격(보통 하나의 필터 = 하나의 규격)을 결합해야 하는 경우 클래스를 사용할 수 있습니다.

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

위의 코드 예제에서는 정적 가져오기를 사용합니다.Specifications.where에 대해서도VehicleSpecifications.*좀 더 선언적으로 보이게 하기 위해서요

당신은 쓸 필요가 없습니다.if()우리가 이미 그것들을 썼기 때문에 여기에 진술.VehicleSpecifications.withCity()당신이 돌아오는 한null이러한 방법들로부터 그들은 Spring에 의해 무시될 것입니다.

언급URL : https://stackoverflow.com/questions/39167189/spring-boot-dynamic-query