Spring Data RESTプロジェクトは初めてで、最初のRESTfulサービスを作成しようとしています。タスクは簡単ですが、行き詰まっています。
RESTful APIを使用して、埋め込みデータベースに保存されているユーザーデータに対してCRUD操作を実行したい。
しかし、SpringフレームワークがbirthDataを「1999-12-15」として処理し、LocalDateとして保存する方法を理解することはできません。 @JsonFormatアノテーションは役に立ちません。
現在、私はエラーを受け取ります:
HTTP/1.1 400
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 24 Aug 2017 13:36:51 GMT
Connection: close
{"cause":{"cause":null,"message":"Can not construct instance of Java.time.LocalDate:
no String-argument constructor/factory method to deserialize from String value ('1999-10-10')\n
at [Source: org.Apache.catalina.connector.CoyoteInputStream@4ee2a60e;
line: 1, column: 65] (through reference chain: ru.zavanton.entities.User[\"birthDate\"])"},
"message":"JSON parse error: Can not construct instance of Java.time.LocalDate:
no String-argument constructor/factory method to deserialize from String value ('1999-10-10'); nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Can not construct instance of Java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('1999-10-10')\n
at [Source: org.Apache.catalina.connector.CoyoteInputStream@4ee2a60e; line: 1, column: 65] (through reference chain: ru.zavanton.entities.User[\"birthDate\"])"}
クライアントが次のように呼び出すように機能させる方法:
curl -i -X POST -H "Content-Type:application/json" -d "{ \"firstName\" : \"John\", \"lastName\" : \"Johnson\", \"birthDate\" : \"1999-10-10\", \"email\" : \"[email protected]\" }" http://localhost:8080/users
実際にエンティティをデータベースに保存します。
以下は、クラスに関する情報です。
ユーザークラス:
package ru.zavanton.entities;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import Java.time.LocalDate;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate birthDate;
private String email;
private String password;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public LocalDate getBirthDate() {
return birthDate;
}
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserRepositoryクラス:
package ru.zavanton.repositories;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import ru.zavanton.entities.User;
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
User findByEmail(@Param("email") String email);
}
アプリケーションクラス:
package ru.zavanton;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
このシリアライゼーションとデシリアライゼーションには、ジャクソンの依存関係が必要です。
この依存関係を追加します。
Gradle:
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.4")
メイヴン:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
その後、JavaTimeModuleを使用するようにJackson ObjectMapperに指示する必要があります。それを行うには、メインクラスでObjectMapperをAutowireし、JavaTimeModuleを登録します。
import javax.annotation.PostConstruct;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@SpringBootApplication
public class MockEmployeeApplication {
@Autowired
private ObjectMapper objectMapper;
public static void main(String[] args) {
SpringApplication.run(MockEmployeeApplication.class, args);
}
@PostConstruct
public void setUp() {
objectMapper.registerModule(new JavaTimeModule());
}
}
その後、LocalDateとLocalDateTimeを正しくシリアル化および逆シリアル化する必要があります。
判明したように、jacson依存関係をpomファイルに含めることを忘れないでください。これで問題が解決しました:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
Instant date APIが原因で問題が発生している場合は、次のjackson属性を追加します。
spring:
application:
name: data
jackson:
serialization.write_dates_as_timestamps: false
^-これをymlファイルに追加します
jpa:
open-in-view: false
さて、私がすべてのプロジェクトで行うことは、上記のオプションの組み合わせです。
まず、jsr310依存関係を追加します。
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
重要な詳細:この依存関係を置きます最上部依存関係リストの。このpom.xmlへの依存関係がある場合でも、Localdateエラーが続くプロジェクトを既に見ています。しかし、依存関係の順序を変更すると、エラーはなくなりました。
/src/main/resources/application.yml
ファイルで、write-dates-as-timestamps
プロパティを設定します。
spring:
jackson:
serialization:
write-dates-as-timestamps: false
そして、次のようにObjectMapper
Beanを作成します。
@Configuration
public class WebConfigurer {
@Bean
@Primary
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.build();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
return objectMapper;
}
}
この構成に従って、変換はエラーなしで常にSpring Boot 1.5.xで機能します。
Spring AMQPを使用して、Jackson2JsonMessageConverter
の新しいインスタンスがある場合は注意してください(SimpleRabbitListenerContainerFactory
を作成するときの一般的なこと)。次のように、ObjectMapper
Beanを渡す必要があります。
Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter(objectMapper);
それ以外の場合は、同じエラーが表示されます。