Validasi di Spring Boot

1. Ikhtisar

Dalam hal memvalidasi input pengguna, Spring Boot memberikan dukungan yang kuat untuk tugas umum namun penting ini langsung dari kotaknya.

Meskipun Spring Boot mendukung integrasi tanpa batas dengan validator kustom, standar de-facto untuk melakukan validasi adalah Hibernate Validator , implementasi referensi kerangka Validasi Bean.

Dalam tutorial ini, kita akan melihat cara memvalidasi objek domain di Spring Boot .

2. Dependensi Maven

Dalam kasus ini, kita akan belajar cara memvalidasi objek domain di Spring Boot dengan membuat pengontrol REST dasar.

Pengontrol pertama-tama akan mengambil objek domain, kemudian akan memvalidasinya dengan Hibernate Validator, dan terakhir akan menyimpannya ke dalam database H2 dalam memori.

Ketergantungan proyek cukup standar:

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-data-jpa   com.h2database h2 1.4.197 runtime 

Seperti yang ditunjukkan di atas, kami menyertakan spring-boot-starter-web di file pom.xml kami karena kami akan membutuhkannya untuk membuat pengontrol REST. Selain itu, pastikan untuk memeriksa versi terbaru spring-boot-starter-jpa dan database H2 di Maven Central.

Dimulai dengan Boot 2.3, kita juga perlu menambahkan dependensi validasi spring-boot-starter secara eksplisit :

 org.springframework.boot spring-boot-starter-validation 

3. Kelas Domain Sederhana

Dengan dependensi proyek kita sudah ada, selanjutnya kita perlu mendefinisikan contoh kelas entitas JPA, yang perannya hanya akan menjadi pemodelan pengguna.

Mari kita lihat kelas ini:

@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @NotBlank(message = "Name is mandatory") private String name; @NotBlank(message = "Email is mandatory") private String email; // standard constructors / setters / getters / toString }

Implementasi kelas entitas Pengguna kami memang cukup lemah, tetapi ini menunjukkan secara singkat bagaimana menggunakan batasan Validasi Bean untuk membatasi bidang nama dan email .

Demi kesederhanaan, kami membatasi bidang target hanya dengan menggunakan batasan @NotBlank . Juga, kami menentukan pesan kesalahan dengan atribut pesan .

Oleh karena itu, saat Spring Boot memvalidasi instance kelas, kolom yang dibatasi tidak boleh kosong dan panjangnya yang dipotong harus lebih besar dari nol .

Selain itu, Validasi Bean menyediakan banyak batasan praktis lainnya selain @NotBlank. Ini memungkinkan kita untuk menerapkan dan menggabungkan aturan validasi yang berbeda ke kelas yang dibatasi. Untuk informasi lebih lanjut, silakan baca dokumen validasi kacang resmi.

Karena kita akan menggunakan Spring Data JPA untuk menyimpan pengguna ke database H2 dalam memori, kita juga perlu mendefinisikan antarmuka repositori sederhana untuk memiliki fungsionalitas CRUD dasar pada objek Pengguna :

@Repository public interface UserRepository extends CrudRepository {}

4. Menerapkan Pengontrol REST

Tentu saja, kita perlu menerapkan lapisan yang memungkinkan kita mendapatkan nilai yang ditetapkan ke bidang dibatasi objek Pengguna kita .

Oleh karena itu, kami dapat memvalidasinya dan melakukan beberapa tugas lebih lanjut, bergantung pada hasil validasi.

Spring Boot membuat proses yang tampaknya rumit ini sangat sederhana melalui penerapan pengontrol REST.

Mari kita lihat implementasi pengontrol REST:

