Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria
Gabungkan predikat dinamik yang selamat dari segi jenis dengan API Spesifikasi JPA untuk penapisan dipacu masa jalan.
Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria ialah pelajaran Panduan Lengkap Spring Boot 4 percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Panduan Lengkap Spring Boot 4, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Panduan Lengkap Spring Boot 4 merangkumi sejumlah 4 pelajaran.
Mengapa Penapisan Dinamik?
Aplikasi sebenar jarang membuat pertanyaan dengan kriteria tetap. Skrin carian produk mungkin menapis berdasarkan nama, kategori, julat harga, atau apa-apa gabungan yang dipilih pengguna semasa masa jalan.
Menulis kaedah repositori berasingan untuk setiap gabungan berkembang dengan cepat: findByName, findByNameAndCategory, findByCategoryAndPriceBetween... Pendekatan ini tidak boleh diskalakan.
API Specification Spring Data JPA membolehkan anda menggabungkan serpihan pertanyaan yang selamat dari segi jenis semasa masa jalan dan menggabungkannya dengan and() / or(). Dalam pelajaran ini, anda akan membina predikat dinamik dengan cara yang kemas.
Mendayakan Specification pada Repositori
Untuk menggunakan Specification, repositori anda mesti melanjutkan JpaSpecificationExecutor<T> selain JpaRepository.
Ini menambahkan kaedah terlebih beban seperti findAll(Specification<T>), findAll(Specification, Pageable), findOne(Specification), dan count(Specification).
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface ProductRepository
extends JpaRepository<Product, Long>,
JpaSpecificationExecutor<Product> {
}Anatomi Specification
Specification<T> ialah antara muka berfungsi dengan satu kaedah:
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
- root — entiti yang menjadi sumber pertanyaan anda; gunakan
root.get("field")untuk merujuk lajur. - query —
CriteriaQuerykeseluruhan (untuk pengisihan, distinct dan pengumpulan). - cb — kilang
CriteriaBuilderyang membina objekPredicatesepertiequal,likedangreaterThan.
Specification Pertama Anda
Berikut ialah Specification yang menapis produk berdasarkan nama kategori yang tepat. Amalan lazim adalah mendedahkan kaedah kilang yang mengembalikan Specification.
Perhatikan bahawa root.get("category") menelusuri entiti Category yang berkaitan, kemudian .get("name") mencapai medannya.
import org.springframework.data.jpa.domain.Specification;
public class ProductSpecs {
public static Specification<Product> hasCategory(String category) {
return (root, query, cb) ->
cb.equal(root.get("category").get("name"), category);
}
}Menggabungkan Specification
Kekuatan Specification terletak pada penggabungan. Gunakan pembantu statik dan pembantu tika pada antara muka tersebut:
Specification.allOf(...)/Specification.anyOf(...)— gabungkan banyak syarat.spec.and(other)— AND logik.spec.or(other)— OR logik.Specification.not(spec)— penafian.
Setiap penggabung mengembalikan Specification baharu, jadi rangkaian kekal tidak boleh diubah dan mudah dibaca.
Specification<Product> spec =
ProductSpecs.hasCategory("Laptops")
.and(ProductSpecs.priceLessThan(new BigDecimal("2000")));
List<Product> result = productRepository.findAll(spec);Membina Predikat Secara Bersyarat
Manfaat sebenar ialah memasang Specification hanya daripada penapis yang benar-benar diberikan oleh pengguna. Mulakan dengan gabungan kosong dan tambahkan kriteria yang bukan null.
Dalam Spring Boot 4, Specification.unrestricted() mengembalikan asas tanpa operasi yang sepadan dengan segala-galanya — titik permulaan neutral yang ideal.
public Specification<Product> build(ProductFilter f) {
Specification<Product> spec = Specification.unrestricted();
if (f.getName() != null) {
spec = spec.and(ProductSpecs.nameContains(f.getName()));
}
if (f.getCategory() != null) {
spec = spec.and(ProductSpecs.hasCategory(f.getCategory()));
}
if (f.getMaxPrice() != null) {
spec = spec.and(ProductSpecs.priceLessThan(f.getMaxPrice()));
}
return spec;
}LIKE, Julat dan Padanan Tanpa Mengira Huruf Besar Kecil
CriteriaBuilder menyediakan blok binaan yang diperlukan untuk penapis teks dan angka yang fleksibel:
cb.like(cb.lower(root.get("name")), "%" + term.toLowerCase() + "%")— padanan mengandungi tanpa mengira huruf besar kecil.cb.between(root.get("price"), min, max)— julat inklusif.cb.greaterThanOrEqualTo(...)/cb.lessThanOrEqualTo(...)— sempadan terbuka.
public static Specification<Product> nameContains(String term) {
return (root, query, cb) ->
cb.like(cb.lower(root.get("name")),
"%" + term.toLowerCase() + "%");
}
public static Specification<Product> priceLessThan(BigDecimal max) {
return (root, query, cb) ->
cb.lessThanOrEqualTo(root.get("price"), max);
}Specification Selamat daripada Null
Alternatif yang kemas berbanding perlindungan if: biarkan setiap kilang mengembalikan null apabila inputnya tiada. Spring Data menganggap Specification null (dan nilai null yang dikembalikan daripada toPredicate) sebagai "tiada sekatan" lalu melangkaunya semasa penggabungan.
Ini menjadikan pembina lebih rata, tetapi nyatakan dengan jelas — pengembalian null boleh mengejutkan pembaca, jadi dokumentasikan perkara tersebut.
public static Specification<Product> hasCategory(String category) {
return (root, query, cb) ->
category == null
? null
: cb.equal(root.get("category").get("name"), category);
}JOIN dalam Specification
Untuk perkaitan koleksi atau bagi mengelakkan masalah pemuatan malas, cipta Join eksplisit daripada root. Ini menjana SQL JOIN dan membolehkan anda menapis berdasarkan lajur entiti berkaitan.
Petua: apabila JOIN boleh menggandakan baris, panggil query.distinct(true) untuk mengelakkan induk pendua dalam hasil.
import jakarta.persistence.criteria.Join;
public static Specification<Product> hasTag(String tag) {
return (root, query, cb) -> {
Join<Product, Tag> tags = root.join("tags");
query.distinct(true);
return cb.equal(tags.get("label"), tag);
};
}Penomboran dan Pengisihan
Specification digabungkan dengan lancar dengan penomboran. Hantar Pageable bersama Specification dan Spring Data menggunakan WHERE, ORDER BY, LIMIT dan OFFSET dalam satu pertanyaan.
Page yang dikembalikan juga menjalankan pertanyaan count (menggunakan Specification yang sama), jadi anda mendapat jumlah elemen secara automatik.
Pageable pageable = PageRequest.of(0, 20, Sort.by("price").descending());
Page<Product> page = productRepository.findAll(build(filter), pageable);
long total = page.getTotalElements();
List<Product> items = page.getContent();Demo Penggabungan Kendiri
Specification ialah lambda, jadi logik penggabungan itu sendiri ialah Java biasa yang boleh difahami tanpa pangkalan data. Contoh boleh dijalankan ini meniru cara and()/or() melakukan pemendekan litar dengan menggabungkan predikat boolean dengan cara yang sama.
Ia menunjukkan model mental ini: Specification ialah predikat tertangguh yang anda gabungkan sebelum melaksanakannya.
import java.util.List;
import java.util.function.Predicate;
public class SpecDemo {
record Product(String name, String category, int price) {}
public static void main(String[] args) {
List<Product> products = List.of(
new Product("UltraBook", "Laptops", 1800),
new Product("GamerX", "Laptops", 2400),
new Product("OfficeMouse", "Accessories", 25)
);
Predicate<Product> spec = p -> p.category().equals("Laptops");
spec = spec.and(p -> p.price() <= 2000);
products.stream()
.filter(spec)
.forEach(p -> System.out.println(p.name()));
}
}Semakan Pantas
Anda sedang membina penapis dinamik yang setiap kriterianya adalah pilihan dan mungkin ada atau tiada. Anda mahukan Specification asas neutral yang sepadan dengan semua baris, kemudian menambah sekatan secara bersyarat. Apakah titik permulaan Spring Boot 4 yang betul?
Imbas Kembali
Anda telah mempelajari cara membina penapis dipacu masa jalan yang selamat dari segi jenis dengan API JPA Specification:
- Lanjutkan JpaSpecificationExecutor untuk mendayakan
findAll(Specification, ...). - Specification ialah lambda atas
(root, query, cb)yang mengembalikanPredicate. - Gabungkan dengan
and(),or(),not(), dan mulakan denganSpecification.unrestricted(). - Tambahkan sekatan secara bersyarat supaya hanya penapis yang diberikan mempengaruhi pertanyaan.
- Gunakan
cb.like/cb.lower,cb.betweendanroot.join(...)eksplisit bersamaquery.distinct(true)untuk pertanyaan yang lebih kaya. - Hantar Pageable untuk penomboran, pengisihan dan pertanyaan kiraan automatik.
Pola ini menggantikan berpuluh-puluh kaedah pencari yang ditulis secara manual dengan satu pembina yang kemas dan boleh digabungkan.
Pelajari Java dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 21
- Pelajaran
- 84
Soalan Lazim
Adakah pelajaran “Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria” percuma?
Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Panduan Lengkap Spring Boot 4, termasuk “Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Panduan Lengkap Spring Boot 4 merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria”?
Gabungkan predikat dinamik yang selamat dari segi jenis dengan API Spesifikasi JPA untuk penapisan dipacu masa jalan. Anda berlatih Panduan Lengkap Spring Boot 4 menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Panduan Lengkap Spring Boot 4?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Panduan Lengkap Spring Boot 4 di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.
Berapa lamakah pelajaran “Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Panduan Lengkap Spring Boot 4 ini?
Ya. Setiap pelajaran Panduan Lengkap Spring Boot 4 menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Kaedah Pertanyaan Terbitan dan Penyelesaian Kata Kunci
- Pertanyaan JPQL dan Asli dengan @Query
- Spesifikasi dan Penapisan Dinamik Berasaskan Kriteria
- Penomboran, Pengisihan dan Penstriman Hirisan