如何在 POST 方法中以 REST API 发送日期
How to send Date in REST API in POST method
我正在尝试构建具有 Spring 支持的 RESTful 网络服务。当我尝试发送 POST 请求时出现以下异常。
输入:
POST http://localhost:8080/InventoryDemo/item
在 JSON 负载中:
{"materialId":"ID02","materialName":"Material_2","materialCategory":"LIQUID","currency":"RUPEES","unitCostInCurrency":2200.0,"quantityLevel":1000,"quantityAtDate":"2016-04-11","warehouseName":"WareHouse_2"}
异常:
WARNING: Handler execution resulted in exception: Could not read document: Can not instantiate value of type [simple type, class java.time.LocalDate] from String value ('2016-04-11'); no single-String constructor/factory method
at [Source: java.io.PushbackInputStream@378ace07; line: 1, column: 146] (through reference chain: com.psl.inventory.model.InventorySystemModel["quantityAtDate"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class java.time.LocalDate] from String value ('2016-04-11'); no single-String constructor/factory method
at [Source: java.io.PushbackInputStream@378ace07; line: 1, column: 146] (through reference chain: com.psl.inventory.model.InventorySystemModel["quantityAtDate"])
这是我来自@RestController 的 POST 方法:
@RequestMapping(value = "/item", method = RequestMethod.POST)
public ResponseEntity<Void> createInventorySystemModel(@RequestBody InventorySystemModel inventorySystemModel, UriComponentsBuilder ucBuilder) {
System.out.println("Creating InventorySystemModel " + inventorySystemModel.getMaterialName());
if (inventorySystemService.isInventorySystemModelExist(inventorySystemModel)) {
System.out.println("A InventorySystemModel with name " + inventorySystemModel.getMaterialName() + " already exist");
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}
inventorySystemService.saveInventoryItem(inventorySystemModel);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/user/{materialId}").buildAndExpand(inventorySystemModel.getMaterialId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
这是我的 POJO class:
public class InventorySystemModel {
private String materialId;
private String materialName;
private String materialCategory;
private String currency;
private double unitCostInCurrency;
private int quantityLevel;
private LocalDate quantityAtDate;
private String warehouseName;
public InventorySystemModel(){
}
public InventorySystemModel(String materialId, String materialName,
String materialCategory, String currency,
double unitCostInCurrency, int quantityLevel, LocalDate quantityAtDate,
String warehouseName) {
super();
this.materialId = materialId;
this.materialName = materialName;
this.materialCategory = materialCategory;
this.currency = currency;
this.unitCostInCurrency = unitCostInCurrency;
this.quantityLevel = quantityLevel;
this.quantityAtDate = quantityAtDate;
this.warehouseName = warehouseName;
}
public String getMaterialId() {
return materialId;
}
public void setMaterialId(String materialId) {
this.materialId = materialId;
}
public String getMaterialName() {
return materialName;
}
public void setMaterialName(String materialName) {
this.materialName = materialName;
}
public String getMaterialCategory() {
return materialCategory;
}
public void setMaterialCategory(String materialCategory) {
this.materialCategory = materialCategory;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public double getUnitCostInCurrency() {
return unitCostInCurrency;
}
public void setUnitCostInCurrency(double unitCostInCurrency) {
this.unitCostInCurrency = unitCostInCurrency;
}
public int getQuantityLevel() {
return quantityLevel;
}
public void setQuantityLevel(int quantityLevel) {
this.quantityLevel = quantityLevel;
}
public LocalDate getQuantityAtDate() {
return quantityAtDate;
}
public void setQuantityAtDate(LocalDate quantityAtDate) {
this.quantityAtDate = quantityAtDate;
}
public String getWarehouseName() {
return warehouseName;
}
public void setWarehouseName(String warehouseName) {
this.warehouseName = warehouseName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((currency == null) ? 0 : currency.hashCode());
result = prime
* result
+ ((materialCategory == null) ? 0 : materialCategory.hashCode());
result = prime * result
+ ((materialId == null) ? 0 : materialId.hashCode());
result = prime * result
+ ((materialName == null) ? 0 : materialName.hashCode());
result = prime * result
+ ((quantityAtDate == null) ? 0 : quantityAtDate.hashCode());
result = prime * result + quantityLevel;
long temp;
temp = Double.doubleToLongBits(unitCostInCurrency);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result
+ ((warehouseName == null) ? 0 : warehouseName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InventorySystemModel other = (InventorySystemModel) obj;
if (currency == null) {
if (other.currency != null)
return false;
} else if (!currency.equals(other.currency))
return false;
if (materialCategory == null) {
if (other.materialCategory != null)
return false;
} else if (!materialCategory.equals(other.materialCategory))
return false;
if (materialId == null) {
if (other.materialId != null)
return false;
} else if (!materialId.equals(other.materialId))
return false;
if (materialName == null) {
if (other.materialName != null)
return false;
} else if (!materialName.equals(other.materialName))
return false;
if (quantityAtDate == null) {
if (other.quantityAtDate != null)
return false;
} else if (!quantityAtDate.equals(other.quantityAtDate))
return false;
if (quantityLevel != other.quantityLevel)
return false;
if (Double.doubleToLongBits(unitCostInCurrency) != Double
.doubleToLongBits(other.unitCostInCurrency))
return false;
if (warehouseName == null) {
if (other.warehouseName != null)
return false;
} else if (!warehouseName.equals(other.warehouseName))
return false;
return true;
}
@Override
public String toString() {
return "InventorySystemModel [materialId=" + materialId
+ ", materialName=" + materialName + ", materialCategory="
+ materialCategory + ", currency=" + currency
+ ", unitCostInCurrency=" + unitCostInCurrency
+ ", quantityLevel=" + quantityLevel + ", quantityAtDate="
+ quantityAtDate + ", warehouseName=" + warehouseName + "]";
}
}
仅供参考:我确实检查了 this post 但没有得到像我需要修改的确切位置这样的线索。
我正在使用 Java 8 和 Spring 4.2
有人可以详细解释一下我到底需要做什么吗?
此外,当我点击 GET 请求时,我想要相同的日期格式。
谢谢。
利用@JsonFormat定义日期格式
http://www.baeldung.com/jackson-serialize-dates
public class InventorySystemModel {
private String materialId;
private String materialName;
private String materialCategory;
private String currency;
private double unitCostInCurrency;
private int quantityLevel;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date quantityAtDate;
private String warehouseName;
//getters and setters
}
要求:
{
"materialId": "ID02",
"materialName": "Material_2",
"materialCategory": "LIQUID",
"currency": "RUPEES",
"unitCostInCurrency": 2200.0,
"quantityLevel": 1000,
"quantityAtDate": "2016-04-11",
"warehouseName": "WareHouse_2"
}
回复:
InventorySystemModel [materialId=ID02, materialName=Material_2, materialCategory=LIQUID, currency=RUPEES, unitCostInCurrency=2200.0, quantityLevel=1000, quantityAtDate=Mon Apr 11 05:30:00 IST 2016, warehouseName=WareHouse_2]
您可以让您的自定义 LocalDate Deserializer. This Deserializer will be called when setter method for the LocalDate 变量被调用。
步骤如下:
定义自定义解串器
public class LocalDateDeserializer extends JsonDeserializer<LocalDate>{
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("required format");
LocalDate localDate = null;
localDate = LocalDate.parse(p.getText(), formatter);
return localDate;
}
}
注:参考LocalDate.parse方法。
在变量上方定义@JsonDeserialize注解
@JsonDeserialize(using=LocalDateDeserializer.class)
private LocalDate quantityAtDate;
使用@JsonDeserialize 注释导入如下:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
希望对您有所帮助。
错误
JsonMappingException
是 Jackson 抛出的异常,Jackson 是 Java 的 JSON 解析器。它表示将 JSON 映射到 Java bean 时出现致命问题。
在这种情况下,字符串 2016-04-11
似乎无法从 Java 8.
解析为 LocalDate
如何修复
Jackson 支持Java 8 种日期类型,但需要以下依赖:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
然后配置你的ObjectMapper
:
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
默认情况下,日期将在 ISO 8601 format. If you want to change the format, you can use @JsonFormat
:
中序列化
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM")
private LocalDate date;
不需要自定义(反)序列化程序。
使用解串器解析 LocalDate。
添加 Maven 依赖 -
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.10</version>
</dependency>
如果您的 restful 服务直接解析 bean,请添加以下内容
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
@PostMapping(value = "/xyz")
@JsonDeserialize(using = LocalDateDeserializer.class)
public ResponseEntity <String> testMethod (@RequestBody Bean bean){
}
否则,在 bean class 中添加 deserializer
。
我正在尝试构建具有 Spring 支持的 RESTful 网络服务。当我尝试发送 POST 请求时出现以下异常。
输入:
POST http://localhost:8080/InventoryDemo/item
在 JSON 负载中:
{"materialId":"ID02","materialName":"Material_2","materialCategory":"LIQUID","currency":"RUPEES","unitCostInCurrency":2200.0,"quantityLevel":1000,"quantityAtDate":"2016-04-11","warehouseName":"WareHouse_2"}
异常:
WARNING: Handler execution resulted in exception: Could not read document: Can not instantiate value of type [simple type, class java.time.LocalDate] from String value ('2016-04-11'); no single-String constructor/factory method
at [Source: java.io.PushbackInputStream@378ace07; line: 1, column: 146] (through reference chain: com.psl.inventory.model.InventorySystemModel["quantityAtDate"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class java.time.LocalDate] from String value ('2016-04-11'); no single-String constructor/factory method
at [Source: java.io.PushbackInputStream@378ace07; line: 1, column: 146] (through reference chain: com.psl.inventory.model.InventorySystemModel["quantityAtDate"])
这是我来自@RestController 的 POST 方法:
@RequestMapping(value = "/item", method = RequestMethod.POST)
public ResponseEntity<Void> createInventorySystemModel(@RequestBody InventorySystemModel inventorySystemModel, UriComponentsBuilder ucBuilder) {
System.out.println("Creating InventorySystemModel " + inventorySystemModel.getMaterialName());
if (inventorySystemService.isInventorySystemModelExist(inventorySystemModel)) {
System.out.println("A InventorySystemModel with name " + inventorySystemModel.getMaterialName() + " already exist");
return new ResponseEntity<Void>(HttpStatus.CONFLICT);
}
inventorySystemService.saveInventoryItem(inventorySystemModel);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/user/{materialId}").buildAndExpand(inventorySystemModel.getMaterialId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
这是我的 POJO class:
public class InventorySystemModel {
private String materialId;
private String materialName;
private String materialCategory;
private String currency;
private double unitCostInCurrency;
private int quantityLevel;
private LocalDate quantityAtDate;
private String warehouseName;
public InventorySystemModel(){
}
public InventorySystemModel(String materialId, String materialName,
String materialCategory, String currency,
double unitCostInCurrency, int quantityLevel, LocalDate quantityAtDate,
String warehouseName) {
super();
this.materialId = materialId;
this.materialName = materialName;
this.materialCategory = materialCategory;
this.currency = currency;
this.unitCostInCurrency = unitCostInCurrency;
this.quantityLevel = quantityLevel;
this.quantityAtDate = quantityAtDate;
this.warehouseName = warehouseName;
}
public String getMaterialId() {
return materialId;
}
public void setMaterialId(String materialId) {
this.materialId = materialId;
}
public String getMaterialName() {
return materialName;
}
public void setMaterialName(String materialName) {
this.materialName = materialName;
}
public String getMaterialCategory() {
return materialCategory;
}
public void setMaterialCategory(String materialCategory) {
this.materialCategory = materialCategory;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public double getUnitCostInCurrency() {
return unitCostInCurrency;
}
public void setUnitCostInCurrency(double unitCostInCurrency) {
this.unitCostInCurrency = unitCostInCurrency;
}
public int getQuantityLevel() {
return quantityLevel;
}
public void setQuantityLevel(int quantityLevel) {
this.quantityLevel = quantityLevel;
}
public LocalDate getQuantityAtDate() {
return quantityAtDate;
}
public void setQuantityAtDate(LocalDate quantityAtDate) {
this.quantityAtDate = quantityAtDate;
}
public String getWarehouseName() {
return warehouseName;
}
public void setWarehouseName(String warehouseName) {
this.warehouseName = warehouseName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((currency == null) ? 0 : currency.hashCode());
result = prime
* result
+ ((materialCategory == null) ? 0 : materialCategory.hashCode());
result = prime * result
+ ((materialId == null) ? 0 : materialId.hashCode());
result = prime * result
+ ((materialName == null) ? 0 : materialName.hashCode());
result = prime * result
+ ((quantityAtDate == null) ? 0 : quantityAtDate.hashCode());
result = prime * result + quantityLevel;
long temp;
temp = Double.doubleToLongBits(unitCostInCurrency);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result
+ ((warehouseName == null) ? 0 : warehouseName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
InventorySystemModel other = (InventorySystemModel) obj;
if (currency == null) {
if (other.currency != null)
return false;
} else if (!currency.equals(other.currency))
return false;
if (materialCategory == null) {
if (other.materialCategory != null)
return false;
} else if (!materialCategory.equals(other.materialCategory))
return false;
if (materialId == null) {
if (other.materialId != null)
return false;
} else if (!materialId.equals(other.materialId))
return false;
if (materialName == null) {
if (other.materialName != null)
return false;
} else if (!materialName.equals(other.materialName))
return false;
if (quantityAtDate == null) {
if (other.quantityAtDate != null)
return false;
} else if (!quantityAtDate.equals(other.quantityAtDate))
return false;
if (quantityLevel != other.quantityLevel)
return false;
if (Double.doubleToLongBits(unitCostInCurrency) != Double
.doubleToLongBits(other.unitCostInCurrency))
return false;
if (warehouseName == null) {
if (other.warehouseName != null)
return false;
} else if (!warehouseName.equals(other.warehouseName))
return false;
return true;
}
@Override
public String toString() {
return "InventorySystemModel [materialId=" + materialId
+ ", materialName=" + materialName + ", materialCategory="
+ materialCategory + ", currency=" + currency
+ ", unitCostInCurrency=" + unitCostInCurrency
+ ", quantityLevel=" + quantityLevel + ", quantityAtDate="
+ quantityAtDate + ", warehouseName=" + warehouseName + "]";
}
}
仅供参考:我确实检查了 this post 但没有得到像我需要修改的确切位置这样的线索。
我正在使用 Java 8 和 Spring 4.2
有人可以详细解释一下我到底需要做什么吗? 此外,当我点击 GET 请求时,我想要相同的日期格式。
谢谢。
利用@JsonFormat定义日期格式
http://www.baeldung.com/jackson-serialize-dates
public class InventorySystemModel {
private String materialId;
private String materialName;
private String materialCategory;
private String currency;
private double unitCostInCurrency;
private int quantityLevel;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date quantityAtDate;
private String warehouseName;
//getters and setters
}
要求:
{
"materialId": "ID02",
"materialName": "Material_2",
"materialCategory": "LIQUID",
"currency": "RUPEES",
"unitCostInCurrency": 2200.0,
"quantityLevel": 1000,
"quantityAtDate": "2016-04-11",
"warehouseName": "WareHouse_2"
}
回复:
InventorySystemModel [materialId=ID02, materialName=Material_2, materialCategory=LIQUID, currency=RUPEES, unitCostInCurrency=2200.0, quantityLevel=1000, quantityAtDate=Mon Apr 11 05:30:00 IST 2016, warehouseName=WareHouse_2]
您可以让您的自定义 LocalDate Deserializer. This Deserializer will be called when setter method for the LocalDate 变量被调用。
步骤如下:
定义自定义解串器
public class LocalDateDeserializer extends JsonDeserializer<LocalDate>{ @Override public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("required format"); LocalDate localDate = null; localDate = LocalDate.parse(p.getText(), formatter); return localDate; } }
注:参考LocalDate.parse方法。
在变量上方定义@JsonDeserialize注解
@JsonDeserialize(using=LocalDateDeserializer.class) private LocalDate quantityAtDate;
使用@JsonDeserialize 注释导入如下:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
希望对您有所帮助。
错误
JsonMappingException
是 Jackson 抛出的异常,Jackson 是 Java 的 JSON 解析器。它表示将 JSON 映射到 Java bean 时出现致命问题。
在这种情况下,字符串 2016-04-11
似乎无法从 Java 8.
LocalDate
如何修复
Jackson 支持Java 8 种日期类型,但需要以下依赖:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
然后配置你的ObjectMapper
:
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
}
默认情况下,日期将在 ISO 8601 format. If you want to change the format, you can use @JsonFormat
:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM")
private LocalDate date;
不需要自定义(反)序列化程序。
使用解串器解析 LocalDate。
添加 Maven 依赖 -
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.10</version>
</dependency>
如果您的 restful 服务直接解析 bean,请添加以下内容
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
@PostMapping(value = "/xyz")
@JsonDeserialize(using = LocalDateDeserializer.class)
public ResponseEntity <String> testMethod (@RequestBody Bean bean){
}
否则,在 bean class 中添加 deserializer
。