[JAVA] Filtern Sie das Ergebnis von BindingResult [Spring]

Zielgruppe

-Ich implementiere Validation in Spring Framework, aber ich möchte das Ergebnis von BindingResult filtern! ・ Ich möchte ein gemeinsames Formular für neue und aktualisierte verwenden!

Bestätigung des Objekts

View

コメント 2020-05-16 103732.png

Durch einfaches Verwenden des Spring-Tags wird userForm in modelAttribute definiert und das Eingabe-Tag und das Label-Tag werden geschrieben. Die Update-Seite hat genau die gleiche Struktur.

Form

UserForm.java



@Data
@ConfirmMail(field = "mail", groups = MailGroup3.class)
@ConfirmPassword(field = "password", groups = PasswordGroup4.class)
@CheckBirthday(field = "birthday", groups = ValidGroup2.class)
public class UserForm {

	private String id;

	@NotBlank(groups = ValidGroup1.class)
	@Size(min = 6, max = 20, groups = ValidGroup2.class)
	@Pattern(regexp = "^[a-zA-Z0-9]+$", groups = ValidGroup3.class)
	private String account;

	@NotBlank(groups = PasswordGroup1.class)
	@Size(min = 6, max = 12, groups = PasswordGroup2.class)
	@Pattern(regexp = "^[a-zA-Z0-9!-/:-@¥[-`{-~]]+$", groups = PasswordGroup3.class)
	private String password;

	@NotBlank(groups = PasswordGroup1.class)
	@Size(min = 6, max = 12, groups = PasswordGroup2.class)
	@Pattern(regexp = "^[a-zA-Z0-9!-/:-@¥[-`{-~]]+$", groups = PasswordGroup3.class)
	private String confirmPassword;

	@NotBlank(groups = ValidGroup1.class)
	@Size(min = 1, max = 10, groups = ValidGroup2.class)
	private String name;

	@NotBlank(groups = ValidGroup1.class)
	private String birthday;

	@NotBlank(groups = MailGroup1.class)
	@Email(groups = MailGroup2.class)
	private String mail;

	@NotBlank(groups = MailGroup1.class)
	@Email(groups = MailGroup2.class)
	private String confirmMail;

	private String roleName;

}

Für jeden Artikel werden Leerzeichen, reguläre Ausdrücke, Bestätigungskennwörter, Bestätigungs-E-Mail-Adressen und andere Überprüfungen definiert. Die zu filternden Felder sind getrennt, und es ist besser, GroupOrder anzugeben. .. ..

Controller

SignupController


	@PostMapping("/signup")
	String createUser(@ModelAttribute("userForm") @Validated({ GroupOrder.class, PasswordGroupOrder.class, MailGroupOrder.class })  UserForm userForm,
			BindingResult result, RedirectAttributes redirectAttributes) {

		if(result.hasErrors()) {
			return "users/signup/new";
		}
		mailAuthUserService.authUserbyMail(userForm);
		redirectAttributes.addFlashAttribute("resultMessage", "Eine E-Mail wurde gesendet. Bitte überprüfen Sie Ihre Mailbox.");
		return "redirect:/login";
}

Wenn man die Umleitung dieser zur Update-Seite als Problem betrachtet (Angenommen, Sie bringen die Informationen so, wie sie aus der Datenbank stammen.)

-Wenn das Kennwort aktualisiert wird, wird das Kennwort irreversibel gehasht, sodass die von der Datenbank übermittelten Informationen nicht so eingegeben werden können, wie sie in dem Formular auf der Aktualisierungsseite vorliegen (das zum Zeitpunkt der Aktualisierung gehashte Kennwort wird gehasht). Weil es gemacht wird). Das Passwort muss leer sein. -Wenn Sie nicht aktualisieren möchten, sind die Elemente des Bestätigungskennworts und der Bestätigungs-E-Mail-Adresse leer, sodass die Validierung angewendet wird. Es ist mühsam, Gegenstände einzeln zu platzieren.

Die Validierung steht also im Weg.

コメント 2020-05-16 111346.png

Gegenmaßnahmen

Ist es möglich, einige Fehlerelemente von BindinResult zu löschen?

Laut Google-Lehrer scheint die Methode zum Löschen des Fehlerelements nicht in "BindinResult" definiert zu sein, daher kann dies nicht durchgeführt werden. Wenn Sie das Objekt neu definieren, anstatt es zu löschen, können Sie es als Ergebnis löschen!

Filtermethode

