我只想提供一个休息端点,用户可以在其中发送金额。我决定第一次使用 javamoney.moneta.Money 并且它在 Postgres 中一直保持为空。
这是模型:
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.javamoney.moneta.Money;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@Entity
@Table(name = "accounts")
public class Account extends AuditModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
private Money money;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "person_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = true)
@JsonProperty("person_id")
private Person person;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Money getMoney() {
return money;
}
public void setMoney(Money money) {
this.money = money;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
如果相关,这里是连接列的相关模型
import java.util.Date;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Entity
@Table(name = "persons")
public class Person extends AuditModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Size(max = 50)
@Column(unique = true)
private String name;
@NotNull
private String cpf;
@NotNull
@Temporal(TemporalType.DATE)
private Date birthDate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCpf() {
return cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
}
及其 AuditModel
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "createdAt", "updatedAt" }, allowGetters = true)
public abstract class AuditModel implements Serializable {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at", nullable = false, updatable = false)
@CreatedDate
private Date createdAt;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated_at", nullable = false)
@LastModifiedDate
private Date updatedAt;
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}
存储库
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.mybank.accountmanagement.model.Account;
@Repository
public interface AccountRepository extends JpaRepository<Account, Long> {
}
以及暴露端点的 AccountController
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.mybank.accountmanagement.jpa.exception.*;
import com.mybank.accountmanagement.model.Account;
import com.mybank.accountmanagement.repository.AccountRepository;
import com.mybank.accountmanagement.repository.PersonRepository;
@RestController
public class AccountController {
@Autowired
AccountRepository accountRepository;
@Autowired
PersonRepository personRepository;
@PostMapping("/accounts/{personId}")
public Account createAccount(@PathVariable(value = "personId") Long personId, @Valid @RequestBody Account account) {
return personRepository.findById(personId).map(person -> {
account.setPerson(person);
return accountRepository.save(account);
}).orElseThrow(() -> new ResourceNotFoundException("PersonId " + personId + " not found"));
}
}
这是我如何调用其余端点
curl --location --request POST 'localhost:2000/accounts/3' --header 'Content-Type: application/json' --data-raw '{
"amount": 29.95,
"currency": "EUR",
"formatted": "29,95 EUR"
}'
这导致在Account
表中创建新记录但Money
列为空
我尝试通过添加jackson-datatype-money来遵循这个建议这是我的POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.mybank</groupId>
<artifactId>accountmanagement</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>accountmanagement</name>
<description>Test</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!-- exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId>
</exclusion> </exclusions -->
</dependency>
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.3</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.zalando</groupId>
<artifactId>jackson-datatype-money</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
如果它增加了一些有用的点,则此单元测试通过
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.javamoney.moneta.Money;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;
import com.mybank.accountmanagement.model.Account;
import com.mybank.accountmanagement.model.Person;
import com.mybank.accountmanagement.repository.AccountRepository;
import com.mybank.accountmanagement.repository.PersonRepository;
@RunWith(SpringRunner.class)
@DataJpaTest(showSql = true)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class JpaAccountUnitTest {
@Autowired
PersonRepository personRepository;
@Autowired
AccountRepository accountRepository;
@Autowired
private TestEntityManager entityManager;
@Test
public void should_save_an_account() {
Person p1 = new Person();
p1.setCpf("12345678901");
p1.setName("Fulano de tal");
try {
p1.setBirthDate(new SimpleDateFormat("yyyy-MM-dd").parse("1978-04-14"));
} catch (ParseException e) {
e.printStackTrace();
}
p1.setCreatedAt(new Date());
p1.setUpdatedAt(new Date());
Person personSaved = personRepository.save(p1);
Account ac = new Account();
ac.setPerson(personSaved);
ac.setMoney(Money.of(1, "EUR"));
ac.setCreatedAt(new Date());
ac.setUpdatedAt(new Date());
Account accountSaved = accountRepository.save(ac);
Assert.assertEquals(accountSaved.getMoney(), Money.of(1, "EUR"));
}
}
最后,在我认为我做错了什么的地方,在控制器端点上它填充了空值。