Parcourir la source

提交全图监控

chenxiaofei il y a 1 mois
Parent
commit
ec6ca760b5

+ 59 - 5
sckw-modules-api/sckw-transport-api/src/main/java/com/sckw/transport/api/feign/VehicleTraceFeignConfig.java

@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import feign.Logger;
 import feign.Request;
+import feign.Response;
 import feign.Retryer;
 import feign.codec.Decoder;
 import feign.codec.ErrorDecoder;
@@ -16,7 +17,11 @@ import org.springframework.cloud.openfeign.support.SpringDecoder;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.util.StreamUtils;
 
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -65,27 +70,76 @@ public class VehicleTraceFeignConfig {
     @Bean
     public ErrorDecoder errorDecoder() {
         return (methodKey, response) -> {
-            log.error("车辆轨迹服务调用失败, 方法: {}, 状态码: {}", 
-                methodKey, response.status());
-            return new RuntimeException("车辆轨迹服务调用失败: " + response.reason());
+            String responseBody = "";
+            try {
+                if (response.body() != null) {
+                    responseBody = new String(StreamUtils.copyToByteArray(response.body().asInputStream()), StandardCharsets.UTF_8);
+                }
+            } catch (IOException e) {
+                log.warn("读取响应体失败", e);
+            }
+            log.error("车辆轨迹服务调用失败, 方法: {}, 状态码: {}, 响应体: {}", 
+                methodKey, response.status(), responseBody);
+            return new RuntimeException("车辆轨迹服务调用失败: " + response.reason() + ", 响应: " + responseBody);
         };
     }
 
     /**
      * 自定义 Feign 解码器,支持 Java 8 时间类型(LocalDateTime 等)
+     * 支持 ISO 8601 格式:2025-12-05T00:00:00.000+00:00
      */
     @Bean
     public Decoder feignDecoder() {
         ObjectMapper objectMapper = new ObjectMapper();
-        // 注册 Java 8 时间模块
+        // 注册 Java 8 时间模块(自动支持 ISO 8601 格式)
         objectMapper.registerModule(new JavaTimeModule());
+        // 禁用将日期写为时间戳(使用 ISO 8601 字符串格式)
+        objectMapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
         // 忽略未知属性,避免外部服务返回多余字段导致解析失败
         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         // 允许空对象
         objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
+        // 允许单值作为数组
+        objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+        // 允许空值
+        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
         
         MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(objectMapper);
         ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(converter);
-        return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
+        
+        // 包装解码器,添加错误日志
+        Decoder defaultDecoder = new ResponseEntityDecoder(new SpringDecoder(objectFactory));
+        return new Decoder() {
+            @Override
+            public Object decode(Response response, Type type) throws IOException {
+                // 先保存响应体内容,以便在解码失败时记录日志
+                String responseBody = "";
+                byte[] bodyBytes = null;
+                if (response.body() != null) {
+                    try {
+                        bodyBytes = StreamUtils.copyToByteArray(response.body().asInputStream());
+                        responseBody = new String(bodyBytes, StandardCharsets.UTF_8);
+                    } catch (IOException ex) {
+                        log.warn("读取响应体失败", ex);
+                    }
+                }
+                
+                try {
+                    // 使用保存的响应体重新构建 Response,因为流已经被读取
+                    if (bodyBytes != null) {
+                        Response rebuiltResponse = response.toBuilder()
+                            .body(bodyBytes)
+                            .build();
+                        return defaultDecoder.decode(rebuiltResponse, type);
+                    } else {
+                        return defaultDecoder.decode(response, type);
+                    }
+                } catch (Exception e) {
+                    log.error("Feign 解码失败, 类型: {}, 状态码: {}, 响应体: {}, 错误: {}", 
+                        type, response.status(), responseBody, e.getMessage(), e);
+                    throw e;
+                }
+            }
+        };
     }
 }

+ 59 - 0
sckw-modules-api/sckw-transport-api/src/main/java/com/sckw/transport/api/model/dto/LocalDateTimeDeserializer.java