UserController.java


	private BindingResult filteringBindingResult(BindingResult result, UserForm userForm) {

		UserDto userDto = findById(userForm.getId()); //・ ・ ・ 1
		BindingResult tmpResult = new BeanPropertyBindingResult(userForm, "userForm");//・ ・ ・ 2

		if(StringUtils.isEmpty(userForm.getPassword()) && userDto.getMail().equals(userForm.getMail())) { //· · · 3

			for(FieldError fieldError : result.getFieldErrors()) { //・ ・ ・ 4
				if(fieldError.getField().equals("confirmMail") ||
						fieldError.getField().equals("confirmPassword") ||
						fieldError.getField().equals("password")) {
					continue;
				}
				tmpResult.addError(fieldError);
			}

			return tmpResult;
		}

		if(StringUtils.isEmpty(userForm.getPassword())) {

			for(FieldError fieldError : result.getFieldErrors()) {
				if(fieldError.getField().equals("confirmPassword") ||
						fieldError.getField().equals("password")) {
					continue;
				}
				tmpResult.addError(fieldError);
			}

			return tmpResult;
		}

		if(userDto.getMail().equals(userForm.getMail())) {

			for(FieldError fieldError : result.getFieldErrors()) {
				if(fieldError.getField().equals("confirmMail")) {
					continue;
				}
				tmpResult.addError(fieldError);
			}

			return tmpResult;
		}

		return result;
	}

Argumente: BindingResult-Ergebnis (speichert das Fehlerergebnis), UserForm userForm (Element auf der Ansichtsseite eingegeben)

Rückgabewert ・ ・ ・ BindingResult

1 ... Definiert, um Benutzerinformationen aus der Datenbank abzurufen und zu überprüfen, ob sich die E-Mail-Adresse geändert hat. 2 ... Da BindingResult eine Schnittstelle ist, hat es keine Implementierung. BeanPropertyBindingResult ist die Standardimplementierung von BindingResult. Daher ist es erforderlich, diesem Objekt ein gefiltertes Fehlerelement zuzuweisen. Definieren Sie es daher. Springframework 3 ... In dieser Implementierung möchten wir die Validierung verwenden, wenn sie aktualisiert werden muss. Überprüfen Sie daher, ob das Kennwort leer ist und sich die E-Mail-Adresse nicht geändert hat, und filtern Sie nach "Valaidation", wenn "true". Wenn mit multipliziert wird und falsch ist, ist die Implementierung so, dass mit normaler Valaidation multipliziert wird ``. 4 ... Mit dem Controller werden die empfangenen BindingResults einzeln entfernt, diejenigen, die den zu filternden Elementen entsprechen, werden mit continue übersprungen und die anderen werden tmpResult zugewiesen.

Update 2020/6/10

UserController.java


	private BindingResult filteringBindingResult(BindingResult result, UserForm userForm) throws Exception {

		final BindingResult newResult = new BeanPropertyBindingResult(userForm, "userForm");
		Set<FieldError> allErrors = new HashSet<>();
		result.getFieldErrors().forEach(x -> allErrors.add(x));

		if (StringUtils.isEmpty(userForm.getPassword()) && StringUtils.isEmpty(userForm.getConfirmPassword())) {
			allErrors.removeIf(x -> x.getField().equals("password") || x.getField().equals("confirmPassword"));
		}

		UserDto userDto = userService.findById(userForm.getId());
		if (userDto.getMail().equals(userForm.getMail()) && StringUtils.isEmpty(userForm.getConfirmMail())) {
			allErrors.removeIf(x -> x.getField().equals("mail") || x.getField().equals("confirmMail"));
		}

		allErrors.forEach(x -> newResult.addError(x));

		if (result.getFieldErrorCount() == newResult.getFieldErrorCount()) {
			return result;
		} else {
			return newResult;
		}
	}

Das BindingResult-Ergebnis wird nur entfernt, wenn das Bestätigungskennwort und das Kennwort leer sind "und wenn sich die E-Mail-Adresse nicht geändert hat und die Bestätigungs-E-Mail-Adresse leer ist". ..

Controller

UserController.java


	@PostMapping("/{id}/edit")
	String edit(Model model,
			@Validated({ GroupOrder.class, PasswordGroupOrder.class, MailGroupOrder.class })  UserForm userForm,
			BindingResult result) {

		BindingResult filteringBindingResult = filteringBindingResult(result, userForm); //・ ・ ・ 1

		if(filteringBindingResult.hasErrors()) {
			model.addAttribute("org.springframework.validation.BindingResult.userForm", filteringBindingResult); //・ ・ ・ 2
			return "users/edit";
		}

		userService.update(userForm);
		return "redirect:/user/mypage";

	}

1 ... Der Rückgabewert der zuvor definierten Methode wird in filteringBindingResult gespeichert. 2 ... Ich hatte hier eine sehr schwierige Zeit, aber zuerst fragte ich mich, ob ich es reibungslos implementieren könnte, indem ich die Referenz des BindingResult-Ergebnisses umschreibe, aber anscheinend wurde es, als dieser Controller aufgerufen wurde, ein Modell. Das Ergebnis von BindingResult vor dem Anwenden des Filters wurde gespeichert. Sie müssen dieses Objekt also überschreiben. "org.springframework.validation.BindingResult.userForm hat das Modell selbst gedruckt und debuggt ...

