Formularvalidierung mit AngularJS und Spring MVC

1. Übersicht

Die Validierung ist nie so einfach wie erwartet. Die Überprüfung der von einem Benutzer in eine Anwendung eingegebenen Werte ist natürlich sehr wichtig, um die Integrität unserer Daten zu gewährleisten.

Im Kontext einer Webanwendung erfolgt die Dateneingabe normalerweise mithilfe von HTML-Formularen und erfordert sowohl eine clientseitige als auch eine serverseitige Validierung.

In diesem Tutorial werden wir uns mit der Implementierung der clientseitigen Validierung von Formulareingaben mithilfe von AngularJS und der serverseitigen Validierung mithilfe des Spring MVC-Frameworks befassen .

Dieser Artikel konzentriert sich auf Spring MVC. In unserem Artikel Validierung in Spring Boot wird beschrieben, wie Sie Validierungen in Spring Boot durchführen.

2. Maven-Abhängigkeiten

Fügen wir zunächst die folgenden Abhängigkeiten hinzu:

 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 

Die neuesten Versionen von spring-webmvc, Hibernate-Validator und Jackson-Databind können von Maven Central heruntergeladen werden.

3. Validierung mit Spring MVC

Eine Anwendung sollte sich niemals ausschließlich auf die clientseitige Validierung verlassen, da dies leicht umgangen werden kann. Um zu verhindern, dass falsche oder böswillige Werte gespeichert werden oder die Anwendungslogik nicht ordnungsgemäß ausgeführt wird, ist es wichtig, die Eingabewerte auch auf der Serverseite zu überprüfen.

Spring MVC bietet Unterstützung für die serverseitige Validierung mithilfe von JSR 349 ​​Bean Validation- Spezifikationsanmerkungen. In diesem Beispiel verwenden wir die Referenzimplementierung der Spezifikation, die den Ruhezustand validiert .

3.1. Das Datenmodell

Erstellen wir eine Benutzerklasse , deren Eigenschaften mit entsprechenden Validierungsanmerkungen versehen sind:

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 }

Die oben verwendeten Anmerkungen gehören zur JSR 349- Spezifikation, mit Ausnahme von @Email und @NotBlank , die für die Hibernate-Validator- Bibliothek spezifisch sind .

3.2. Feder MVC Controller

Erstellen wir eine Controller-Klasse, die einen / user- Endpunkt definiert, mit dem ein neues Benutzerobjekt in einer Liste gespeichert wird .

Um die Validierung des Benutzerobjekts zu ermöglichen, das über Anforderungsparameter empfangen wurde, muss vor der Deklaration die Annotation @Valid stehen , und die Validierungsfehler werden in einer BindingResult- Instanz gespeichert .

Um festzustellen, ob das Objekt ungültige Werte enthält, können wir die hasErrors () -Methode von BindingResult verwenden .

Wenn hasErrors () true zurückgibt , können wir ein JSON-Array zurückgeben, das die Fehlermeldungen enthält, die den nicht bestandenen Validierungen zugeordnet sind. Andernfalls fügen wir das Objekt der Liste hinzu:

@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); } } }

Wie Sie sehen, bietet die serverseitige Validierung den Vorteil, dass zusätzliche Überprüfungen durchgeführt werden können, die auf der Clientseite nicht möglich sind.

In unserem Fall können wir überprüfen, ob bereits ein Benutzer mit derselben E-Mail-Adresse vorhanden ist, und in diesem Fall den Status 409 CONFLICT zurückgeben.

Wir müssen auch unsere Benutzerliste definieren und mit einigen Werten initialisieren:

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));

Fügen Sie außerdem eine Zuordnung zum Abrufen der Benutzerliste als JSON-Objekt hinzu:

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

Das letzte Element, das wir in unserem Spring MVC-Controller benötigen, ist eine Zuordnung, um die Hauptseite unserer Anwendung zurückzugeben:

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

Wir werden uns die Seite user.html im Abschnitt AngularJS genauer ansehen .

3.3. Spring MVC-Konfiguration

Fügen wir unserer Anwendung eine grundlegende MVC-Konfiguration hinzu:

@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. Initialisierung der Anwendung

Erstellen wir eine Klasse, die die WebApplicationInitializer- Schnittstelle implementiert , um unsere Anwendung auszuführen:

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. Testen der Spring Mvc-Validierung mit Curl

Bevor wir den AngularJS-Client-Abschnitt implementieren, können wir unsere API mithilfe von cURL mit dem folgenden Befehl testen:

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

Die Antwort ist ein Array mit den Standardfehlermeldungen:

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

Die clientseitige Validierung ist hilfreich, um eine bessere Benutzererfahrung zu erzielen, da sie dem Benutzer Informationen zum erfolgreichen Übermitteln gültiger Daten liefert und es ihm ermöglicht, weiterhin mit der Anwendung zu interagieren.

Die AngularJS-Bibliothek bietet hervorragende Unterstützung für das Hinzufügen von Validierungsanforderungen für Formularfelder, das Behandeln von Fehlermeldungen und das Gestalten gültiger und ungültiger Formulare.

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.

Wie immer finden Sie den vollständigen Quellcode für die Beispiele auf GitHub.

Um die Anwendung anzuzeigen, greifen Sie nach dem Ausführen auf die URL / userPage zu .