Benutzereingabe-Validierung in Webanwendungen mit Spring MVC Form Validator

Wenn wir Benutzereingaben in einer Webanwendung akzeptieren, wird es notwendig, diese zu validieren. Wir können die Benutzereingabe auf der Clientseite mit JavaScript validieren, aber es ist auch notwendig, sie auf der Serverseite zu validieren, um sicherzustellen, dass wir gültige Daten verarbeiten, falls der Benutzer JavaScript deaktiviert hat.

Validierung mit Spring MVC Form Validator

Das Spring MVC Framework unterstützt standardmäßig die JSR-303-Spezifikationen, und alles, was wir tun müssen, ist, JSR-303 und seine Implementierungsabhängigkeiten in die Spring MVC-Anwendung einzufügen. Spring bietet auch die Annotation @Validator und die Klasse BindingResult an, durch die wir die von der Validator-Implementierung im Controller-Anfrage-Handler erzeugten Fehler erhalten können. Wir können unsere eigenen benutzerdefinierten Validator-Implementierungen auf zwei Arten erstellen – die erste besteht darin, eine Annotation zu erstellen, die den JSR-303-Spezifikationen entspricht, und deren Validator-Klasse zu implementieren. Der zweite Ansatz besteht darin, das Interface org.springframework.validation.Validator zu implementieren und es im Controller mithilfe der Annotation @InitBinder als Validator festzulegen. Lassen Sie uns ein einfaches Spring MVC-Projekt im Spring Tool Suite erstellen, in dem wir die JSR-303-Spezifikationen mit dem Implementierungsartefakt hibernate-validator verwenden. Wir werden auf Annotations basierende Formularvalidierung verwenden und unseren eigenen benutzerdefinierten Validator basierend auf den JSR-303-Spezifikationsstandards erstellen. Wir werden auch unsere eigene benutzerdefinierte Validator-Klasse erstellen, indem wir das Validator-Interface implementieren und es in einer der Controller-Handler-Methoden verwenden.

Spring MVC Form Validator

Unsere endgültige pom.xml-Datei sieht wie folgt aus. Neben den Standard-Spring-MVC-Artefakten haben wir validation-api und hibernate-validator-Abhängigkeiten im Projekt.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>spring</artifactId>
	<name>SpringFormValidation</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.7</java-version>
		<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
		<org.aspectj-version>1.7.4</org.aspectj-version>
		<org.slf4j-version>1.7.5</org.slf4j-version>
	</properties>
	<dependencies>
	<!-- Form Validation using Annotations -->  
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.1.0.Final</version>
		</dependency>
		
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>

		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>

		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.9</version>
				<configuration>
					<additionalProjectnatures>
						<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
					</additionalProjectnatures>
					<additionalBuildcommands>
						<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
					</additionalBuildcommands>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
					<compilerArgument>-Xlint:all</compilerArgument>
					<showWarnings>true</showWarnings>
					<showDeprecation>true</showDeprecation>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<version>1.2.1</version>
				<configuration>
					<mainClass>org.test.int1.Main</mainClass>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Bereitstellungsbeschreibung

Beim Erstellen eines Spring MVC-Projekts von STS werden zwei Kontextkonfigurationsdateien erstellt. Wir haben dies etwas bereinigt und haben nur eine Spring-Bean-Konfigurationsdatei. Unsere finale web.xml-Datei sieht wie folgt aus:

 

        <?xml version="1.0" encoding="UTF-8"?>
        <web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
        xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
        
        <!-- Verarbeitet Anwendungsanfragen -->
        <servlet>
            <servlet-name>appServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/spring/spring.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
            
        <servlet-mapping>
            <servlet-name>appServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>

        </web-app>

Spring Bean-Konfigurationsdatei

