Java >> Java Tutorial >  >> Tag >> Spring

Spring From the Trenches:Analysieren von Datums- und Zeitinformationen aus einem Anforderungsparameter

Vor ein paar Tagen musste ich eine Controller-Methode schreiben, die zum Hochladen von Dateien in eine Spring-Webanwendung verwendet wird.

Dies ist eine einfache Aufgabe, aber ich hatte eine andere Anforderung, die sich als Problem herausstellte:Jede Datei hat ein Ablaufdatum, das beim Hochladen der Datei angegeben werden muss.

Was ist schief gelaufen?

Das Problem:Fehlgeschlagener Typkonvertierungsversuch

Das Problem besteht darin, dass Spring eine Anforderungsparameterzeichenfolge nicht in ein Objekt konvertieren kann, das die Datums- (und Uhrzeit-) Informationen enthält. Ich werde dieses Problem demonstrieren, indem ich einen einfachen Controller verwende, der zwei Methoden hat:

  • Der POST Anfragen werden an folgende URL gesendet:'/api/datetime/date ' werden von processDate() verarbeitet Methode.
  • Der POST Anfragen werden an folgende URL gesendet:'/api/datetime/datetime ' werden von processDateTime() behandelt Methode.

Der Quellcode dieser Controller-Klasse sieht wie folgt aus:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;

@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {

    @RequestMapping(value = "date", method = RequestMethod.POST)
    public void processDate(@RequestParam("date") LocalDate date) {
		//Do stuff
    }

    @RequestMapping(value = "datetime", method = RequestMethod.POST)
    public void processDateTime(@RequestParam("datetime") LocalDateTime dateAndTime) {
		//Do stuff
    }
}

Diese Controller-Klasse hat zwei Probleme:

  • Wenn wir einen POST senden Anfrage an die URL:'/api/datetime/date ' und legen Sie den Wert des Datums fest Anforderungsparameter an:2015-09-26 (ISO 8601-Datumsformat), eine ConversionFailedException wird geworfen.
  • Wenn wir einen POST senden Anfrage an die URL:'/api/datetime/datetime ' und legen Sie den Wert von datetime fest Anforderungsparameter an:2015-09-26T01:30:00.000 (ISO 8601 Datums- und Uhrzeitformat), eine ConversionFailedException wird geworfen.

Mit anderen Worten, wir können die von DateTimeController bereitgestellte API nicht verwenden Klasse, weil es kaputt ist. Lassen Sie uns herausfinden, wie wir das Problem beheben können.

@DateTimeFormat Anmerkung zur Rettung

Das Javadoc des @DateTimeFormat Anmerkung gibt an, dass sie deklariert, dass ein Feld als Datumszeit formatiert werden soll. Auch wenn das Javadoc es nicht erwähnt, können wir diese Anmerkung verwenden, um das Muster anzugeben, das von unseren Anfrageparametern verwendet wird.

Diese Beispiele zeigen, wie wir diese Anmerkung verwenden können:

Beispiel 1:

Wenn wir das ISO 8601-Datumsformat verwenden möchten (yyyy-MM-dd ), müssen wir den Controller-Methodenparameter mit @DateTimeFormat annotieren -Anmerkung und legen Sie den Wert ihrer iso fest Attribut zu DateTimeFormat.ISO.DATE . Die Controller-Klasse, die dieses Datumsformat verwendet, sieht wie folgt aus:

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;

@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {

    @RequestMapping(value = "date", method = RequestMethod.POST)
    public void processDate(@RequestParam("date") 
							@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
        //Do stuff
    }
}

Beispiel 2:

Wenn wir ein benutzerdefiniertes Datumsformat verwenden möchten (wie das finnische Datumsformat:dd.MM.yyyy ), müssen wir den Controller-Methodenparameter mit @DateTimeFormat annotieren -Anmerkung und legen Sie den Wert ihres Musters fest Attribut auf 'dd.MM.yyyy'. Die Controller-Klasse, die dieses Datumsformat verwendet, sieht wie folgt aus:

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;

@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {

    @RequestMapping(value = "date", method = RequestMethod.POST)
    public void processDate(@RequestParam("date") 
							@DateTimeFormat(pattern = "dd.MM.yyyy") LocalDate date) {
        //Do stuff
    }
}
Beispiel 3:

Wenn wir das Datums- und Uhrzeitformat nach ISO 8601 verwenden möchten (yyyy-MM-dd'T'HH:mm:ss.SSSZ ), müssen wir den Controller-Methodenparameter mit @DateTimeFormat annotieren -Anmerkung und legen Sie den Wert ihrer iso fest Attribut zu DateTimeFormat.ISO.DATE_TIME . Die Controller-Klasse, die dieses Datumsformat verwendet, sieht wie folgt aus:

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;

@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {

	@RequestMapping(value = "datetime", method = RequestMethod.POST)
	public void processDateTime(@RequestParam("datetime") 
								@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateAndTime) {
		//Do stuff
    }
}

Beispiel 4:
Wenn wir ein benutzerdefiniertes Datums- und Zeitformat verwenden möchten (wie das finnische Datums- und Zeitformat:dd.MM.yyyy HH:mm:ss.SSSZ ), müssen wir den Methodenparameter des Controllers mit der Annotation @DateTimeFormat annotieren und den Wert seines Musters festlegen Attribut zu „dd.MM.yyyy HH:mm:ss.SSSZ“. Die Controller-Klasse, die dieses Datumsformat verwendet, sieht wie folgt aus:

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;

@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {

	@RequestMapping(value = "datetime", method = RequestMethod.POST)
	public void processDateTime(@RequestParam("datetime") 
								@DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss.SSSZ") LocalDateTime dateAndTime) {
		//Do stuff
    }
}

Fassen wir zusammen, was wir aus diesem Blogbeitrag gelernt haben.

Zusammenfassung

Dieser Blogbeitrag hat uns drei Dinge gelehrt:

  • Wir können das @DateTimeFormat anwenden Anmerkung zu java.util.Date , java.util.Calendar , java.lang.Long , Joda-Time-Werttypen; und ab Spring 4 und JDK 8 zu JSR-310 java.time Typen auch.
  • Wenn wir das ISO 8601-Format verwenden wollen, müssen wir das verwendete Format konfigurieren, indem wir den Wert von @DateTimeFormat setzen iso der Anmerkung Attribut.
  • Wenn wir ein benutzerdefiniertes Format verwenden möchten, müssen wir das verwendete Format konfigurieren, indem wir den Wert von @DateTimeFormat festlegen Muster der Anmerkung Attribut.

P.S. Sie können die Beispielanwendung dieses Blogbeitrags von Github herunterladen.


Java-Tag