@@ -0,0 +1,59 @@
+package com.sckw.transport.api.model.dto;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * 自定义 LocalDateTime 反序列化器
+ * 支持解析带时区的 ISO 8601 格式(如:2025-12-05T00:00:00.000+00:00)
+ * 自动转换为 LocalDateTime(忽略时区信息)
+ */
+@Slf4j
+public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
+
+    private static final long serialVersionUID = 1L;
+
+    public LocalDateTimeDeserializer() {
+        super(LocalDateTime.class);
+    }
+
+    @Override
+    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+        String dateTimeStr = p.getText();
+        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
+            return null;
+        }
+
+        dateTimeStr = dateTimeStr.trim();
+
+        // 优先尝试解析带时区的格式(如:2025-12-05T00:00:00.000+00:00)
+        // OffsetDateTime 可以解析带时区偏移的 ISO 8601 格式
+        try {
+            OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateTimeStr);
+            return offsetDateTime.toLocalDateTime();
+        } catch (DateTimeParseException e) {
+            // 如果解析失败,尝试不带时区的格式
+            try {
+                // 尝试解析不带时区的 ISO 格式(如:2025-12-05T00:00:00 或 2025-12-05T00:00:00.000)
+                return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+            } catch (DateTimeParseException e2) {
+                // 尝试其他常见格式
+                try {
+                    return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+                } catch (DateTimeParseException e3) {
+                    log.error("所有时间格式解析失败: {}", dateTimeStr, e3);
+                    throw new IOException("无法解析时间字符串: " + dateTimeStr, e3);
+                }
+            }
+        }
+    }
+}
+

+ 4 - 2
sckw-modules-api/sckw-transport-api/src/main/java/com/sckw/transport/api/model/dto/VehicleReturnData.java

@@ -1,6 +1,6 @@
 package com.sckw.transport.api.model.dto;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import lombok.Data;
 
 import java.io.Serial;