Impressionen

Ich weiß ehrlich gesagt nicht, ob es die beste Praxis ist. Es ist möglicherweise einfacher zu erkennen, wenn Sie es später betrachten, wenn Sie einfach das Formular für die Aktualisierung und die neue Registrierung trennen. Wenn Sie das Formular jedoch allgemein machen, können Sie auch die Fehlermeldung allgemein machen, sodass ich diese Methode ausführen werde Wurde ausgewählt. Ich wäre dankbar, wenn jemand hilfreich sein könnte.

2020/06/09 Bearbeiten

Wenn die "@ GroupSequence" der Validierung alle gleich ist, gab es ein Problem, dass die Validierung nicht abgefangen wurde, als andere Felder fehlerhaft waren. Dies liegt daran, dass das gefilterte BindingResult nach ValidGroup1 nicht ausgegeben wird, da angegeben wird, dass ValidGroup2,3,4 darunter nicht ausgegeben wird, wenn es in ValidGroup1 von GroupOrder abgefangen wird. Daher ist es notwendig, "@ GroupSequence" separat vorzubereiten und anzuwenden.

Recommended Posts

Filtern Sie das Ergebnis von BindingResult [Spring]
Filtern Sie die Schwankungen der Rohdaten
Die Frühjahrsvalidierung war in der Reihenfolge von Form und BindingResult wichtig
Die Geschichte der Begegnung mit Spring Custom Annotation
Holen Sie sich das Ergebnis von POST in Java
Informationen zur ersten Anzeige von Spring Framework
[Java] [Spring] Testen Sie das Verhalten des Loggers
Über den offiziellen Startleitfaden für Spring Framework
Die Geschichte der Erhöhung der Spring Boot 1.5-Serie auf die 2.1-Serie
Lassen Sie uns das Gefühl von Spring Boot + Swagger 2.0 überprüfen
Holen Sie sich den Body-Teil von HttpResponse mit Spring Filter
So zeigen Sie das Ergebnis des Ausfüllens des Formulars an
Der offizielle Name von Spring MVC ist Spring Web MVC
[Frühling] Fallstricke von BeanUtils.copyProperties
[Für Anfänger] DI ~ Die Grundlagen von DI und DI im Frühjahr ~
Runden Sie das Ergebnis einer Bruchberechnung nicht einfach ab
Greifen Sie mit jdbcTemplate auf das integrierte h2db des Spring Boot zu
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Beurteilung des Kalenders
Die Welt der Clara-Regeln (4)
Die Welt der Clara-Regeln (1)
Über DI des Frühlings ②
Die Welt der Clara-Regeln (3)
Bis zur Verwendung von Spring Data und JPA Part 2
Die Welt der Clara-Regeln (5)
Bis zur Verwendung von Spring Data und JPA Part 1
Die Idee der schnellen Sortierung
Eine Übersicht über die Spring Framework Resource-Oberfläche
Überprüfen Sie das Ergebnis der generischen Parameterinferenz mit JShell
Überprüfen Sie das Verhalten von include, exclude und ExhaustedRetryException von Spring Retry
Steuern Sie den Spring Batch-Verarbeitungsablauf mit JavaConfig.
Eine Aufzeichnung über das Studium des Spring Framework von Grund auf neu
Übersicht über Spring AOP
Die Idee von jQuery
Die Geschichte der Erhöhung von Spring Boot von 1.5 auf 2.1 Serie Teil2
Fügen Sie die Datei in die Eigenschaften eines Strings mit Spring XML-Konfiguration ein
Eine Geschichte voller Grundlagen von Spring Boot (gelöst)
Seite, auf der Sie die Versionsrelation von spring (?) Sehen können
Lassen Sie uns das Betriebsbild (Atmosphäre) des DI-Containers von Spring erfassen
Über den Umgang mit Null
Docker-Überwachung - Erläuterung der Grundlagen der Grundlagen
Ausführungsergebnis-Memo von String.substring
Informationen zur Beschreibung von Docker-compose.yml
Das Spiel der Instanziierung von java.lang.Void
Medianwert von drei Werten
Die Illusion der Objektorientierung
Probieren Sie das Spring WebFlux-Tutorial aus
Ich möchte den Ablauf der Spring-Verarbeitungsanforderungsparameter verstehen
Rufen Sie in Spring Boot eine Proxy-Instanz der Komponente selbst ab
Teil 4: Passen Sie das Verhalten der von Spring Security 5 unterstützten OAuth 2.0-Anmeldung an
Erhalten Sie Flux-Ergebnisse von Spring Web Flux von JS mit der Fetch-API
Sehen Sie sich das Verhalten von Entitätsaktualisierungen mit Spring Boot + Spring Data JPA an
Ich möchte die Standardfehlermeldung von Spring Boot steuern