Perbezaan dalam Anotasi @Valid dan @Validated pada Musim Bunga

1. Gambaran keseluruhan

Dalam tutorial ini cepat, kami akan memberi tumpuan kepada perbezaan antara @Valid dan @Validated penjelasan dalam Spring.

Mengesahkan input pengguna adalah fungsi biasa di kebanyakan aplikasi kami. Dalam Ekosistem Java, kami secara khusus menggunakan API Pengesahan Kacang Standard Java untuk menyokong ini. Selain itu, ini juga terintegrasi dengan Spring dari versi 4.0 dan seterusnya. The @Valid dan @Validated anotasi berpunca dari API Standard Bean ini .

Pada bahagian seterusnya, mari kita perhatikan secara terperinci.

2. @Valid dan @Validated Anotasi

Pada musim bunga, kami menggunakan anotasi @Valid JSR-303 untuk pengesahan tahap kaedah . Selain itu, kami juga menggunakannya untuk menandakan atribut anggota untuk pengesahan . Walau bagaimanapun, anotasi ini tidak menyokong pengesahan kumpulan.

Kumpulan membantu mengehadkan kekangan yang berlaku semasa pengesahan. Satu kes penggunaan tertentu adalah penyihir UI. Di sini, pada langkah pertama, kita mungkin mempunyai subkumpulan bidang tertentu. Pada langkah seterusnya, mungkin ada kumpulan lain yang tergolong dalam kacang yang sama. Oleh itu kita perlu menerapkan kekangan pada bidang terhad ini pada setiap langkah, tetapi @Valid tidak menyokong ini.

Dalam kes ini, untuk peringkat kumpulan, kita harus menggunakan Spring's @Validated, yang merupakan varian dari JSR-303's @Valid ini . Ini digunakan pada tahap kaedah. Dan untuk menandakan atribut ahli, kami terus menggunakan anotasi @Valid .

Sekarang, mari kita selami dan melihat penggunaan anotasi ini dengan contoh.

3. Contoh

Mari pertimbangkan borang pendaftaran pengguna ringkas yang dikembangkan menggunakan Spring Boot. Sebagai permulaan, kami hanya mempunyai nama dan atribut kata laluan :

public class UserAccount { @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; // standard constructors / setters / getters / toString } 

Seterusnya, mari lihat pengawal. Di sini, kita akan mempunyai kaedah saveBasicInfo dengan anotasi @Valid untuk mengesahkan input pengguna:

@RequestMapping(value = "/saveBasicInfo", method = RequestMethod.POST) public String saveBasicInfo( @Valid @ModelAttribute("useraccount") UserAccount useraccount, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "error"; } return "success"; }

Sekarang mari kita menguji kaedah ini:

@Test public void givenSaveBasicInfo_whenCorrectInput_thenSuccess() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfo") .accept(MediaType.TEXT_HTML) .param("name", "test123") .param("password", "pass")) .andExpect(view().name("success")) .andExpect(status().isOk()) .andDo(print()); }

Setelah mengesahkan bahawa ujian berjalan dengan jayanya, sekarang mari kita memperluas fungsi. Langkah logik seterusnya adalah menukar ini ke borang pendaftaran pelbagai langkah, seperti yang berlaku pada kebanyakan ahli sihir. Langkah pertama dengan nama dan kata laluan tidak berubah. Pada langkah kedua, kami akan mengambil maklumat tambahan seperti usia dan telefon . Oleh itu, kami akan mengemas kini objek domain kami dengan medan tambahan ini:

public class UserAccount { @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; @Min(value = 18, message = "Age should not be less than 18") private int age; @NotBlank private String phone; // standard constructors / setters / getters / toString } 

Namun, kali ini kita akan melihat bahawa ujian sebelumnya gagal. Ini kerana kita tidak melewati usia dan bidang telefon , yang masih belum ada dalam gambar di UI . Untuk menyokong tingkah laku ini, kami memerlukan pengesahan kumpulan dan anotasi @Validated .

Untuk ini, kita perlu mengelompokkan medan membuat dua kumpulan berbeza. Pertama, kita perlu membuat dua muka penanda. Yang terpisah untuk setiap kumpulan atau setiap langkah. Kami boleh merujuk artikel kami mengenai pengesahan kumpulan untuk pelaksanaannya dengan tepat. Di sini, mari kita fokus pada perbezaan penjelasan.

Kami akan mempunyai antara muka BasicInfo untuk langkah pertama dan AdvanceInfo untuk langkah kedua. Selanjutnya, kami akan mengemas kini kelas UserAccount kami untuk menggunakan antara muka penanda seperti berikut:

public class UserAccount { @NotNull(groups = BasicInfo.class) @Size(min = 4, max = 15, groups = BasicInfo.class) private String password; @NotBlank(groups = BasicInfo.class) private String name; @Min(value = 18, message = "Age should not be less than 18", groups = AdvanceInfo.class) private int age; @NotBlank(groups = AdvanceInfo.class) private String phone; // standard constructors / setters / getters / toString } 

Sebagai tambahan, kami kini akan mengemas kini pengawal kami untuk menggunakan anotasi @Validated dan bukannya @Valid :

@RequestMapping(value = "/saveBasicInfoStep1", method = RequestMethod.POST) public String saveBasicInfoStep1( @Validated(BasicInfo.class) @ModelAttribute("useraccount") UserAccount useraccount, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "error"; } return "success"; }

Hasil daripada kemas kini ini, ujian kami kini berjaya. Sekarang mari kita uji kaedah baru ini:

@Test public void givenSaveBasicInfoStep1_whenCorrectInput_thenSuccess() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfoStep1") .accept(MediaType.TEXT_HTML) .param("name", "test123") .param("password", "pass")) .andExpect(view().name("success")) .andExpect(status().isOk()) .andDo(print()); }

Ini juga berjaya. Oleh itu kita dapat melihat bagaimana penggunaan @Validated sangat penting untuk pengesahan kumpulan.

Seterusnya, mari kita lihat bagaimana @Valid penting untuk mencetuskan pengesahan atribut bersarang.

4. Menggunakan Anotasi @Valid untuk Menandakan Objek Bersarang

The @Valid anotasi digunakan untuk menandakan sifat-sifat bersarang khususnya . Ini mencetuskan pengesahan objek bersarang. Sebagai contoh, dalam senario semasa kami, mari buat objek UserAddress :

public class UserAddress { @NotBlank private String countryCode; // standard constructors / setters / getters / toString }

Untuk memastikan pengesahan objek bersarang ini, kami akan menghiasi atribut dengan penjelasan @Valid :

public class UserAccount { //... @Valid @NotNull(groups = AdvanceInfo.class) private UserAddress useraddress; // standard constructors / setters / getters / toString }

5. Kebaikan dan Kekurangan

Mari kita lihat beberapa kebaikan dan keburukan menggunakan @Valid dan @Validated penjelasan dalam Spring.

The @Valid anotasi memastikan pengesahan keseluruhan objek. Yang penting, ia melakukan pengesahan keseluruhan grafik objek. Walau bagaimanapun, ini menimbulkan masalah untuk senario yang hanya memerlukan pengesahan separa.

Sebaliknya, kita boleh menggunakan @Validated untuk pengesahan kumpulan, termasuk pengesahan separa di atas. Namun, dalam hal ini, entiti yang disahkan harus mengetahui peraturan pengesahan untuk semua kumpulan atau kes penggunaan yang digunakannya. Di sini kita mencampurkan kebimbangan, oleh itu ini boleh menghasilkan anti-corak.

6. Kesimpulannya

Dalam tutorial ringkas ini, kami meneroka perbezaan utama antara @Valid dan @Validated Annotations.

Sebagai kesimpulan, untuk sebarang pengesahan asas, kami akan menggunakan penjelasan JSR @Valid dalam kaedah panggilan kami. Sebaliknya, untuk sebarang pengesahan kumpulan, termasuk urutan kumpulan, kami perlu menggunakan anotasi Spring @Validated dalam panggilan kaedah kami. The @Valid anotasi juga diperlukan untuk mencetuskan pengesahan hartanah bersarang.

Seperti biasa, kod yang disajikan dalam artikel ini terdapat di GitHub.