Pengesahan Bentuk dengan AngularJS dan Spring MVC

1. Gambaran keseluruhan

Pengesahan tidak semudah yang kita jangkakan. Dan tentu saja mengesahkan nilai yang dimasukkan oleh pengguna ke dalam aplikasi sangat penting untuk menjaga integriti data kami.

Dalam konteks aplikasi web, input data biasanya dilakukan menggunakan bentuk HTML dan memerlukan pengesahan dari sisi klien dan pelayan.

Dalam tutorial ini, kita akan melihat pelaksanaan pengesahan input borang klien menggunakan AngularJS dan pengesahan sisi pelayan menggunakan kerangka Spring MVC .

Artikel ini memberi tumpuan kepada Spring MVC. Artikel kami Validation in Spring Boot menerangkan bagaimana melakukan validasi di Spring Boot.

2. Pergantungan Maven

Untuk memulakan, mari tambahkan kebergantungan 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 terkini spring-webmvc, hibernate-validator dan jackson-databaseind ​​boleh dimuat turun dari Maven Central.

3. Pengesahan Menggunakan Spring MVC

Aplikasi tidak boleh bergantung sepenuhnya pada pengesahan sisi pelanggan, kerana ini dapat dengan mudah dielakkan. Untuk mengelakkan nilai yang salah atau berniat jahat disimpan atau menyebabkan pelaksanaan logik aplikasi yang tidak betul, penting juga untuk mengesahkan nilai input di sisi pelayan.

Spring MVC menawarkan sokongan untuk pengesahan sisi pelayan dengan menggunakan anotasi spesifikasi JSR 349 ​​Bean Validation . Untuk contoh ini, kami akan menggunakan rujukan pelaksanaan spesifikasi, yang merupakan hibernate-validator .

3.1. Model Data

Mari buat kelas Pengguna yang mempunyai sifat yang diberi anotasi pengesahan 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 , kecuali @Email dan @NotBlank , yang khusus untuk pustaka validator hibernate .

3.2. Pengawal Spring MVC

Mari buat kelas pengawal yang menentukan titik akhir pengguna / , yang akan digunakan untuk menyimpan objek Pengguna baru ke Senarai .

Untuk memungkinkan pengesahan objek Pengguna yang diterima melalui parameter permintaan, deklarasi harus didahului oleh anotasi @Valid , dan kesalahan pengesahan akan dilakukan dalam contoh BindingResult .

Untuk menentukan sama ada objek yang mengandungi nilai-nilai tidak sah, kami boleh menggunakan hasErrors () kaedah BindingResult .

Sekiranya hasErrors () kembali benar , kita dapat mengembalikan array JSON yang mengandungi mesej ralat yang berkaitan dengan pengesahan yang tidak lulus. Jika tidak, kami akan menambahkan objek ke senarai:

@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, pengesahan sisi pelayan menambahkan kelebihan memiliki kemampuan untuk melakukan pemeriksaan tambahan yang tidak mungkin dilakukan di sisi klien.

Dalam kes kami, kami dapat mengesahkan sama ada pengguna dengan e-mel yang sama sudah ada - dan mengembalikan status 409 KONFLIK jika itu berlaku.

Kami juga perlu menentukan senarai pengguna kami dan menginisialisasi 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 juga tambahkan pemetaan untuk mendapatkan senarai pengguna sebagai objek JSON:

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

Item terakhir yang kami perlukan dalam pengawal Spring MVC kami adalah pemetaan untuk mengembalikan halaman utama aplikasi kami:

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

Kami akan melihat halaman user.html dengan lebih terperinci di bahagian AngularJS.

3.3. Konfigurasi Spring MVC

Mari tambahkan konfigurasi MVC asas pada aplikasi kami:

@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. Memulakan Permohonan

Mari buat kelas yang menerapkan antara muka WebApplicationInitializer untuk menjalankan aplikasi kami:

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 Pengesahan Spring Mvc Menggunakan Curl

Sebelum kita melaksanakan bahagian klien AngularJS, kita dapat menguji API kita menggunakan cURL dengan perintah:

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

Respons adalah susunan yang mengandungi mesej ralat lalai:

[ "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. Pengesahan AngularJS

Pengesahan dari sisi pelanggan berguna dalam mewujudkan pengalaman pengguna yang lebih baik, kerana ia memberi pengguna maklumat tentang cara mengemukakan data yang sah dan membolehkan mereka dapat terus berinteraksi dengan aplikasi.

Perpustakaan AngularJS mempunyai sokongan hebat untuk menambahkan syarat pengesahan pada bidang borang, menangani mesej ralat, dan menggayakan borang yang sah dan tidak sah.

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, kod sumber penuh untuk contoh boleh didapati di GitHub.

Untuk melihat aplikasi, akses URL / userPage setelah menjalankannya.