Validasi Formulir dengan AngularJS dan Spring MVC

1. Ikhtisar

Validasi tidak pernah sesederhana yang kami harapkan. Dan tentunya memvalidasi nilai yang dimasukkan oleh pengguna ke dalam aplikasi sangat penting untuk menjaga keutuhan data kami.

Dalam konteks aplikasi web, input data biasanya dilakukan menggunakan formulir HTML dan membutuhkan validasi sisi klien dan sisi server.

Dalam tutorial ini, kita akan melihat penerapan validasi sisi klien dari input formulir menggunakan AngularJS dan validasi sisi server menggunakan kerangka MVC Spring .

Artikel ini berfokus pada Spring MVC. Artikel kami Validasi di Spring Boot menjelaskan cara melakukan validasi di Spring Boot.

2. Ketergantungan Maven

Untuk memulai, mari tambahkan dependensi berikut:

 org.springframework spring-webmvc 4.3.7.RELEASE   org.hibernate hibernate-validator 5.4.0.Final   com.fasterxml.jackson.core jackson-databind 2.8.7 

Versi terbaru spring-webmvc, hibernate-validator, dan jackson-databind dapat diunduh dari Maven Central.

3. Validasi Menggunakan Spring MVC

Aplikasi tidak boleh hanya mengandalkan validasi sisi klien, karena ini dapat dengan mudah dielakkan. Untuk mencegah nilai yang salah atau berbahaya disimpan atau menyebabkan eksekusi logika aplikasi yang tidak tepat, penting juga untuk memvalidasi nilai input di sisi server.

Spring MVC menawarkan dukungan untuk validasi sisi server dengan menggunakan anotasi spesifikasi JSR 349 ​​Bean Validation . Untuk contoh ini, kita akan menggunakan implementasi referensi dari spesifikasi, yaitu hibernate-validator .

3.1. Model Data

Mari buat kelas Pengguna yang memiliki properti yang dianotasi dengan anotasi validasi yang sesuai:

public class User { @NotNull @Email private String email; @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; @Min(18) @Digits(integer = 2, fraction = 0) private int age; // standard constructor, getters, setters }

Anotasi yang digunakan di atas termasuk dalam spesifikasi JSR 349 , dengan pengecualian @Email dan @NotBlank , yang khusus untuk pustaka hibernate-validator .

3.2. Pengontrol MVC Musim Semi

Mari buat kelas pengontrol yang mendefinisikan titik akhir / pengguna , yang akan digunakan untuk menyimpan objek Pengguna baru ke Daftar .

Untuk mengaktifkan validasi objek Pengguna yang diterima melalui parameter permintaan, deklarasi harus diawali dengan anotasi @Valid , dan kesalahan validasi akan disimpan dalam instance BindingResult .

Untuk menentukan apakah objek berisi nilai yang tidak valid, kita bisa menggunakan metode hasErrors () dari BindingResult .

Jika hasErrors () mengembalikan nilai true , kita bisa mengembalikan array JSON yang berisi pesan kesalahan yang terkait dengan validasi yang tidak lolos. Jika tidak, kami akan menambahkan objek ke daftar:

@PostMapping(value = "/user") @ResponseBody public ResponseEntity saveUser(@Valid User user, BindingResult result, Model model) { if (result.hasErrors()) { List errors = result.getAllErrors().stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.toList()); return new ResponseEntity(errors, HttpStatus.OK); } else { if (users.stream().anyMatch(it -> user.getEmail().equals(it.getEmail()))) { return new ResponseEntity( Collections.singletonList("Email already exists!"), HttpStatus.CONFLICT); } else { users.add(user); return new ResponseEntity(HttpStatus.CREATED); } } }

Seperti yang Anda lihat, validasi sisi server menambah keuntungan karena memiliki kemampuan untuk melakukan pemeriksaan tambahan yang tidak mungkin dilakukan di sisi klien.

Dalam kasus kami, kami dapat memverifikasi apakah pengguna dengan email yang sama sudah ada - dan mengembalikan status 409 KONFLIK jika demikian.

Kami juga perlu menentukan daftar pengguna kami dan menginisialisasinya dengan beberapa nilai:

private List users = Arrays.asList( new User("[email protected]", "pass", "Ana", 20), new User("[email protected]", "pass", "Bob", 30), new User("[email protected]", "pass", "John", 40), new User("[email protected]", "pass", "Mary", 30));

Mari tambahkan juga pemetaan untuk mengambil daftar pengguna sebagai objek JSON:

@GetMapping(value = "/users") @ResponseBody public List getUsers() { return users; }

Item terakhir yang kita butuhkan di pengontrol MVC Spring kita adalah pemetaan untuk mengembalikan halaman utama aplikasi kita:

@GetMapping("/userPage") public String getUserProfilePage() { return "user"; }

Kami akan melihat halaman user.html lebih detail di bagian AngularJS.

3.3. Konfigurasi MVC Musim Semi

Mari tambahkan konfigurasi MVC dasar ke aplikasi kita:

@Configuration @EnableWebMvc @ComponentScan(basePackages = "com.baeldung.springmvcforms") class ApplicationConfiguration implements WebMvcConfigurer { @Override public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Bean public InternalResourceViewResolver htmlViewResolver() { InternalResourceViewResolver bean = new InternalResourceViewResolver(); bean.setPrefix("/WEB-INF/html/"); bean.setSuffix(".html"); return bean; } }

3.4. Memulai Aplikasi

Mari buat kelas yang mengimplementasikan antarmuka WebApplicationInitializer untuk menjalankan aplikasi kita:

public class WebInitializer implements WebApplicationInitializer { public void onStartup(ServletContext container) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(ApplicationConfiguration.class); ctx.setServletContext(container); container.addListener(new ContextLoaderListener(ctx)); ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx)); servlet.setLoadOnStartup(1); servlet.addMapping("/"); } }

3.5. Menguji Validasi Spring Mvc Menggunakan Curl

Sebelum kami menerapkan bagian klien AngularJS, kami dapat menguji API kami menggunakan cURL dengan perintah:

curl -i -X POST -H "Accept:application/json" "localhost:8080/spring-mvc-forms/user?email=aaa&password=12&age=12"

Responsnya adalah larik yang berisi pesan kesalahan default:

[ "not a well-formed email address", "size must be between 4 and 15", "may not be empty", "must be greater than or equal to 18" ]

4. Validasi AngularJS

Validasi sisi klien berguna dalam menciptakan pengalaman pengguna yang lebih baik, karena memberikan pengguna informasi tentang cara berhasil mengirimkan data yang valid dan memungkinkan mereka untuk dapat terus berinteraksi dengan aplikasi.

Pustaka AngularJS memiliki dukungan besar untuk menambahkan persyaratan validasi pada bidang formulir, menangani pesan kesalahan, dan gaya formulir yang valid dan tidak valid.

First, let's create an AngularJS module that injects the ngMessages module, which is used for validation messages:

var app = angular.module('app', ['ngMessages']);

Next, let's create an AngularJS service and controller that will consume the API built in the previous section.

4.1. The AngularJS Service

Our service will have two methods that call the MVC controller methods — one to save a user, and one to retrieve the list of users:

app.service('UserService',['$http', function ($http) { this.saveUser = function saveUser(user){ return $http({ method: 'POST', url: 'user', params: {email:user.email, password:user.password, name:user.name, age:user.age}, headers: 'Accept:application/json' }); } this.getUsers = function getUsers(){ return $http({ method: 'GET', url: 'users', headers:'Accept:application/json' }).then( function(response){ return response.data; } ); } }]);

4.2. The AngularJS Controller

The UserCtrl controller injects the UserService, calls the service methods and handles the response and error messages:

app.controller('UserCtrl', ['$scope','UserService', function ($scope,UserService) { $scope.submitted = false; $scope.getUsers = function() { UserService.getUsers().then(function(data) { $scope.users = data; }); } $scope.saveUser = function() { $scope.submitted = true; if ($scope.userForm.$valid) { UserService.saveUser($scope.user) .then (function success(response) { $scope.message = 'User added!'; $scope.errorMessage = ''; $scope.getUsers(); $scope.user = null; $scope.submitted = false; }, function error(response) { if (response.status == 409) { $scope.errorMessage = response.data.message; } else { $scope.errorMessage = 'Error adding user!'; } $scope.message = ''; }); } } $scope.getUsers(); }]);

We can see in the example above that the service method is called only if the $valid property of userForm is true. Still, in this case, there is the additional check for duplicate emails, which can only be done on the server and is handled separately in the error() function.

Also, notice that there is a submitted variable defined which will tell us if the form has been submitted or not.

Initially, this variable will be false, and on invocation of the saveUser() method, it becomes true. If we don't want validation messages to show before the user submits the form, we can use the submitted variable to prevent this.

4.3. Form Using AngularJS Validation

In order to make use of the AngularJS library and our AngularJS module, we will need to add the scripts to our user.html page:

Then we can use our module and controller by setting the ng-app and ng-controller properties:

Let's create our HTML form:

 ... 

Note that we have to set the novalidate attribute on the form in order to prevent default HTML5 validation and replace it with our own.

The ng-class attribute adds the form-error CSS class dynamically to the form if the submitted variable has a value of true.

The ng-submit attribute defines the AngularJS controller function that will be called when the form in submitted. Using ng-submit instead of ng-click has the advantage that it also responds to submitting the form using the ENTER key.

Now let's add the four input fields for the User attributes:

Email:  Password:  Name:  Age: 

Each input field has a binding to a property of the user variable through the ng-model attribute.

For setting validation rules, we use the HTML5 required attribute and several AngularJS-specific attributes: ng-minglength, ng-maxlength, ng-min, and ng-trim.

For the email field, we also use the type attribute with a value of email for client-side email validation.

In order to add error messages corresponding to each field, AngularJS offers the ng-messages directive, which loops through an input's $errors object and displays messages based on each validation rule.

Let's add the directive for the email field right after the input definition:

Invalid email!

Email is required!

Similar error messages can be added for the other input fields.

We can control when the directive is displayed for the email field using the ng-show property with a boolean expression. In our example, we display the directive when the field has an invalid value, meaning the $invalid property is true, and the submitted variable is also true.

Only one error message will be displayed at a time for a field.

We can also add a check mark sign (represented by HEX code character ✓) after the input field in case the field is valid, depending on the $valid property:

AngularJS validation also offers support for styling using CSS classes such as ng-valid and ng-invalid or more specific ones like ng-invalid-required and ng-invalid-minlength.

Let's add the CSS property border-color:red for invalid inputs inside the form's form-error class:

.form-error input.ng-invalid { border-color:red; }

We can also show the error messages in red using a CSS class:

.error-messages { color:red; }

After putting everything together, let's see an example of how our client-side form validation will look when filled out with a mix of valid and invalid values:

5. Conclusion

In this tutorial, we've shown how we can combine client-side and server-side validation using AngularJS and Spring MVC.

Seperti biasa, kode sumber lengkap untuk contoh dapat ditemukan di GitHub.

Untuk melihat aplikasi, akses / userPage URL setelah menjalankannya.