@RestController public class UserController { @PostMapping("/users") ResponseEntity addUser(@Valid @RequestBody User user) { // persisting the user return ResponseEntity.ok("User is valid"); } // standard constructors / other methods } 

Dalam konteks Spring REST, implementasi metode addUser () cukup standar.

Tentu saja, bagian yang paling relevan adalah penggunaan anotasi @Valid .

Ketika Spring Boot menemukan argumen yang dianotasi dengan @Valid , itu secara otomatis mem -bootstrap implementasi JSR 380 default - Hibernate Validator - dan memvalidasi argumen.

Jika argumen target gagal untuk melewati validasi, Spring Boot akan menampilkan pengecualian MethodArgumentNotValidException .

5. Anotasi @ExceptionHandler

Meskipun sangat berguna untuk memiliki Spring Boot yang memvalidasi objek User yang diteruskan ke metode addUser () secara otomatis, aspek yang hilang dari proses ini adalah bagaimana kami memproses hasil validasi.

The @ExceptionHandler penjelasan memungkinkan kita untuk menangani jenis tertentu pengecualian melalui satu metode tunggal.

Oleh karena itu, kami dapat menggunakannya untuk memproses kesalahan validasi:

@ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public Map handleValidationExceptions( MethodArgumentNotValidException ex) { Map errors = new HashMap(); ex.getBindingResult().getAllErrors().forEach((error) -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return errors; }

Kami menetapkan pengecualian MethodArgumentNotValidException sebagai pengecualian yang akan ditangani. Akibatnya, Spring Boot akan memanggil metode ini jika objek User yang ditentukan tidak valid .

Metode menyimpan nama dan pesan kesalahan pasca-validasi dari setiap bidang yang tidak valid di Peta. Selanjutnya mengirimkan Peta kembali ke klien sebagai representasi JSON untuk diproses lebih lanjut.

Sederhananya, pengontrol REST memungkinkan kita untuk dengan mudah memproses permintaan ke titik akhir yang berbeda, memvalidasi objek Pengguna , dan mengirim tanggapan dalam format JSON.

Desainnya cukup fleksibel untuk menangani respons pengontrol melalui beberapa tingkatan web, mulai dari mesin templat seperti Thymeleaf, hingga kerangka kerja JavaScript berfitur lengkap seperti Angular.

6. Menguji Kontroler REST

Kami dapat dengan mudah menguji fungsionalitas pengontrol REST kami dengan uji integrasi.

Mari mulai mengejek / melakukan autowiring implementasi antarmuka UserRepository , bersama dengan instance UserController , dan objek MockMvc :

@RunWith(SpringRunner.class) @WebMvcTest @AutoConfigureMockMvc public class UserControllerIntegrationTest { @MockBean private UserRepository userRepository; @Autowired UserController userController; @Autowired private MockMvc mockMvc; //... } 

Karena kami hanya menguji lapisan web, kami menggunakan anotasi @WebMvcTest . Ini memungkinkan kita menguji permintaan dan respons dengan mudah menggunakan kumpulan metode statis yang diterapkan oleh kelas MockMvcRequestBuilders dan MockMvcResultMatchers .

Sekarang mari kita uji metode addUser () dengan objek Pengguna yang valid dan tidak valid yang diteruskan di badan permintaan:

@Test public void whenPostRequestToUsersAndValidUser_thenCorrectResponse() throws Exception { MediaType textPlainUtf8 = new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8")); String user = "{\"name\": \"bob\", \"email\" : \"[email protected]\"}"; mockMvc.perform(MockMvcRequestBuilders.post("/users") .content(user) .contentType(MediaType.APPLICATION_JSON_UTF8)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content() .contentType(textPlainUtf8)); } @Test public void whenPostRequestToUsersAndInValidUser_thenCorrectResponse() throws Exception { String user = "{\"name\": \"\", \"email\" : \"[email protected]\"}"; mockMvc.perform(MockMvcRequestBuilders.post("/users") .content(user) .contentType(MediaType.APPLICATION_JSON_UTF8)) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andExpect(MockMvcResultMatchers.jsonPath("$.name", Is.is("Name is mandatory"))) .andExpect(MockMvcResultMatchers.content() .contentType(MediaType.APPLICATION_JSON_UTF8)); } } 

Selain itu, kita dapat menguji API pengontrol REST menggunakan aplikasi pengujian siklus hidup API gratis , seperti Postman.

7. Menjalankan Aplikasi Contoh

Akhirnya, kita dapat menjalankan proyek contoh kita dengan metode main () standar :

@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner run(UserRepository userRepository) throws Exception { return (String[] args) -> { User user1 = new User("Bob", "[email protected]"); User user2 = new User("Jenny", "[email protected]"); userRepository.save(user1); userRepository.save(user2); userRepository.findAll().forEach(System.out::println); }; } } 

Seperti yang diharapkan, kita akan melihat beberapa objek Pengguna dicetak di konsol.

Permintaan POST ke // localhost: 8080 / users endpoint dengan objek User yang valid akan mengembalikan String "User is valid".

Demikian pula, permintaan POST dengan objek Pengguna tanpa nama dan nilai email akan mengembalikan respons berikut:

{ "name":"Name is mandatory", "email":"Email is mandatory" }

8. Kesimpulan

Di artikel ini, kami mempelajari dasar-dasar melakukan validasi di Spring Boot .

Seperti biasa, semua contoh yang ditampilkan dalam artikel ini tersedia di GitHub.