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 entity
class中,你可以定义如下时间戳并尝试:
@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" 时间格式。现在我设置它并且它完美运行。
我正在开发两个相互通信的 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 entity
class中,你可以定义如下时间戳并尝试:
@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" 时间格式。现在我设置它并且它完美运行。