Java spring 启动 JSON 两个 Java 应用程序之间的时间戳转换问题

Java spring boot JSON timestamp convert issue between two Java applications

我正在开发两个相互通信的 java 应用程序("backend1" 和 "backend2")。 我得到了这个错误:

[{
    "status": "BAD_REQUEST",
    "timestamp": "2018-07-11 02:54:28",
    "message": "Malformed JSON request",
    "debugMessage": "JSON parse error: Cannot deserialize value of type `java.sql.Timestamp` from String \"Jul 11, 2018 9:32:10 AM\": not a valid representation (error: Failed to parse Date value 'Jul 11, 2018 9:32:10 AM': Cannot parse date \"Jul 11, 2018 9:32:10 AM\": not compatible with any of standard forms (\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\", \"yyyy-MM-dd'T'HH:mm:ss.SSS\", \"EEE, dd MMM yyyy HH:mm:ss zzz\", \"yyyy-MM-dd\")); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.sql.Timestamp` from String \"Jul 11, 2018 9:32:10 AM\": not a valid representation (error: Failed to parse Date value 'Jul 11, 2018 9:32:10 AM': Cannot parse date \"Jul 11, 2018 9:32:10 AM\": not compatible with any of standard forms (\"yyyy-MM-dd'T'HH:mm:ss.SSSZ\", \"yyyy-MM-dd'T'HH:mm:ss.SSS\", \"EEE, dd MMM yyyy HH:mm:ss zzz\", \"yyyy-MM-dd\"))\n at [Source: (PushbackInputStream); line: 1, column: 166] (through reference chain: java.util.ArrayList[0]->com.irm.api.automata.response.AutomataDeliveryNoteModel[\"createdAt\"])",
    "code": null,
    "subErrors": null
}]

我在 backend1 中的一个函数调用了 backend2 控制器,其中 后端 1 代码:

Call<List<DeliverynotesEntity>> deliverynotesEntityCall = commonFunction.retrofitBuilder(commonFunction.getBaseURL()).create(ISendDeliveryNoteCall.class).sendDeliveryNotes(
        commonFunction.getToken(),
        deliverynotesEntities
    );

这是使用retrofit2调用时的界面

import com.irmmat.backend.entity.object.DeliverynotesEntity;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;

import java.util.List;

public interface ISendDeliveryNoteCall {

  @Headers({
      "Content-Type: application/json",
  })
  @POST("send-delivery-note")
  Call<List<DeliverynotesEntity>> sendDeliveryNotes(
      @Header("Authorization") String token,
      @Body List<DeliverynotesEntity> deliverynotesEntityList
  );
}

并且控制器在后端 2:

import com.irm.api.automata.response.AutomataDeliveryNoteModel;
import com.irm.api.service.DeliveryNoteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("api/v1/automata")
public class AutomataDeliveryNoteController {

  private DeliveryNoteService deliveryNoteService;

  @Autowired
  public AutomataDeliveryNoteController(DeliveryNoteService deliveryNoteService) {
    this.deliveryNoteService = deliveryNoteService;
  }

  @PostMapping(value = "/send-delivery-note")
  public ResponseEntity<List<AutomataDeliveryNoteModel>> saveDeliveryNote(@RequestBody List<AutomataDeliveryNoteModel> automataDeliveryNoteModelList) {
    List<AutomataDeliveryNoteModel> noteResponse = deliveryNoteService.saveDeliveryNotes(automataDeliveryNoteModelList);
    return new ResponseEntity<>(noteResponse, HttpStatus.ACCEPTED);
  }
}

这是 json 后端 1 调用在正文中发送的内容

[{
    "id": 15,
    "serpaCostCenterId": 2,
    "serpaProductId": 555549,
    "productQuantity": 1,
    "direction": -1,
    "requesterEmployeeId": 1,
    "supervisorId": 1,
    "createdAt": 1531294330000,
    "serpaSequenceId": 17,
    "sessionId": "0000813701:1530609987"
}]

这里是createdAt引起的问题。这很奇怪,因为如果我使用邮递员通过 url 调用控制器函数,代码是完美的,可以工作,但是 backend1 函数调用 backend2 控制器我得到那个异常。

这是我在后端 1 中使用的送货单实体

package com.irmmat.backend.entity.object;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Objects;

