如何在 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 变量被调用。

步骤如下:

  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 注释导入如下:

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