2017-07-07 1 views
0

J'utilise Spring Boot 1.5.3, Spring Data REST, Spring JPA, Hibernate. Je travaille en UTC avec java.time. * Sur le serveur, et mes clients sont également censés renvoyer des dates en UTC. Je personnalisé un peu ma configuration REST:Printemps MVC LocalDate paramètre a un format incorrect

@Configuration 
public class RestConfig extends RepositoryRestConfigurerAdapter { 

@Bean 
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { 
    return new Jackson2ObjectMapperBuilderCustomizer() { 

     @Override 
     public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) { 

      jacksonObjectMapperBuilder.serializers(InstantSerializer.INSTANCE); 
      jacksonObjectMapperBuilder.serializers(new ZonedDateTimeSerializer(ISO_FIXED_FORMAT)); 
      jacksonObjectMapperBuilder 
        .serializers(new LocalDateSerializer(new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter())); 
      jacksonObjectMapperBuilder.serializers(new LocalDateTimeSerializer(
        new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").toFormatter())); 
     } 

    }; 
} 

}

J'ai créé une méthode personnalisée dans un référentiel:

@Transactional 
@PreAuthorize("isAuthenticated()") 
public interface DailyCodeRepository extends PagingAndSortingRepository<DailyCode, Long> { 


    @Query("SELECT d FROM DailyCode d WHERE (:code IS NULL OR code=:code) AND (:from IS NULL OR date>=:from) AND (:to IS NULL OR date<=:to)") 
    public Page<DailyCode> findAllWithParameter(@Param("code") @RequestParam(value = "code", required = false) String code, 
      @Param("from") @RequestParam(value = "from", required = false) @DateTimeFormat(iso=ISO.DATE) LocalDate from, 
      @Param("to") @RequestParam(value = "to", required = false) @DateTimeFormat(iso=ISO.DATE) LocalDate to, Pageable pageable); 
} 

Le premier problème est que la méthode accepte le format ISO seulement si je mets l'annotation @DateTimeFormat(iso=ISO.DATE), sinon il choisit le format de mes paramètres régionaux (Italie). Je veux le définir globalement comme fait pour la réponse (voir mon Jackson2ObjectMapperBuilderCustomizer).

Le deuxième problème est que les paramètres de la date d'envoi du client sont interprétées comme 1 jour avant, donc une telle demande:

http://localhost:8080/api/v1/dailyCodes/search/findAllWithParameter?from=2017-07-07&to=2017-07-07 

cause cette requête sur la base de données:

select dailycode0_.`id` as id1_7_, dailycode0_.`created_by` as created_2_7_, dailycode0_.`created_date` as created_3_7_, dailycode0_.`last_modified_by` as last_mod4_7_, dailycode0_.`last_modified_date` as last_mod5_7_, dailycode0_.`sid` as sid6_7_, dailycode0_.`version` as version7_7_, dailycode0_.`code` as code8_7_, dailycode0_.`date` as date9_7_ from `daily_code` dailycode0_ where (null is null or dailycode0_.`code`=null) and ('2017-07-06' is null or dailycode0_.`date`>='2017-07-06') and ('2017-07-06' is null or dailycode0_.`date`<='2017-07-06') limit 20 

Donc, il interroge 1 jour avant et c'est faux. Je suppose que c'est un problème de fuseau horaire, mais je n'arrive pas à trouver une solution.

Ceci est la partie pertinente de mes propriétés fichier:

spring.mvc.date-format= `yyyy-MM-dd` 
# REST 
spring.data.rest.default-page-size= 20 
spring.data.rest.base-path=/api/v1 
spring.data.rest.enable-enum-translation=true 

#Jackson 

# to avoid an error loading lazy objects 
spring.jackson.serialization.fail-on-empty-beans=false 
spring.jackson.serialization.write-dates-as-timestamps=false 
spring.jackson.mapper.infer-property-mutators=false 
spring.jpa.properties.hibernate.jdbc.time_zone = UTC 

Répondre

1

Vous avez plusieurs questions dans votre code:

Le premier problème est que la méthode accepte le format ISO uniquement

Vous avez besoin d'un OffsetDateTime (pas ZonedDateTime, lire this) et d'un convertisseur personnalisé. Lisez this.

paramètres de la date d'envoi du client sont interprétées comme 1 jour avant

Pourquoi? À quel fuseau horaire interprétez-vous cette date? Votre fuseau horaire local peut être différent de celui du serveur qui peut être différent de celui du client.

Jackson2ObjectMapperBuilderCustomizer

Qu'est-ce utilisé?

spring.mvc.date format = aaaa-mm-jj

Cela ne devrait pas être nécessaire, et je ne pense pas que quoi que ce soit fait pour les données de printemps de toute façon.

+0

La méthode doit accepter uniquement une date sans information de temps. Je n'ai pas besoin de ça dans ce cas.J'utilise Spring Data REST, donc il n'y a pas d'implémentation de cette méthode. Le fuseau horaire du serveur est Europe/Rome, mais je travaille et stocke les dates au format UTC dans la base de données grâce à la configuration affichée. A propos de Jackson2ObjectMapperBuilderCustomizer J'ai édité ma question en ajoutant la classe, selon https://github.com/spring-projects/spring-boot/issues/4217 – drenda

+0

@drenda Vous avez évidemment besoin de convertir la chaîne envoyée par le client en une date, indépendamment de tout ce que vous envoyez à 'findAllWithParameter'. Si vous passez aveuglément la chaîne envoyée par le client à la méthode, vous supposez que tous vos clients proviennent du même emplacement, ce qui est évidemment faux. Ensuite, il y a la question de la conversion entre 'findAllWithParameter' et l'heure de DB, que vous dites est UTC. Spring Les méthodes de données peuvent avoir des corps si nécessaire. Vous aurez besoin d'un référentiel personnalisé dans ce cas. –

+0

Parce que l'utilisation de l'UTC est une bonne pratique, mon client (dans ce cas, une application Angular) enverra toutes les dates au format UTC. Donc, je ne vois pas le besoin d'avoir beaucoup de code standard pour une chose qui devrait être assez standard. Merci – drenda