2017-01-27 3 views
1

:私はつもりだクライアントからJPA @Past私は、単純なDTOオブジェクトを持って春ブートベースのプロジェクトで日付/カレンダー検証

public class ExpenseController { 

private final ExpenseService expenseService; 

    @Autowired 
    public ExpenseController(ExpenseService expenseService) { 
     this.expenseService = expenseService; 
    } 

    @RequestMapping(value = ADD_EXPENSE, method = POST) 
    public ResponseEntity addExpense(@Valid @RequestBody ExpenseDTO expenseDTO, Principal principal) { 
     expenseService.addExpense(expenseDTO, principal.getName()); 
     return ResponseEntity.ok().build(); 
    } 
} 

public class ExpenseDTO { 

    @Min(value = 1, message = "expense.amount.negative") 
    private int amount; 

    @Past 
    private Calendar createdAt; 

    // setters/getters/constructor are omitted 
} 

や、残りのコントローラ現在の日付:{"createdAt": "2017-01-27T21:32:19.183Z"}を送信しますが、バックエンドの検証中に日付は "2017-01-28T01:30:00.000 + 0200"というように解析されます結果は間違っており、検証は失敗します。私は@JsonFormatで遊んでいましたが、結果はありませんでした。

注:H2データベースを使用していますが、DTOオブジェクトから@Pastを削除するとすべて正常に機能しますが、将来の日付を無効にする必要があります。

タイムゾーンなしで日付を検証するにはどうすればいいですか?クライアントから送信されたものと同じ日付をバックエンドで正確に必要としますか?

+1

クライアントが '2017-01-27T21:32:19.183Z'を送信している場合、それはどのようにして' 2017-01-28T01:30:00.000 + 0200'に変換されましたか?それは同じ時代に近いことさえありません。 「2017-01-27T23:32:19.183 + 0200」は同じ時刻になります。 – Andreas

+0

@Andreas私はそれが私のJVMのタイムゾーンがGMT + 2であると思う。 – TimurJD

答えて

1

ローカルマシンにTimeZoneが設定されている可能性があります。あなたは、例えば、アプリケーションの起動にUTCに設定することができます

TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 

また、あなたは(あなたがBeanとしてObjectMapperを設定している場合)ObjectMapper内に構成されているSimpleDateFormatインスタンスにTimeZoneを設定する必要があり、例えば:それはまだ動作しない場合

@Bean 
public ObjectMapper objectMapper(){ 
    ObjectMapper objectMapper = new ObjectMapper(); 
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 
    objectMapper.setSerializationInclusion(Include.NON_NULL); 

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'Z'"); 
    simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 
    objectMapper.setDateFormat(simpleDateFormat); 
    return objectMapper; 
} 

は、私は例えば、カレンダーのカスタムデシリアライザを作成し、手動で新しいインスタンスにTimeZoneを設定することをお勧めします:

@Component 
public class CalendarDeserialiser extends JsonDeserializer<Calendar>{ 

    TimeZone UTC = TimeZone.getTimeZone("UTC"); 
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'Z'"); 

    @Override 
    public Calendar deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 

     Calendar calendar; 
     try{ 
      calendar = Calendar.getInstance(UTC); 
      calendar.setTime(dateFormat.parse(p.getText())); 
     }catch(Exception e){ 
      throw new IOException(e); 
     } 
     calendar.setTimeInMillis(p.getLongValue()); 
     return calendar; 
    } 
} 

Calendarフィールドには@JsonDeserialize(using = CalendarDeserialiser.class)と注釈を付けてください。

+0

CalendarDeserialiserとの日付はUTCタイムゾーンであるが、@Pastの検証はまだ失敗する – TimurJD

+0

「21:32Z」が01:30 + 0200」、明らかに「23:32 + 0200」でなければなりません。 2分はどこに消えたのですか?なぜ2時間はオフですか? '@Part'の検証の詳細はわかりませんが、検証の時点で' 21:32Z 'が過去にあったと仮定すると、 '23:32 + 0200'も過去にあったでしょう。まったく同じ物理的時間。問題はタイムゾーンではなく、翌日の「23:32 + 0200」から「01:30 + 0200」までの値の破損*です。 – Andreas

+0

これで、過去の検証は正常に動作しました。私はCalendarDeserialiserを使用しましたが、削除を忘れました。 PostConstruct public void started(){ setDefault(getTimeZone( "UTC")); } DBには、マイナス2時間の日付が格納されています – TimurJD

関連する問題