@Entity
@Table(name = "delivery_notes", schema = "irmmat")
public class DeliverynotesEntity implements Serializable {
  private Integer id;
  private Integer serpaCostCenterId;
  private Integer serpaProductId;
  private Integer productQuantity;
  private Integer direction;
  private Integer requesterEmployeeId;
  private Integer supervisorId;
  private Integer serpaSequenceId;
  @JsonFormat(shape = JsonFormat.Shape.NUMBER_FLOAT)
  private Timestamp createdAt;
  private String sessionId;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false)
  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  @Basic
  @Column(name = "serpa_cost_center_id")
  public Integer getSerpaCostCenterId() {
    return serpaCostCenterId;
  }

  public void setSerpaCostCenterId(Integer serpaCostCenterId) {
    this.serpaCostCenterId = serpaCostCenterId;
  }

  @Basic
  @Column(name = "serpa_product_id", nullable = false)
  public Integer getSerpaProductId() {
    return serpaProductId;
  }

  public void setSerpaProductId(Integer serpaProductId) {
    this.serpaProductId = serpaProductId;
  }

  @Basic
  @Column(name = "product_quantity", nullable = false)
  public Integer getProductQuantity() {
    return productQuantity;
  }

  public void setProductQuantity(Integer productQuantity) {
    this.productQuantity = productQuantity;
  }

  @Basic
  @Column(name = "direction", nullable = false)
  public Integer getDirection() {
    return direction;
  }

  public void setDirection(Integer direction) {
    this.direction = direction;
  }

  @Basic
  @Column(name = "requester_employee_id", nullable = false)
  public Integer getRequesterEmployeeId() {
    return requesterEmployeeId;
  }

  public void setRequesterEmployeeId(Integer requesterEmployeeId) {
    this.requesterEmployeeId = requesterEmployeeId;
  }

  @Basic
  @Column(name = "supervisor_id", nullable = false)
  public Integer getSupervisorId() {
    return supervisorId;
  }

  public void setSupervisorId(Integer supervisorId) {
    this.supervisorId = supervisorId;
  }

  @Basic
  @Column(name = "serpa_sequence_id", nullable = false)
  public Integer getSerpaSequenceId() {
    return serpaSequenceId;
  }

  public void setSerpaSequenceId(Integer serpaSequenceId) {
    this.serpaSequenceId = serpaSequenceId;
  }

  @Basic
  @CreationTimestamp
  @Column(name = "created_at", nullable = false, updatable = false)
  public Timestamp getCreatedAt() {
    return createdAt;
  }

  public void setCreatedAt(Timestamp createdAt) {
    this.createdAt = createdAt;
  }

  @Basic
  @Column(name = "session_id", nullable = false)
  public String getSessionId() {
    return sessionId;
  }

  public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    DeliverynotesEntity that = (DeliverynotesEntity) o;
    return Objects.equals(id, that.id) &&
        Objects.equals(serpaCostCenterId, that.serpaCostCenterId) &&
        Objects.equals(serpaProductId, that.serpaProductId) &&
        Objects.equals(productQuantity, that.productQuantity) &&
        Objects.equals(direction, that.direction) &&
        Objects.equals(requesterEmployeeId, that.requesterEmployeeId) &&
        Objects.equals(supervisorId, that.supervisorId) &&
        Objects.equals(serpaSequenceId, that.serpaSequenceId) &&
        Objects.equals(createdAt, that.createdAt) &&
        Objects.equals(sessionId, that.sessionId);
  }

  @Override
  public int hashCode() {

    return Objects.hash(id, serpaCostCenterId, serpaProductId, productQuantity, direction, requesterEmployeeId, supervisorId, serpaSequenceId, createdAt, sessionId);
  }

}

这是我在后端 2 中的模型

package com.irm.api.automata.response;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.sql.Timestamp;

public class AutomataDeliveryNoteModel {
  private Integer id;
  private Integer serpaCostCenterId;
  private Integer serpaProductId;
  private Integer productQuantity;
  private Integer direction;
  private Integer requesterEmployeeId;
  private Integer supervisorId;
  private Integer serpaSequenceId;
  @JsonFormat(shape = JsonFormat.Shape.NUMBER_FLOAT)
  private Timestamp createdAt;
  private String sessionId;

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public Integer getSerpaCostCenterId() {
    return serpaCostCenterId;
  }

  public void setSerpaCostCenterId(Integer serpaCostCenterId) {
    this.serpaCostCenterId = serpaCostCenterId;
  }

  public Integer getSerpaProductId() {
    return serpaProductId;
  }

  public void setSerpaProductId(Integer serpaProductId) {
    this.serpaProductId = serpaProductId;
  }

  public Integer getProductQuantity() {
    return productQuantity;
  }

  public void setProductQuantity(Integer productQuantity) {
    this.productQuantity = productQuantity;
  }

  public Integer getDirection() {
    return direction;
  }

  public void setDirection(Integer direction) {
    this.direction = direction;
  }

  public Integer getRequesterEmployeeId() {
    return requesterEmployeeId;
  }

  public void setRequesterEmployeeId(Integer requesterEmployeeId) {
    this.requesterEmployeeId = requesterEmployeeId;
  }

  public Integer getSupervisorId() {
    return supervisorId;
  }

  public void setSupervisorId(Integer supervisorId) {
    this.supervisorId = supervisorId;
  }

  public Integer getSerpaSequenceId() {
    return serpaSequenceId;
  }

  public void setSerpaSequenceId(Integer serpaSequenceId) {
    this.serpaSequenceId = serpaSequenceId;
  }

  public Timestamp getCreatedAt() {
    return createdAt;
  }

  public void setCreatedAt(Timestamp createdAt) {
    this.createdAt = createdAt;
  }

  public String getSessionId() {
    return sessionId;
  }

  public void setSessionId(String sessionId) {
    this.sessionId = sessionId;
  }
}

希望有人能给我一些提示,我不知道。我尝试了很多转换等方法

deliverynote entityclass中,你可以定义如下时间戳并尝试:

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSS")
private Timestamp createdAt;

我解决了这个问题。 问题出自 retrofit.builder

 Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").create(); //this line was missing
    return new Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

因为我使用默认的 GsonConverter,它创建了格式化的 json 时间戳到 "useless" 时间格式。现在我设置它并且它完美运行。