如何在 REST API 中以 POST 方法发送日期

新手上路,请多包涵

我正在尝试构建具有 Spring 支持的 RESTful Web 服务。当我尝试发送 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 类:

 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 + "]";
    }
}

仅供参考:我确实检查了 这篇 文章,但没有得到像我到底需要在哪里进行修改这样的线索。

我正在使用 Java 8 和 Spring 4.2

有人可以详细解释一下我到底需要做什么吗? 当我点击 GET 请求时,我也想要相同的日期格式。

谢谢。

原文由 Amit Gawali 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 731
2 个回答

您可以制作自定义 LocalDate 反序列化器。当调用 LocalDate 变量的 setter 方法时,将调用此 Deserializer。

步骤如下:

  1. 定义自定义反序列化器
   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 方法。

  1. 在变量上方定义@JsonDeserialize 注解
   @JsonDeserialize(using=LocalDateDeserializer.class)
   private LocalDate quantityAtDate;

对于使用 @JsonDeserialize 注释导入以下内容:

导入 com.fasterxml.jackson.databind.annotation.JsonDeserialize;

希望这可以帮助。

原文由 SachinSarawgi 发布,翻译遵循 CC BY-SA 3.0 许可协议

错误

JsonMappingException 是 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 格式序列化。如果要更改格式,可以使用 @JsonFormat

 @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM")
private LocalDate date;

不需要自定义(反)序列化器。

原文由 cassiomolin 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题