@@ -20,8 +20,10 @@ public class VehicleReturnData implements Serializable {
 
     /**
      * 时间戳
+     * IoT平台返回ISO 8601格式:2025-12-05T00:00:00.000+00:00
+     * 使用自定义反序列化器支持带时区的格式
      */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
     private LocalDateTime ts;
 
     /**

+ 26 - 0
sckw-modules-api/sckw-transport-api/src/main/java/com/sckw/transport/api/model/param/AddLogisticOrderParam.java

@@ -38,6 +38,32 @@ public class AddLogisticOrderParam implements Serializable {
      */
     @NotBlank(message = "订单编号不能为空")
     private String tradeOrderNo;
+
+    /**
+     * 非托运方单位
+     */
+    @NotBlank(message = "非托运方单位名称不能为空")
+    private String nonConsignCompany;
+    /**
+     * 非托运方单位id
+     */
+    @NotBlank(message = "非托运方单位id不能为空")
+    private Long nonConsignCompanyId;
+    /**
+     * 非托运方联系电话
+     */
+    @NotBlank(message = "非托运方联系电话不能为空")
+    private String nonConsignContactPhone;
+    /**
+     * 非托运方联系人
+     */
+    @NotBlank(message = "非托运方联系人不能为空")
+    private String nonConsignContacts;
+    /**
+     * 非托运方联系人id
+     */
+    @NotBlank(message = "非托运方联系人id不能为空")
+    private Long nonConsignContactsId;
     /**
      * 托运单位
      */

+ 6 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/dubbo/TransportServiceImpl.java

@@ -1262,6 +1262,12 @@ public class TransportServiceImpl implements TransportRemoteService {
         addLogisticOrderDTO.setUserId(param.getUserId());
         addLogisticOrderDTO.setTradeOrderId(param.getTradeOrderId());
         addLogisticOrderDTO.setTradeOrderNo(param.getTradeOrderNo());
+        addLogisticOrderDTO.setNonConsignCompany(param.getNonConsignCompany());
+        addLogisticOrderDTO.setNonConsignCompanyId(param.getNonConsignCompanyId());
+        addLogisticOrderDTO.setNonConsignContactPhone(param.getNonConsignContactPhone());
+        addLogisticOrderDTO.setNonConsignContacts(param.getNonConsignContacts());
+        addLogisticOrderDTO.setNonConsignContactsId(param.getNonConsignContactsId());
+
         addLogisticOrderDTO.setConsignCompany(param.getConsignCompany());
         addLogisticOrderDTO.setConsignCompanyId(param.getConsignCompanyId());
         addLogisticOrderDTO.setConsignContactPhone(param.getConsignContactPhone());

+ 26 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/dto/AddLogisticOrderDTO.java

@@ -36,6 +36,32 @@ public class AddLogisticOrderDTO implements Serializable {
      */
     @NotBlank(message = "订单编号不能为空")
     private String tradeOrderNo;
+    /**
+     * 非托运方单位
+     */
+    @NotBlank(message = "非托运方单位名称不能为空")
+    private String nonConsignCompany;
+    /**
+     * 非托运方单位id
+     */
+    @NotBlank(message = "非托运方单位id不能为空")
+    private Long nonConsignCompanyId;
+    /**
+     * 非托运方联系电话
+     */
+    @NotBlank(message = "非托运方联系电话不能为空")
+    private String nonConsignContactPhone;
+    /**
+     * 非托运方联系人
+     */
+    @NotBlank(message = "非托运方联系人不能为空")
+    private String nonConsignContacts;
+    /**
+     * 非托运方联系人id
+     */
+    @NotBlank(message = "非托运方联系人id不能为空")
+    private Long nonConsignContactsId;
+
     /**
      * 托运单位
      */

+ 11 - 8
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/VehiclesTrajectoryReq.java

@@ -1,20 +1,21 @@
 package com.sckw.transport.model.param;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.Valid;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
-import java.time.LocalDateTime;
-import java.util.Date;
+import java.io.Serial;
+import java.io.Serializable;
 
 /**
  * @author PC
  */
 @Data
-@Valid
-public class VehiclesTrajectoryReq {
+public class VehiclesTrajectoryReq implements Serializable {
+    
+    @Serial
+    private static final long serialVersionUID = 1L;
     private String ts;
     /**
      * 手机号
@@ -47,7 +48,7 @@ public class VehiclesTrajectoryReq {
      * 车速(km/h)
      */
     @Schema(description = "车速(km/h)")
-    @NotBlank(message = "车速speed不能为空")
+    @NotNull(message = "车速speed不能为空")
     private Float speed;
 
     /**
@@ -118,8 +119,10 @@ public class VehiclesTrajectoryReq {
     private VehicleDataVO vehicleDataVO;
 
     @Data
-    @Valid
-    public static class VehicleDataVO {
+    public static class VehicleDataVO implements Serializable {
+        
+        @Serial
+        private static final long serialVersionUID = 1L;
 
         /**
          * 车牌

+ 22 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtAcceptCarriageOrderService.java

@@ -3332,6 +3332,28 @@ public class KwtAcceptCarriageOrderService {
         unit.setUpdateBy(orderDTO.getUserId());
         unit.setUpdateTime(new Date());
         savelogOrderUnitList.add(unit);
+        KwtLogisticsOrderUnit notifyUnit = new KwtLogisticsOrderUnit();
+
+        notifyUnit.setId(new IdWorker(NumberConstant.THREE).nextId());
+        notifyUnit.setLOrderId(lOrderId);
+        notifyUnit.setUnitType(NumberConstant.THREE);
+        notifyUnit.setEntId(orderDTO.getNonConsignCompanyId());
+        EntCacheResDto ent2 = entMap.get(orderDTO.getNonConsignCompanyId());
+        if (Objects.isNull(ent2)) {
+            throw new BusinessException("企业:" + orderDTO.getNonConsignCompany() + "的一级企业信息不存在!");
+        }
+        notifyUnit.setContactsId(orderDTO.getNonConsignContactsId());
+        notifyUnit.setTopEntId(ent2.getId());
+        notifyUnit.setFirmName(orderDTO.getNonConsignCompany());
+        notifyUnit.setContacts(orderDTO.getNonConsignContacts());
+        notifyUnit.setPhone(orderDTO.getNonConsignContactPhone());
+//        unit.setRemark(orderDTO.getRemark());
+        notifyUnit.setStatus(NumberConstant.ZERO);
+        notifyUnit.setCreateBy(orderDTO.getUserId());
+        notifyUnit.setCreateTime(new Date());
+        notifyUnit.setUpdateBy(orderDTO.getUserId());
+        notifyUnit.setUpdateTime(new Date());
+        savelogOrderUnitList.add(notifyUnit);
     }
 
     private static void setLogisticContractInfo(AddLogisticOrderDTO orderDTO,LogisticData x, Long lOrderId, List<KwtLogisticsOrderContract> saveContractList) {

+ 1 - 1
sckw-modules/sckw-transport/src/main/resources/bootstrap.yml

@@ -19,7 +19,7 @@ mybatis-plus:
 logging:
   level:
     root: info
-    com.sckw.payment: debug
+    com.sckw.transport: debug
 
 # SpringDoc OpenAPI 配置
 springdoc: