This commit is contained in:
2026-08-08 11:07:23 +08:00
parent 2644718b5f
commit 54893aeb6b
2 changed files with 1975 additions and 7 deletions
@@ -12,6 +12,9 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -27,6 +30,7 @@ import java.util.Set;
/** 将墨家固定 AppKey + JSON/Base64 协议转换为统一单箱测量命令。 */
@Service
public class MojiaMeasurementOpenApiService {
private static final Logger log = LoggerFactory.getLogger(MojiaMeasurementOpenApiService.class);
static final String CALLBACK_PATH = "/openapi/v1/inbound-measurements";
private static final String JPEG_PREFIX = "data:image/jpeg;base64,";
private static final long MAX_IMAGE_BYTES = 5L * 1024 * 1024;
@@ -47,13 +51,34 @@ public class MojiaMeasurementOpenApiService {
}
public CartonMeasurementResult receive(MeasurementRequestHeaders headers, String rawJson) {
AuthenticatedMeasurementApp app = authenticator.authenticate(
"POST", CALLBACK_PATH, headers, rawJson, false);
UploadRequest request = parseAndValidate(rawJson);
MultipartFile image = decodeJpeg(request.picture());
return cartonMeasurements.upsert(app.tenantId(), app.subjectId(), new CartonMeasurementCommand(
request.boxCode(), request.length(), request.width(), request.height(), request.weight(),
request.machineNo(), request.measuredAt() == null ? LocalDateTime.now() : request.measuredAt(), image));
UploadRequest request = null;
try {
AuthenticatedMeasurementApp app = authenticator.authenticate(
"POST", CALLBACK_PATH, headers, rawJson, false);
request = parseAndValidate(rawJson);
MultipartFile image = decodeJpeg(request.picture());
CartonMeasurementResult result = cartonMeasurements.upsert(
app.tenantId(), app.subjectId(), new CartonMeasurementCommand(
request.boxCode(), request.length(), request.width(), request.height(), request.weight(),
request.machineNo(), request.measuredAt() == null ? LocalDateTime.now() : request.measuredAt(),
image));
log.info("MOJIA_MEASUREMENT accepted requestId={} traceId={} boxCode={} machineNo={} "
+ "lengthCm={} widthCm={} heightCm={} weightKg={} imageBytes={} measurementId={} "
+ "itemId={} created={}",
correlation("requestId"), correlation("traceId"), safe(request.boxCode()),
safe(request.machineNo()), request.length(), request.width(), request.height(), request.weight(),
image.getSize(), result.measurementId(), result.itemId(), result.created());
return result;
} catch (RuntimeException exception) {
String code = exception instanceof BizException biz ? biz.getResultCode().code() : "S0500";
log.warn("MOJIA_MEASUREMENT rejected requestId={} traceId={} boxCode={} machineNo={} "
+ "payloadChars={} code={} reason={}",
correlation("requestId"), correlation("traceId"),
request == null ? "unparsed" : safe(request.boxCode()),
request == null ? "unparsed" : safe(request.machineNo()),
rawJson == null ? 0 : rawJson.length(), code, safe(exception.getMessage()));
throw exception;
}
}
private UploadRequest parseAndValidate(String rawJson) {
@@ -93,6 +118,17 @@ public class MojiaMeasurementOpenApiService {
return new InMemoryMultipartFile(bytes);
}
private String correlation(String name) {
String value = MDC.get(name);
return value == null || value.isBlank() ? "missing" : safe(value);
}
private String safe(String value) {
if (value == null) return "null";
String normalized = value.replace('\r', '_').replace('\n', '_');
return normalized.length() <= 160 ? normalized : normalized.substring(0, 160);
}
private record InMemoryMultipartFile(byte[] content) implements MultipartFile {
@Override public String getName() { return "image"; }
@Override public String getOriginalFilename() { return "mojia-measurement.jpg"; }
File diff suppressed because it is too large Load Diff