简体   繁体   English

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

[英]How to send Date in REST API in POST method

I am trying to build RESTful web service with Spring support. 我正在尝试通过Spring支持构建RESTful Web服务。 I am getting following exception when I am trying to send POST request. 尝试发送POST请求时出现以下异常。

Input: 输入:

POST    http://localhost:8080/InventoryDemo/item

In JSON Payload: 在JSON有效负载中:

{"materialId":"ID02","materialName":"Material_2","materialCategory":"LIQUID","currency":"RUPEES","unitCostInCurrency":2200.0,"quantityLevel":1000,"quantityAtDate":"2016-04-11","warehouseName":"WareHouse_2"}

Exception: 例外:

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"])

This is my POST method from @RestController: 这是我来自@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);
    }

and this is my POJO class: 这是我的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 + "]";
    }
}

FYI: I did checked this post but not getting clue like where exactly I need to do modification. 仅供参考:我确实检查了这篇文章,但没有得到确切的线索,例如我确实需要进行修改。

I am using Java 8 and Spring 4.2 我正在使用Java 8和Spring 4.2

Can some one please explain in detail like what exactly I need to do here. 有人可以详细解释一下,例如我到底需要在这里做什么。 Also I want same date format when I will hit GET request. 另外,当我点击GET请求时,我想要相同的日期格式。

Thanks. 谢谢。

The error 错误

JsonMappingException is an exception thrown by Jackson, a JSON parser for Java. JsonMappingException是由Java的JSON解析器Jackson引发的异常。 It indicates fatal problems when mapping a JSON to a Java bean. 它表示将JSON映射到Java bean时出现致命问题。

In this situation, looks like the string 2016-04-11 cannot be parsed to a LocalDate from Java 8. 在这种情况下,看起来字符串2016-04-11无法从Java 8解析为LocalDate

How to fix it 如何修复

Jackson supports Java 8 date types, but the following dependency is required: Jackson支持Java 8日期类型,但是需要以下依赖项:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>${jackson.version}</version>
</dependency>

And then configure your ObjectMapper : 然后配置您的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;
    }
}

By default, dates will be serialized in the ISO 8601 format. 默认情况下,日期将以ISO 8601格式序列化。 If you want to change the format, you can use @JsonFormat : 如果要更改格式,可以使用@JsonFormat

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

No custom (de)serializers are required. 不需要自定义(反)序列化器。

You can make your Custom LocalDate Deserializer. 您可以创建自定义LocalDate反序列化器。 This Deserializer will be called when setter method for the LocalDate variable is called. 当调用LocalDate变量的setter方法时,将调用此反序列化器。

Steps as follows: 步骤如下:

  1. Define a Custom Deserializer 定义自定义反序列化器

     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; } } 

Note: Reference for LocalDate.parse method. 注意: LocalDate.parse方法的参考。

  1. Define @JsonDeserialize annotation above the variable 在变量上方定义@JsonDeserialize批注

     @JsonDeserialize(using=LocalDateDeserializer.class) private LocalDate quantityAtDate; 

For using @JsonDeserialize annotation import following: 要使用@JsonDeserialize注释导入,请执行以下操作:

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

Hope this helps. 希望这可以帮助。

Make use of @JsonFormat to define the date format 利用@JsonFormat定义日期格式

http://www.baeldung.com/jackson-serialize-dates 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
}

Request : 要求:

{
    "materialId": "ID02",
    "materialName": "Material_2",
    "materialCategory": "LIQUID",
    "currency": "RUPEES",
    "unitCostInCurrency": 2200.0,
    "quantityLevel": 1000,
    "quantityAtDate": "2016-04-11",
    "warehouseName": "WareHouse_2"
}

Response : 回应:

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]

Use a deserializer for parsing the LocalDate. 使用反序列化器来解析LocalDate。

Add Maven dependency - 添加Maven依赖-

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.8.10</version>
    </dependency>

If your restful service is parsing the bean directly, add the below 如果您的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){
}

Else, add deserializer in the bean class. 否则,在bean类中添加deserializer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM