Apa yang ditunjukkan oleh anotasi @Valid di Spring?

88

Dalam contoh berikut, ScriptFileparameter ditandai dengan @Validanotasi.

Apa @Validfungsi anotasi?

@RequestMapping(value = "/scriptfile", method = RequestMethod.POST)    
public String create(@Valid ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        
    if (result.hasErrors()) {        
        modelMap.addAttribute("scriptFile", scriptFile);            
        modelMap.addAttribute("showcases", ShowCase.findAllShowCases());            
        return "scriptfile/create";            
    }        
    scriptFile.persist();        
    return "redirect:/scriptfile/" + scriptFile.getId();        
}    
Gary Ford
sumber

Jawaban:

63

Ini untuk tujuan validasi.

Validasi Adalah umum untuk memvalidasi model setelah mengikat input pengguna padanya. Spring 3 memberikan dukungan untuk validasi deklaratif dengan JSR-303. Dukungan ini diaktifkan secara otomatis jika penyedia JSR-303, seperti Hibernate Validator, ada di jalur kelas Anda. Saat diaktifkan, Anda dapat memicu validasi cukup dengan membuat anotasi parameter metode Controller dengan anotasi @Valid: Setelah mengikat parameter POST yang masuk, AppointmentForm akan divalidasi; dalam hal ini, untuk memverifikasi nilai bidang tanggal tidak nihil dan terjadi di masa mendatang.


Lihat di sini untuk info lebih lanjut:
http://blog.springsource.com/2009/11/17/spring-3-type-conversion-and-validation/

mhshams
sumber
37

Menambah jawaban di atas, lihat berikut ini. AppointmentForm's datekolom dijelaskan dengan beberapa penjelasan. Dengan memiliki @Validanotasi yang memicu validasi pada AppointmentForm(dalam hal ini @NotNulldan @Future). Anotasi ini dapat berasal dari penyedia JSR-303 yang berbeda (misalnya, Hibernate, Spring..etc).

    @RequestMapping(value = "/appointments", method = RequestMethod.POST)
    public String add(@Valid AppointmentForm form, BindingResult result) {
        ....
    }

    static class AppointmentForm {

        @NotNull @Future
        private Date date;
    }
Charith De Silva
sumber
1
Saya memiliki kode serupa. Saya telah dihapus @Validpada ApplicationFormparameter tetapi, masih validasi dipecat pada date(set sebagai null) lapangan. Tolong jelaskan.
lupchiazoem
18

@Validitu sendiri tidak ada hubungannya dengan Spring. Ini adalah bagian dari spesifikasi Validasi Bean (ada beberapa di antaranya, yang terbaru adalah JSR 380 pada paruh kedua tahun 2017), tetapi @Validsudah sangat tua dan berasal dari JSR 303.

Seperti yang kita semua tahu, Spring sangat bagus dalam menyediakan integrasi dengan semua JSR yang berbeda dan perpustakaan java secara umum (pikirkan JPA, JTA, Caching, dll.) Dan tentu saja orang-orang itu menangani validasi juga. Salah satu komponen utama yang memfasilitasi ini adalah MethodValidationPostProcessor .

Mencoba menjawab pertanyaan Anda - @Validsangat berguna untuk apa yang disebut validasi berjenjang ketika Anda ingin memvalidasi grafik yang kompleks dan bukan hanya elemen tingkat atas dari suatu objek. Setiap kali Anda ingin lebih dalam, Anda harus menggunakan @Valid. Itulah yang diperintahkan JSR. Spring akan mematuhi itu dengan beberapa penyimpangan kecil (misalnya saya mencoba meletakkan @Validatedalih-alih @Validpada metode RestController dan validasi bekerja, tetapi hal yang sama tidak akan berlaku untuk kacang "layanan" biasa).

yuranos
sumber
Tapi, apa yang memvalidasi?
keponakan
Tolong jelaskan, @nephewtom. Apa yang ingin Anda klarifikasi?
yuranos
Saya membaca JSR 303: Validasi Bean, beanvalidation.org/1.0/spec tetapi saya masih tidak mendapatkan validasi apa yang akan dilakukan ScriptFile scriptFile.
keponakan
ScriptFile di dalamnya mungkin memiliki banyak kolom dan kolom tersebut juga memiliki anotasi. Di sinilah validasi dimulai. Berdasarkan pertanyaan awal, tidak jelas apa sebenarnya yang ada di dalam kelas ScriptFile.
yuranos
Ok terima kasih. Bisakah Anda memberi contoh apa yang bisa memvalidasi jika bidangnya di mana String, Integer, dan Bean?
keponakan
17

IIRC @Valid bukanlah anotasi Spring tetapi anotasi JSR-303 (yang merupakan standar Validasi Bean). Apa yang dilakukannya adalah pada dasarnya memeriksa apakah data yang Anda kirim ke metode itu valid atau tidak (itu akan memvalidasi scriptFile untuk Anda).

Mateusz Dymczyk
sumber
2
Apa artinya "itu akan memvalidasi scriptFile untuk Anda"? Periksa apakah tidak null, memiliki beberapa sintaks, atau beberapa konten? Dengan kata lain, apa yang divalidasi dan bagaimana? Haruskah pengguna menerapkan sesuatu? Di mana saya bisa mendapatkan info tentang itu? Terima kasih!
keponakan
Tolong jawab pertanyaan @ nephewtom, jawaban itu tidak cukup untuk memvalidasi dengan poin utama yang hilang yaitu "melawan apa"?
monami
2
public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        

Saya kira @NotNullanotasi ini valid oleh karena itu jika kondisinya tidak diperlukan.

mzlobecki.dll
sumber
2

Saya rasa saya tahu ke mana arah pertanyaan Anda. Dan karena pertanyaan ini adalah pertanyaan yang muncul di hasil utama pencarian google, saya dapat memberikan jawaban yang jelas tentang apa yang dilakukan anotasi @Valid.

Saya akan menyajikan 3 skenario tentang bagaimana saya menggunakan @Valid

Model:

public class Employee{
private String name;
@NotNull(message="cannot be null")
@Size(min=1, message="cannot be blank")
private String lastName;
 //Getters and Setters for both fields.
 //...
}

JSP:

...
<form:form action="processForm" modelAttribute="employee">
 <form:input type="text" path="name"/>
 <br>
 <form:input type="text" path="lastName"/>
<form:errors path="lastName"/>
<input type="submit" value="Submit"/>
</form:form>
...

Pengontrol untuk skenario 1:

     @RequestMapping("processForm")
        public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
        return "employee-confirmation-page";
    }

Dalam skenario ini, setelah mengirimkan formulir Anda dengan bidang nama belakang kosong, Anda akan mendapatkan halaman kesalahan karena Anda menerapkan aturan validasi tetapi Anda tidak menanganinya sama sekali.

Contoh kesalahan tersebut: Halaman pengecualian

Pengontrol untuk skenario 2:

 @RequestMapping("processForm")
    public String processFormData(@Valid @ModelAttribute("employee") Employee employee,
BindingResult bindingResult){
                return bindingResult.hasErrors() ? "employee-form" : "employee-confirmation-page";
            }

Dalam skenario ini, Anda meneruskan semua hasil dari validasi tersebut ke bindingResult, jadi terserah Anda untuk memutuskan apa yang harus dilakukan dengan hasil validasi formulir tersebut.

Pengontrol untuk skenario 3:

@RequestMapping("processForm")
    public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
                return "employee-confirmation-page";
            }
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> invalidFormProcessor(MethodArgumentNotValidException ex){
  //Your mapping of the errors...etc
}

Dalam skenario ini Anda masih tidak menangani kesalahan seperti di skenario pertama, tetapi Anda meneruskannya ke metode lain yang akan menangani pengecualian yang dipicu @Valid saat memproses model formulir. Periksa ini melihat apa yang harus dilakukan dengan pemetaan dan semua itu.

Singkatnya : @Valid sendiri dengan tidak melakukan apa-apa lagi yang memicu validasi validasi bidang beranotasi JSR 303 ( @NotNull, @Email, @Size, dll ... ), Anda masih perlu menentukan strategi tentang apa yang harus dilakukan dengan hasil validasi tersebut.

Semoga saya bisa menjelaskan sesuatu untuk orang-orang yang mungkin tersandung dengan ini.

Alan Balderas Sánchez
sumber
1

Hanya menambahkan jawaban di atas, Dalam aplikasi web @validdigunakan di mana kacang yang akan divalidasi juga dianotasi dengan penjelasan validasi misalnya @NotNull, @Email(anotasi hibernate) sehingga ketika mendapatkan input dari pengguna nilai-nilai dapat divalidasi dan hasil yang mengikat akan memiliki validasi hasil. bindingResult.hasErrors()akan memberi tahu jika ada validasi yang gagal.

puneet goyal
sumber
1

Aspek praktis lainnya dari @Valid yang tidak disebutkan di atas adalah bahwa (yaitu: menggunakan Postman untuk menguji titik akhir) @Valid akan memformat keluaran dari panggilan REST yang salah menjadi JSON yang diformat alih-alih gumpalan teks yang hampir tidak dapat dibaca. Ini sangat berguna jika Anda membuat API yang dapat dikonsumsi secara komersial untuk pengguna Anda.

Sean Gildea
sumber
1

Saya ingin menambahkan lebih banyak detail tentang bagaimana @Valid kerjanya, terutama di musim semi.

Semua yang ingin Anda ketahui tentang validasi di musim semi dijelaskan dengan jelas dan detail di https://reflectoring.io/bean-validation-with-spring-boot/ , tetapi saya akan menyalin jawabannya bagaimana caranya@Valid kerja memetikan tautan turun.

The @Validpenjelasan dapat ditambahkan ke variabel dalam metode controller sisanya untuk memvalidasi mereka. Ada 3 jenis variabel yang dapat divalidasi:

  • badan permintaan,
  • variabel di dalam jalur (mis. id in / foos / {id}) dan,
  • parameter kueri.

Jadi sekarang ... bagaimana musim semi "memvalidasi"? Anda dapat menentukan batasan pada bidang kelas dengan memberi anotasi pada mereka dengan anotasi tertentu. Kemudian, Anda meneruskan objek dari kelas itu ke Validator yang memeriksa apakah batasannya terpenuhi.

Misalnya, saya memiliki metode pengontrol seperti ini:

@RestController
class ValidateRequestBodyController {

  @PostMapping("/validateBody")
  ResponseEntity<String> validateBody(@Valid @RequestBody Input input) {
    return ResponseEntity.ok("valid");
  }

}

Jadi ini adalah permintaan POST yang mengambil isi respons, dan kami memetakan badan respons itu ke kelas Input.

Inilah kelasnya Input:

class Input {

  @Min(1)
  @Max(10)
  private int numberBetweenOneAndTen;

  @Pattern(regexp = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$")
  private String ipAddress;
  
  // ...
}

Anotasi @Valid akan memberi tahu spring untuk pergi dan memvalidasi data yang diteruskan ke pengontrol dengan memeriksa untuk melihat bahwa integer numberBetweenOneAndTenantara 1 dan 10 inklusif karena anotasi min dan max tersebut. Ini juga akan memeriksa untuk memastikan alamat ip yang diteruskan cocok dengan ekspresi reguler dalam anotasi.

catatan samping: ekspresi reguler tidak sempurna .. Anda bisa memasukkan 3 digit angka yang lebih besar dari 255 dan itu akan tetap cocok dengan ekspresi reguler.


Berikut adalah contoh memvalidasi variabel kueri dan variabel jalur:

@RestController
@Validated
class ValidateParametersController {

  @GetMapping("/validatePathVariable/{id}")
  ResponseEntity<String> validatePathVariable(
      @PathVariable("id") @Min(5) int id) {
    return ResponseEntity.ok("valid");
  }
  
  @GetMapping("/validateRequestParameter")
  ResponseEntity<String> validateRequestParameter(
      @RequestParam("param") @Min(5) int param) { 
    return ResponseEntity.ok("valid");
  }
}

Dalam kasus ini, karena variabel kueri dan variabel jalur hanyalah bilangan bulat, bukan hanya kelas yang kompleks, kami meletakkan anotasi batasan @Min(5)tepat di parameter alih-alih menggunakan @Valid.

Beberapa pria
sumber