Normalerweise schauen wir uns die Spring-Verkabelungen zuletzt an, aber dieses Mal haben wir nicht viele Konfigurationen in der Spring-Bean-Konfigurationsdatei. Unsere finale spring.xml-Datei sieht wie folgt aus.

        <?xml version="1.0" encoding="UTF-8"?>
        <beans:beans xmlns="https://www.springframework.org/schema/mvc"
        xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
        xmlns:beans="https://www.springframework.org/schema/beans"
        xmlns:context="https://www.springframework.org/schema/context"
        xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

        <!-- DispatcherServlet-Kontext: definiert die Anfrageverarbeitungsinfrastruktur dieses Servlets -->
        
        <!-- Ermöglicht das Spring MVC @Controller-Programmiermodell -->
        <annotation-driven />

        <!-- Verarbeitet HTTP GET-Anfragen für /resources/**, indem statische Ressourcen im Verzeichnis ${webappRoot}/resources effizient bereitgestellt werden -->
        <resources mapping="/resources/**" location="/resources/" />

        <!-- Löst von @Controllers ausgewählte Ansichten zur Darstellung als .jsp-Ressourcen im Verzeichnis /WEB-INF/views auf -->
        <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <beans:property name="prefix" value="/WEB-INF/views/" />
            <beans:property name="suffix" value=".jsp" />
        </beans:bean>
        
        <beans:bean id="employeeValidator" class="com.journaldev.spring.form.validator.EmployeeFormValidator" />
        
        <beans:bean id="messageSource"
            class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            <beans:property name="basename" value="classpath:message" />
            <beans:property name="defaultEncoding" value="UTF-8" />
        </beans:bean>
        
        <context:component-scan base-package="com.journaldev.spring" />
        
        </beans:beans>


Der einzige wichtige Punkt ist der employeeValidator-Bean, den wir in einen der Controller einfügen werden, und der messageSource-Bean, um die lokalisierten Daten aus den Ressourcenbündeln zu lesen. Der Rest dient zur Unterstützung von Annotationen, View-Resolvern und zum Bereitstellen von Paketen zum Scannen von Controller-Klassen und anderen Komponenten.

Modelklassen

Kundenmodellklasse

        package com.journaldev.spring.form.model;

        import java.util.Date;
        import javax.validation.constraints.Max;
        import javax.validation.constraints.Min;
        import javax.validation.constraints.NotNull;
        import javax.validation.constraints.Past;
        import javax.validation.constraints.Size;
        import org.hibernate.validator.constraints.Email;
        import org.hibernate.validator.constraints.NotEmpty;
        import org.springframework.format.annotation.DateTimeFormat;
        import com.journaldev.spring.form.validator.Phone;

        public class Customer {
            @Size(min=2, max=30) 
            private String name;
             
            @NotEmpty @Email
            private String email;
             
            @NotNull @Min(18) @Max(100)
            private Integer age;
             
            @NotNull
            private Gender gender;
             
            @DateTimeFormat(pattern="MM/dd/yyyy")
            @NotNull @Past
            private Date birthday;
            
            @Phone
            private String phone;
            
            public enum Gender {
                MALE, FEMALE
            }

            // Getter und Setter
        }

Mitarbeitermodellklasse

        package com.journaldev.spring.form.model;

        public class Employee {
            private int id;
            private String name;
            private String role;

            // Getter und Setter
        }

Eigene Validator-Implementierungen

Telefon-Validator


        package com.journaldev.spring.form.validator;

        import java.lang.annotation.Documented;
        import java.lang.annotation.Retention;
        import java.lang.annotation.Target;
        import java.lang.annotation.ElementType;
        import java.lang.annotation.RetentionPolicy;
        import javax.validation.Constraint;
        import javax.validation.Payload;

        @Documented
        @Constraint(validatedBy = PhoneValidator.class)
        @Target({ ElementType.METHOD, ElementType.FIELD })
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Phone {
            String message() default "{Phone}";
            Class<?>[] groups() default {};
            Class<? extends Payload>[] payload() default {};
        }


        package com.journaldev.spring.form.validator;

        import javax.validation.ConstraintValidator;
        import javax.validation.ConstraintValidatorContext;

        public class PhoneValidator implements ConstraintValidator<Phone, String> {
            @Override
            public void initialize(Phone paramA) {
            }

            @Override
            public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
                if (phoneNo == null) {
                    return false;
                }
                // validiere Telefonnummern des Formats "1234567890"
                if (phoneNo.matches("\\d{10}")) return true;
                // validiere Telefonnummern mit -, . oder Leerzeichen
                else if (phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true;
                // validiere Telefonnummern mit Durchwahllänge von 3 bis 5
                else if (phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true;
                // validiere Telefonnummern, bei denen die Vorwahl in Klammern steht ()
                else if (phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")) return true;
                // gebe false zurück, wenn nichts mit der Eingabe übereinstimmt
                else return false;
            }
        }


        package com.journaldev.spring.form.validator;

        import org.springframework.validation.Errors;
        import org.springframework.validation.ValidationUtils;
        import org.springframework.validation.Validator;
        import com.journaldev.spring.form.model.Employee;

        public class EmployeeFormValidator implements Validator {
            @Override
            public boolean supports(Class<?> paramClass) {
                return Employee.class.equals(paramClass);
            }

            @Override
            public void validate(Object obj, Errors errors) {
                ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "id.required");
                Employee emp = (Employee) obj;
                if (emp.getId() <= 0) {
                    errors.rejectValue("id", "negativeValue", new Object[] { "'id'" }, "id darf nicht negativ sein");
                }
                ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "name.required");
                ValidationUtils.rejectIfEmptyOrWhitespace(errors, "role", "role.required");
            }
        }

Controller-Klassen

CustomerController-Klasse

        package com.journaldev.spring.form.controllers;

        import java.util.HashMap;
        import java.util.Map;
        import javax.validation.Valid;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.stereotype.Controller;
        import org.springframework.ui.Model;
        import org.springframework.validation.BindingResult;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RequestMethod;
        import com.journaldev.spring.form.model.Customer;

        @Controller
        public class CustomerController {
            private static final Logger logger = LoggerFactory.getLogger(CustomerController.class);
            private Map<String, Customer> customers = null;

            public CustomerController() {
                customers = new HashMap<String, Customer>();
            }

            @RequestMapping(value = "/cust/save", method = RequestMethod.GET)
            public String saveCustomerPage(Model model) {
                logger.info("Rückgabe der custSave.jsp-Seite");
                model.addAttribute("customer", new Customer());
                return "custSave";
            }

            @RequestMapping(value = "/cust/save.do", method = RequestMethod.POST)
            public String saveCustomerAction(@Valid Customer customer, BindingResult bindingResult, Model model) {
                if (bindingResult.hasErrors()) {
                    logger.info("Rückgabe der custSave.jsp-Seite");
                    return "custSave";
                }
                logger.info("Rückgabe der custSaveSuccess.jsp-Seite");
                model.addAttribute("customer", customer);
                customers.put(customer.getEmail(), customer);
                return "custSaveSuccess";
            }
        }

Kundenspeicher-Erfolgsseite (custSaveSuccess.jsp)

        <%@ page session="false" %>
        <html>
        <head>
            <title>Kunde erfolgreich gespeichert</title>
        </head>
        <body>
        <h3>
            Kunde erfolgreich gespeichert.
        </h3>

        <!-- Kundendetails anzeigen -->

        </body>
        </html>

Mitarbeiterspeicherseite (empSave.jsp)

        <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
        <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
        <%@ taglib uri="https://www.springframework.org/tags/form" prefix="springForm"%>
        <html>
        <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Mitarbeiterspeicherseite</title>
        <style>
        .error {
            color: #ff0000;
            font-style: italic;
            font-weight: bold;
        }
        </style>
        </head>
        <body>

        <springForm:form method="POST" commandName="employee" action="save.do">
            <table>
                <!-- Formularfelder -->
            </table>
        </springForm:form>

        </body>
        </html>

Mitarbeiterspeicher-Erfolgsseite (empSaveSuccess.jsp)

        <%@ page session="false" %>
        <html>
        <head>
            <title>Mitarbeiter erfolgreich gespeichert</title>
        </head>
        <body>
        <h3>
            Mitarbeiter erfolgreich gespeichert.
        </h3>

        <!-- Mitarbeiterdetails anzeigen -->

        </body>
        </html>

Testen der Spring MVC Formularvalidierungsanwendung

Unsere Anwendung ist bereit zum Bereitstellen und Testen. Deployen Sie es in Ihrem bevorzugten Servlet-Container. Wir verwenden Apache Tomcat 7.

Fazit

Das ist eine Anleitung zur Spring MVC Formularvalidierung mit verschiedenen Methoden und unter Verwendung von Ressourcenbündeln für lokalisierte Fehlermeldungen – Benutzereingabe-Validierung in Webanwendungen.

Kostenlosen Account erstellen

Registrieren Sie sich jetzt und erhalten Sie Zugang zu unseren Cloud Produkten.

Das könnte Sie auch interessieren: