优化
This commit is contained in:
+13
-6
@@ -10,12 +10,19 @@ import java.net.http.HttpClient;
|
||||
public class LastlegRestClientFactory {
|
||||
public RestClient build(RestClient.Builder builder, String baseUrl,
|
||||
LastlegRestClientProperties.ClientTimeouts timeouts) {
|
||||
HttpClient httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(timeouts.getConnectTimeout())
|
||||
.build();
|
||||
JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient);
|
||||
requestFactory.setReadTimeout(timeouts.getReadTimeout());
|
||||
JdkClientHttpRequestFactory requestFactory = requestFactory(timeouts);
|
||||
return builder.requestFactory(requestFactory).baseUrl(baseUrl).build();
|
||||
}
|
||||
}
|
||||
|
||||
HttpClient httpClient(LastlegRestClientProperties.ClientTimeouts timeouts) {
|
||||
return HttpClient.newBuilder()
|
||||
.connectTimeout(timeouts.getConnectTimeout())
|
||||
.build();
|
||||
}
|
||||
|
||||
JdkClientHttpRequestFactory requestFactory(LastlegRestClientProperties.ClientTimeouts timeouts) {
|
||||
JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient(timeouts));
|
||||
requestFactory.setReadTimeout(timeouts.getReadTimeout());
|
||||
return requestFactory;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -50,8 +50,14 @@ public class LastlegOrderController {
|
||||
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
|
||||
@RequestBody EventEnvelope event) {
|
||||
tokenGuard.verify(token);
|
||||
int consumed = EventTypes.FIRST_LEG_CONTAINER_SHIPPING_NODE_RECORDED.equals(event.eventType())
|
||||
? shippingNodeConsumer.consume(event) : consumer.consume(event);
|
||||
int consumed;
|
||||
if (EventTypes.FIRST_LEG_CONTAINER_SHIPPING_NODE_RECORDED.equals(event.eventType())) {
|
||||
consumed = shippingNodeConsumer.consume(event);
|
||||
} else if (EventTypes.FIRST_LEG_LOADING_PLAN_COMPLETED.equals(event.eventType())) {
|
||||
consumed = consumer.consume(event);
|
||||
} else {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Lastleg 不消费该事件类型: " + event.eventType());
|
||||
}
|
||||
return ApiResponse.success(consumed);
|
||||
}
|
||||
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.adapter.in.web;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.VehicleApplicationService;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.VehicleApplicationService.VehicleFailure;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.model.VehicleModels;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/last-leg/master-data/vehicles")
|
||||
@Tag(name = "Vehicle master data / 车辆主数据")
|
||||
public class PlatformVehicleController {
|
||||
private final VehicleApplicationService service;
|
||||
|
||||
public PlatformVehicleController(VehicleApplicationService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_LIST + "')")
|
||||
@Operation(summary = "Page vehicle master data", description = "Required authority: platform:overseas-master-data:vehicle:list")
|
||||
public ApiResponse<PageResult<VehicleModels.Response>> page(@Valid VehicleModels.Query query) {
|
||||
return execute(() -> ApiResponse.success(service.page(query)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_LIST + "')")
|
||||
@Operation(summary = "Get vehicle master data detail", description = "Required authority: platform:overseas-master-data:vehicle:list; excludes delivery fulfillment history")
|
||||
public ApiResponse<VehicleModels.Response> detail(@PathVariable long id) {
|
||||
return execute(() -> ApiResponse.success(service.detail(id)));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_CREATE + "')")
|
||||
public ApiResponse<VehicleModels.Response> create(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Valid @RequestBody VehicleModels.Create request) {
|
||||
return execute(() -> ApiResponse.success(service.create(operator(user), request)));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_EDIT + "')")
|
||||
public ApiResponse<VehicleModels.Response> update(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody VehicleModels.Update request) {
|
||||
return execute(() -> ApiResponse.success(service.update(id, operator(user), request)));
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}/status")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_STATUS + "')")
|
||||
public ApiResponse<VehicleModels.Response> status(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@PathVariable long id,
|
||||
@Valid @RequestBody VehicleModels.ChangeStatus request) {
|
||||
return execute(() -> ApiResponse.success(service.changeStatus(id, operator(user), request)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/export", produces = "text/csv")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_EXPORT + "')")
|
||||
public ResponseEntity<byte[]> export(@Valid VehicleModels.Query query) {
|
||||
return execute(() -> ResponseEntity.ok().contentType(new MediaType("text", "csv", StandardCharsets.UTF_8))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=vehicles.csv").body(service.exportCsv(query)));
|
||||
}
|
||||
|
||||
private String operator(AuthenticatedUser user) {
|
||||
if (user == null) return "UNKNOWN";
|
||||
return user.userId() == null ? user.username() : String.valueOf(user.userId());
|
||||
}
|
||||
|
||||
private <T> T execute(Supplier<T> action) {
|
||||
try {
|
||||
return action.get();
|
||||
} catch (VehicleFailure failure) {
|
||||
HttpStatus status = switch (failure.kind()) {
|
||||
case BAD_REQUEST -> HttpStatus.BAD_REQUEST;
|
||||
case NOT_FOUND -> HttpStatus.NOT_FOUND;
|
||||
case CONFLICT -> HttpStatus.CONFLICT;
|
||||
};
|
||||
throw new ResponseStatusException(status, failure.getMessage(), failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -1,13 +1,12 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.mapper;
|
||||
package com.baiyue.lastleg.masterdata.vehicle.adapter.out.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.entity.Vehicle;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
@Mapper
|
||||
public interface VehicleMapper extends BaseMapper<Vehicle> {
|
||||
public interface VehicleMapper extends BaseMapper<VehicleRecord> {
|
||||
@Select("SELECT * FROM ll_vehicle WHERE id=#{id} LIMIT 1 FOR UPDATE")
|
||||
Vehicle lockById(@Param("id") long id);
|
||||
VehicleRecord lockById(@Param("id") long id);
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.adapter.out.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public class VehiclePersistenceAdapter implements VehicleRepository {
|
||||
private final VehicleMapper vehicles;
|
||||
|
||||
public VehiclePersistenceAdapter(VehicleMapper vehicles) {
|
||||
this.vehicles = vehicles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageSlice page(SearchCriteria criteria) {
|
||||
Page<VehicleRecord> page = vehicles.selectPage(Page.of(criteria.page(), criteria.size()), wrapper(criteria));
|
||||
return new PageSlice(page.getRecords().stream().map(this::snapshot).toList(), page.getCurrent(),
|
||||
page.getSize(), page.getTotal(), page.getPages());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VehicleSnapshot> list(SearchCriteria criteria) {
|
||||
return vehicles.selectList(wrapper(criteria)).stream().map(this::snapshot).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VehicleSnapshot> findById(long id) {
|
||||
return Optional.ofNullable(vehicles.selectById(id)).map(this::snapshot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VehicleSnapshot> lockById(long id) {
|
||||
return Optional.ofNullable(vehicles.lockById(id)).map(this::snapshot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long create(NewVehicle vehicle) {
|
||||
VehicleRecord record = new VehicleRecord();
|
||||
record.setId(IdWorker.getId());
|
||||
record.setPlateNumber(vehicle.plateNumber());
|
||||
record.setModel(vehicle.model());
|
||||
record.setFuelConsumptionPer100Km(vehicle.fuelConsumptionPer100Km());
|
||||
record.setMileageKm(vehicle.mileageKm());
|
||||
record.setDriverOrDispatchCompany(vehicle.driverOrDispatchCompany());
|
||||
record.setPhone(vehicle.phone());
|
||||
record.setRegion(vehicle.region());
|
||||
record.setOwnership(vehicle.ownership());
|
||||
record.setStatus(vehicle.status());
|
||||
record.setRemark(vehicle.remark());
|
||||
record.setRecordVersion(0L);
|
||||
record.setCreatedBy(vehicle.operator());
|
||||
record.setUpdatedBy(vehicle.operator());
|
||||
record.setCreatedAt(vehicle.createdAt());
|
||||
record.setUpdatedAt(vehicle.createdAt());
|
||||
try {
|
||||
vehicles.insert(record);
|
||||
} catch (DuplicateKeyException exception) {
|
||||
throw new DuplicatePlateException(exception);
|
||||
}
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(long id, long expectedVersion, VehicleChanges changes) {
|
||||
try {
|
||||
return vehicles.update(null, new LambdaUpdateWrapper<VehicleRecord>()
|
||||
.eq(VehicleRecord::getId, id).eq(VehicleRecord::getRecordVersion, expectedVersion)
|
||||
.set(VehicleRecord::getPlateNumber, changes.plateNumber())
|
||||
.set(VehicleRecord::getModel, changes.model())
|
||||
.set(VehicleRecord::getFuelConsumptionPer100Km, changes.fuelConsumptionPer100Km())
|
||||
.set(VehicleRecord::getMileageKm, changes.mileageKm())
|
||||
.set(VehicleRecord::getDriverOrDispatchCompany, changes.driverOrDispatchCompany())
|
||||
.set(VehicleRecord::getPhone, changes.phone()).set(VehicleRecord::getRegion, changes.region())
|
||||
.set(VehicleRecord::getOwnership, changes.ownership()).set(VehicleRecord::getRemark, changes.remark())
|
||||
.set(VehicleRecord::getUpdatedBy, changes.operator()).set(VehicleRecord::getUpdatedAt, changes.updatedAt())
|
||||
.setSql("record_version = record_version + 1")) == 1;
|
||||
} catch (DuplicateKeyException exception) {
|
||||
throw new DuplicatePlateException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateStatus(long id, long expectedVersion, String status, String operator,
|
||||
java.time.LocalDateTime updatedAt) {
|
||||
return vehicles.update(null, new LambdaUpdateWrapper<VehicleRecord>()
|
||||
.eq(VehicleRecord::getId, id).eq(VehicleRecord::getRecordVersion, expectedVersion)
|
||||
.set(VehicleRecord::getStatus, status).set(VehicleRecord::getUpdatedBy, operator)
|
||||
.set(VehicleRecord::getUpdatedAt, updatedAt).setSql("record_version = record_version + 1")) == 1;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<VehicleRecord> wrapper(SearchCriteria criteria) {
|
||||
return new LambdaQueryWrapper<VehicleRecord>()
|
||||
.and(StringUtils.hasText(criteria.keyword()), wrapper -> wrapper.like(VehicleRecord::getPlateNumber, criteria.keyword())
|
||||
.or().like(VehicleRecord::getModel, criteria.keyword())
|
||||
.or().like(VehicleRecord::getDriverOrDispatchCompany, criteria.keyword()))
|
||||
.eq(criteria.ownership() != null, VehicleRecord::getOwnership, criteria.ownership())
|
||||
.eq(criteria.region() != null, VehicleRecord::getRegion, criteria.region())
|
||||
.eq(criteria.status() != null, VehicleRecord::getStatus, criteria.status())
|
||||
.orderByDesc(VehicleRecord::getUpdatedAt).orderByDesc(VehicleRecord::getId);
|
||||
}
|
||||
|
||||
private VehicleSnapshot snapshot(VehicleRecord value) {
|
||||
return new VehicleSnapshot(value.getId(), value.getPlateNumber(), value.getModel(),
|
||||
value.getFuelConsumptionPer100Km(), value.getMileageKm(), value.getDriverOrDispatchCompany(), value.getPhone(),
|
||||
value.getRegion(), value.getOwnership(), value.getStatus(), value.getRemark(), version(value.getRecordVersion()),
|
||||
value.getUpdatedBy(), value.getUpdatedAt());
|
||||
}
|
||||
|
||||
private static long version(Long value) {
|
||||
return value == null ? 0L : value;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.entity;
|
||||
package com.baiyue.lastleg.masterdata.vehicle.adapter.out.persistence;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@@ -10,7 +10,7 @@ import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("ll_vehicle")
|
||||
public class Vehicle {
|
||||
public class VehicleRecord {
|
||||
@TableId(type = IdType.INPUT) private Long id;
|
||||
private String plateNumber;
|
||||
private String model;
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.application;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.model.VehicleModels;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository.DuplicatePlateException;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository.NewVehicle;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository.SearchCriteria;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository.VehicleChanges;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.application.port.out.VehicleRepository.VehicleSnapshot;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class VehicleApplicationService {
|
||||
private static final Set<String> OWNERSHIPS = Set.of("OWNED", "DISPATCHED");
|
||||
private static final Set<String> REGIONS = Set.of("DOMESTIC", "OVERSEAS");
|
||||
private static final Set<String> STATUSES = Set.of("IN_SERVICE", "DISPATCHED", "MAINTENANCE", "INACTIVE", "RETURNED");
|
||||
|
||||
private final VehicleRepository vehicles;
|
||||
|
||||
public VehicleApplicationService(VehicleRepository vehicles) {
|
||||
this.vehicles = vehicles;
|
||||
}
|
||||
|
||||
public PageResult<VehicleModels.Response> page(VehicleModels.Query query) {
|
||||
var page = vehicles.page(criteria(query));
|
||||
return new PageResult<>(page.records().stream().map(this::response).toList(), page.page(),
|
||||
page.size(), page.total(), page.pages());
|
||||
}
|
||||
|
||||
public VehicleModels.Response detail(long id) {
|
||||
return response(required(id));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public VehicleModels.Response create(String operator, VehicleModels.Create request) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
long id;
|
||||
try {
|
||||
id = vehicles.create(new NewVehicle(
|
||||
requiredText(request.plateNumber(), "车牌号").toUpperCase(Locale.ROOT),
|
||||
requiredText(request.model(), "车型"), request.fuelConsumptionPer100Km(), request.mileageKm(),
|
||||
trim(request.driverOrDispatchCompany()), trim(request.phone()), region(request.region()),
|
||||
ownership(request.ownership()), status(request.status()), trim(request.remark()), operator, now));
|
||||
} catch (DuplicatePlateException exception) {
|
||||
throw conflict("车牌号已存在");
|
||||
}
|
||||
return detail(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public VehicleModels.Response update(long id, String operator, VehicleModels.Update request) {
|
||||
VehicleSnapshot current = locked(id);
|
||||
requireVersion(current, request.recordVersion());
|
||||
if (request.mileageKm() < current.mileageKm()) throw badRequest("当前公里码不能小于已有公里码");
|
||||
boolean updated;
|
||||
try {
|
||||
updated = vehicles.update(id, request.recordVersion(), new VehicleChanges(
|
||||
requiredText(request.plateNumber(), "车牌号").toUpperCase(Locale.ROOT),
|
||||
requiredText(request.model(), "车型"), request.fuelConsumptionPer100Km(), request.mileageKm(),
|
||||
trim(request.driverOrDispatchCompany()), trim(request.phone()), region(request.region()),
|
||||
ownership(request.ownership()), trim(request.remark()), operator, LocalDateTime.now()));
|
||||
} catch (DuplicatePlateException exception) {
|
||||
throw conflict("车牌号已存在");
|
||||
}
|
||||
if (!updated) throw conflict("车辆档案已被其他操作修改,请刷新后重试");
|
||||
return detail(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public VehicleModels.Response changeStatus(long id, String operator, VehicleModels.ChangeStatus request) {
|
||||
VehicleSnapshot current = locked(id);
|
||||
requireVersion(current, request.recordVersion());
|
||||
String status = status(request.status());
|
||||
if (status.equals(current.status())) return response(current);
|
||||
boolean updated = vehicles.updateStatus(id, request.recordVersion(), status, operator, LocalDateTime.now());
|
||||
if (!updated) throw conflict("车辆档案已被其他操作修改,请刷新后重试");
|
||||
return detail(id);
|
||||
}
|
||||
|
||||
public byte[] exportCsv(VehicleModels.Query query) {
|
||||
var rows = vehicles.list(criteria(query)).stream().map(this::response).toList();
|
||||
StringBuilder csv = new StringBuilder("\uFEFF车辆ID,车牌号,车型,油耗(L/100km),当前公里码(km),司机或外派单位,联系电话,区域,车辆归属,状态,更新时间\r\n");
|
||||
for (var row : rows) csv.append(row.id()).append(',').append(cell(row.plateNumber())).append(',')
|
||||
.append(cell(row.model())).append(',').append(row.fuelConsumptionPer100Km()).append(',').append(row.mileageKm()).append(',')
|
||||
.append(cell(row.driverOrDispatchCompany())).append(',').append(cell(row.phone())).append(',')
|
||||
.append(row.region()).append(',').append(row.ownership()).append(',').append(row.status()).append(',')
|
||||
.append(row.updatedAt()).append("\r\n");
|
||||
return csv.toString().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private SearchCriteria criteria(VehicleModels.Query query) {
|
||||
return new SearchCriteria(query.page(), query.size(), trim(query.keyword()),
|
||||
optional(query.ownership(), OWNERSHIPS, "车辆归属"),
|
||||
optional(query.region(), REGIONS, "车辆区域"),
|
||||
optional(query.status(), STATUSES, "车辆状态"));
|
||||
}
|
||||
|
||||
private VehicleSnapshot required(long id) {
|
||||
return vehicles.findById(id).orElseThrow(VehicleApplicationService::notFound);
|
||||
}
|
||||
|
||||
private VehicleSnapshot locked(long id) {
|
||||
return vehicles.lockById(id).orElseThrow(VehicleApplicationService::notFound);
|
||||
}
|
||||
|
||||
private VehicleModels.Response response(VehicleSnapshot value) {
|
||||
return new VehicleModels.Response(String.valueOf(value.id()), value.plateNumber(), value.model(),
|
||||
value.fuelConsumptionPer100Km(), value.mileageKm(), value.driverOrDispatchCompany(), value.phone(),
|
||||
value.region(), value.ownership(), value.status(), value.remark(), value.recordVersion(),
|
||||
value.updatedBy(), value.updatedAt());
|
||||
}
|
||||
|
||||
private void requireVersion(VehicleSnapshot value, long expected) {
|
||||
if (value.recordVersion() != expected) throw conflict("车辆档案已被其他操作修改,请刷新后重试");
|
||||
}
|
||||
|
||||
private static String ownership(String value) { return required(value, OWNERSHIPS, "车辆归属"); }
|
||||
private static String region(String value) { return required(value, REGIONS, "车辆区域"); }
|
||||
private static String status(String value) { return required(value, STATUSES, "车辆状态"); }
|
||||
|
||||
private static String optional(String value, Set<String> allowed, String label) {
|
||||
return StringUtils.hasText(value) ? required(value, allowed, label) : null;
|
||||
}
|
||||
|
||||
private static String required(String value, Set<String> allowed, String label) {
|
||||
if (!StringUtils.hasText(value)) throw badRequest(label + "不能为空");
|
||||
String normalized = value.trim().toUpperCase(Locale.ROOT);
|
||||
if (!allowed.contains(normalized)) throw badRequest(label + "不合法");
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static String requiredText(String value, String label) {
|
||||
if (!StringUtils.hasText(value)) throw badRequest(label + "不能为空");
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
private static String trim(String value) { return StringUtils.hasText(value) ? value.trim() : null; }
|
||||
private static String cell(Object value) { return "\"" + String.valueOf(value == null ? "" : value).replace("\"", "\"\"") + "\""; }
|
||||
private static VehicleFailure notFound() { return new VehicleFailure(FailureKind.NOT_FOUND, "车辆档案不存在"); }
|
||||
private static VehicleFailure badRequest(String message) { return new VehicleFailure(FailureKind.BAD_REQUEST, message); }
|
||||
private static VehicleFailure conflict(String message) { return new VehicleFailure(FailureKind.CONFLICT, message); }
|
||||
|
||||
public enum FailureKind { BAD_REQUEST, NOT_FOUND, CONFLICT }
|
||||
|
||||
public static final class VehicleFailure extends RuntimeException {
|
||||
private final FailureKind kind;
|
||||
|
||||
public VehicleFailure(FailureKind kind, String message) {
|
||||
super(message);
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public FailureKind kind() {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.dto;
|
||||
package com.baiyue.lastleg.masterdata.vehicle.application.model;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.Digits;
|
||||
@@ -11,8 +11,8 @@ import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public final class VehicleDtos {
|
||||
private VehicleDtos() { }
|
||||
public final class VehicleModels {
|
||||
private VehicleModels() { }
|
||||
|
||||
public record Query(@Min(1) Integer page, @Min(1) @Max(200) Integer size,
|
||||
@Size(max = 128) String keyword, String ownership, String region, String status) {
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.application.port.out;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface VehicleRepository {
|
||||
PageSlice page(SearchCriteria criteria);
|
||||
|
||||
List<VehicleSnapshot> list(SearchCriteria criteria);
|
||||
|
||||
Optional<VehicleSnapshot> findById(long id);
|
||||
|
||||
Optional<VehicleSnapshot> lockById(long id);
|
||||
|
||||
long create(NewVehicle vehicle);
|
||||
|
||||
boolean update(long id, long expectedVersion, VehicleChanges changes);
|
||||
|
||||
boolean updateStatus(long id, long expectedVersion, String status, String operator, LocalDateTime updatedAt);
|
||||
|
||||
record SearchCriteria(int page, int size, String keyword, String ownership, String region, String status) { }
|
||||
|
||||
record PageSlice(List<VehicleSnapshot> records, long page, long size, long total, long pages) { }
|
||||
|
||||
record NewVehicle(String plateNumber, String model, BigDecimal fuelConsumptionPer100Km, long mileageKm,
|
||||
String driverOrDispatchCompany, String phone, String region, String ownership, String status,
|
||||
String remark, String operator, LocalDateTime createdAt) { }
|
||||
|
||||
record VehicleChanges(String plateNumber, String model, BigDecimal fuelConsumptionPer100Km, long mileageKm,
|
||||
String driverOrDispatchCompany, String phone, String region, String ownership, String remark,
|
||||
String operator, LocalDateTime updatedAt) { }
|
||||
|
||||
record VehicleSnapshot(long id, String plateNumber, String model, BigDecimal fuelConsumptionPer100Km,
|
||||
long mileageKm, String driverOrDispatchCompany, String phone, String region,
|
||||
String ownership, String status, String remark, long recordVersion,
|
||||
String updatedBy, LocalDateTime updatedAt) { }
|
||||
|
||||
final class DuplicatePlateException extends RuntimeException {
|
||||
public DuplicatePlateException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.controller;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.dto.VehicleDtos;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.service.VehicleService;
|
||||
import com.baiyue.lastleg.security.OverseasPermissions;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/platform/v1/last-leg/master-data/vehicles")
|
||||
@Tag(name = "Vehicle master data / 车辆主数据")
|
||||
public class PlatformVehicleController {
|
||||
@Resource private VehicleService service;
|
||||
|
||||
@GetMapping @PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_LIST + "')")
|
||||
@Operation(summary = "Page vehicle master data", description = "Required authority: platform:overseas-master-data:vehicle:list")
|
||||
public ApiResponse<PageResult<VehicleDtos.Response>> page(@Valid VehicleDtos.Query query) { return ApiResponse.success(service.page(query)); }
|
||||
|
||||
@GetMapping("/{id}") @PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_LIST + "')")
|
||||
@Operation(summary = "Get vehicle master data detail", description = "Required authority: platform:overseas-master-data:vehicle:list; excludes delivery fulfillment history")
|
||||
public ApiResponse<VehicleDtos.Response> detail(@PathVariable long id) { return ApiResponse.success(service.detail(id)); }
|
||||
|
||||
@PostMapping @PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_CREATE + "')")
|
||||
public ApiResponse<VehicleDtos.Response> create(@AuthenticationPrincipal AuthenticatedUser user,
|
||||
@Valid @RequestBody VehicleDtos.Create request) { return ApiResponse.success(service.create(operator(user), request)); }
|
||||
|
||||
@PutMapping("/{id}") @PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_EDIT + "')")
|
||||
public ApiResponse<VehicleDtos.Response> update(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable long id,
|
||||
@Valid @RequestBody VehicleDtos.Update request) { return ApiResponse.success(service.update(id, operator(user), request)); }
|
||||
|
||||
@PatchMapping("/{id}/status") @PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_STATUS + "')")
|
||||
public ApiResponse<VehicleDtos.Response> status(@AuthenticationPrincipal AuthenticatedUser user, @PathVariable long id,
|
||||
@Valid @RequestBody VehicleDtos.ChangeStatus request) { return ApiResponse.success(service.changeStatus(id, operator(user), request)); }
|
||||
|
||||
@GetMapping(value = "/export", produces = "text/csv")
|
||||
@PreAuthorize("hasAuthority('" + OverseasPermissions.VEHICLE_EXPORT + "')")
|
||||
public ResponseEntity<byte[]> export(@Valid VehicleDtos.Query query) {
|
||||
return ResponseEntity.ok().contentType(new MediaType("text", "csv", StandardCharsets.UTF_8))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=vehicles.csv").body(service.exportCsv(query));
|
||||
}
|
||||
|
||||
private String operator(AuthenticatedUser user) {
|
||||
if (user == null) return "UNKNOWN"; return user.userId() == null ? user.username() : String.valueOf(user.userId());
|
||||
}
|
||||
}
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
package com.baiyue.lastleg.masterdata.vehicle.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.dto.VehicleDtos;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.entity.Vehicle;
|
||||
import com.baiyue.lastleg.masterdata.vehicle.mapper.VehicleMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class VehicleService {
|
||||
private static final Set<String> OWNERSHIPS = Set.of("OWNED", "DISPATCHED");
|
||||
private static final Set<String> REGIONS = Set.of("DOMESTIC", "OVERSEAS");
|
||||
private static final Set<String> STATUSES = Set.of("IN_SERVICE", "DISPATCHED", "MAINTENANCE", "INACTIVE", "RETURNED");
|
||||
@Resource private VehicleMapper vehicles;
|
||||
|
||||
public PageResult<VehicleDtos.Response> page(VehicleDtos.Query query) {
|
||||
Page<Vehicle> page = vehicles.selectPage(Page.of(query.page(), query.size()), wrapper(query));
|
||||
return new PageResult<>(page.getRecords().stream().map(this::response).toList(), page.getCurrent(),
|
||||
page.getSize(), page.getTotal(), page.getPages());
|
||||
}
|
||||
|
||||
public VehicleDtos.Response detail(long id) { return response(required(id)); }
|
||||
|
||||
@Transactional
|
||||
public VehicleDtos.Response create(String operator, VehicleDtos.Create request) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Vehicle value = new Vehicle(); value.setId(IdWorker.getId());
|
||||
value.setPlateNumber(requiredText(request.plateNumber(), "车牌号").toUpperCase(Locale.ROOT));
|
||||
value.setModel(requiredText(request.model(), "车型")); value.setFuelConsumptionPer100Km(request.fuelConsumptionPer100Km());
|
||||
value.setMileageKm(request.mileageKm()); value.setDriverOrDispatchCompany(trim(request.driverOrDispatchCompany()));
|
||||
value.setPhone(trim(request.phone())); value.setRegion(region(request.region())); value.setOwnership(ownership(request.ownership()));
|
||||
value.setStatus(status(request.status())); value.setRemark(trim(request.remark())); value.setRecordVersion(0L);
|
||||
value.setCreatedBy(operator); value.setUpdatedBy(operator); value.setCreatedAt(now); value.setUpdatedAt(now);
|
||||
try { vehicles.insert(value); } catch (DuplicateKeyException exception) { throw conflict("车牌号已存在"); }
|
||||
return detail(value.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public VehicleDtos.Response update(long id, String operator, VehicleDtos.Update request) {
|
||||
Vehicle current = locked(id); requireVersion(current, request.recordVersion());
|
||||
if (request.mileageKm() < current.getMileageKm()) throw badRequest("当前公里码不能小于已有公里码");
|
||||
int updated;
|
||||
try {
|
||||
updated = vehicles.update(null, new LambdaUpdateWrapper<Vehicle>()
|
||||
.eq(Vehicle::getId, id).eq(Vehicle::getRecordVersion, request.recordVersion())
|
||||
.set(Vehicle::getPlateNumber, requiredText(request.plateNumber(), "车牌号").toUpperCase(Locale.ROOT))
|
||||
.set(Vehicle::getModel, requiredText(request.model(), "车型"))
|
||||
.set(Vehicle::getFuelConsumptionPer100Km, request.fuelConsumptionPer100Km())
|
||||
.set(Vehicle::getMileageKm, request.mileageKm())
|
||||
.set(Vehicle::getDriverOrDispatchCompany, trim(request.driverOrDispatchCompany()))
|
||||
.set(Vehicle::getPhone, trim(request.phone())).set(Vehicle::getRegion, region(request.region()))
|
||||
.set(Vehicle::getOwnership, ownership(request.ownership())).set(Vehicle::getRemark, trim(request.remark()))
|
||||
.set(Vehicle::getUpdatedBy, operator).set(Vehicle::getUpdatedAt, LocalDateTime.now())
|
||||
.setSql("record_version = record_version + 1"));
|
||||
} catch (DuplicateKeyException exception) { throw conflict("车牌号已存在"); }
|
||||
if (updated != 1) throw conflict("车辆档案已被其他操作修改,请刷新后重试");
|
||||
return detail(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public VehicleDtos.Response changeStatus(long id, String operator, VehicleDtos.ChangeStatus request) {
|
||||
Vehicle current = locked(id); requireVersion(current, request.recordVersion());
|
||||
String status = status(request.status());
|
||||
if (status.equals(current.getStatus())) return response(current);
|
||||
int updated = vehicles.update(null, new LambdaUpdateWrapper<Vehicle>()
|
||||
.eq(Vehicle::getId, id).eq(Vehicle::getRecordVersion, request.recordVersion())
|
||||
.set(Vehicle::getStatus, status).set(Vehicle::getUpdatedBy, operator)
|
||||
.set(Vehicle::getUpdatedAt, LocalDateTime.now()).setSql("record_version = record_version + 1"));
|
||||
if (updated != 1) throw conflict("车辆档案已被其他操作修改,请刷新后重试");
|
||||
return detail(id);
|
||||
}
|
||||
|
||||
public byte[] exportCsv(VehicleDtos.Query query) {
|
||||
var rows = vehicles.selectList(wrapper(query)).stream().map(this::response).toList();
|
||||
StringBuilder csv = new StringBuilder("\uFEFF车辆ID,车牌号,车型,油耗(L/100km),当前公里码(km),司机或外派单位,联系电话,区域,车辆归属,状态,更新时间\r\n");
|
||||
for (var row : rows) csv.append(row.id()).append(',').append(cell(row.plateNumber())).append(',')
|
||||
.append(cell(row.model())).append(',').append(row.fuelConsumptionPer100Km()).append(',').append(row.mileageKm()).append(',')
|
||||
.append(cell(row.driverOrDispatchCompany())).append(',').append(cell(row.phone())).append(',')
|
||||
.append(row.region()).append(',').append(row.ownership()).append(',').append(row.status()).append(',')
|
||||
.append(row.updatedAt()).append("\r\n");
|
||||
return csv.toString().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<Vehicle> wrapper(VehicleDtos.Query query) {
|
||||
String keyword = trim(query.keyword()); String ownership = optional(query.ownership(), OWNERSHIPS, "车辆归属");
|
||||
String region = optional(query.region(), REGIONS, "车辆区域"); String status = optional(query.status(), STATUSES, "车辆状态");
|
||||
return new LambdaQueryWrapper<Vehicle>()
|
||||
.and(StringUtils.hasText(keyword), w -> w.like(Vehicle::getPlateNumber, keyword)
|
||||
.or().like(Vehicle::getModel, keyword).or().like(Vehicle::getDriverOrDispatchCompany, keyword))
|
||||
.eq(ownership != null, Vehicle::getOwnership, ownership).eq(region != null, Vehicle::getRegion, region)
|
||||
.eq(status != null, Vehicle::getStatus, status).orderByDesc(Vehicle::getUpdatedAt).orderByDesc(Vehicle::getId);
|
||||
}
|
||||
private Vehicle required(long id) {
|
||||
Vehicle value = vehicles.selectById(id); if (value == null) throw notFound(); return value;
|
||||
}
|
||||
private Vehicle locked(long id) {
|
||||
Vehicle value = vehicles.lockById(id); if (value == null) throw notFound(); return value;
|
||||
}
|
||||
private VehicleDtos.Response response(Vehicle value) {
|
||||
return new VehicleDtos.Response(String.valueOf(value.getId()), value.getPlateNumber(), value.getModel(),
|
||||
value.getFuelConsumptionPer100Km(), value.getMileageKm(), value.getDriverOrDispatchCompany(), value.getPhone(),
|
||||
value.getRegion(), value.getOwnership(), value.getStatus(), value.getRemark(), version(value.getRecordVersion()),
|
||||
value.getUpdatedBy(), value.getUpdatedAt());
|
||||
}
|
||||
private void requireVersion(Vehicle value, long expected) {
|
||||
if (version(value.getRecordVersion()) != expected) throw conflict("车辆档案已被其他操作修改,请刷新后重试");
|
||||
}
|
||||
private static String ownership(String value) { return required(value, OWNERSHIPS, "车辆归属"); }
|
||||
private static String region(String value) { return required(value, REGIONS, "车辆区域"); }
|
||||
private static String status(String value) { return required(value, STATUSES, "车辆状态"); }
|
||||
private static String optional(String value, Set<String> allowed, String label) {
|
||||
return StringUtils.hasText(value) ? required(value, allowed, label) : null;
|
||||
}
|
||||
private static String required(String value, Set<String> allowed, String label) {
|
||||
if (!StringUtils.hasText(value)) throw badRequest(label + "不能为空");
|
||||
String normalized = value.trim().toUpperCase(Locale.ROOT);
|
||||
if (!allowed.contains(normalized)) throw badRequest(label + "不合法"); return normalized;
|
||||
}
|
||||
private static String requiredText(String value, String label) {
|
||||
if (!StringUtils.hasText(value)) throw badRequest(label + "不能为空"); return value.trim();
|
||||
}
|
||||
private static long version(Long value) { return value == null ? 0L : value; }
|
||||
private static String trim(String value) { return StringUtils.hasText(value) ? value.trim() : null; }
|
||||
private static String cell(Object value) { return "\"" + String.valueOf(value == null ? "" : value).replace("\"", "\"\"") + "\""; }
|
||||
private static ResponseStatusException notFound() { return new ResponseStatusException(HttpStatus.NOT_FOUND, "车辆档案不存在"); }
|
||||
private static ResponseStatusException badRequest(String message) { return new ResponseStatusException(HttpStatus.BAD_REQUEST, message); }
|
||||
private static ResponseStatusException conflict(String message) { return new ResponseStatusException(HttpStatus.CONFLICT, message); }
|
||||
}
|
||||
+2
@@ -32,6 +32,8 @@ public class UnloadCompletedOutboxRepository {
|
||||
.eq(LastlegEventOutbox::getId, id)
|
||||
.eq(LastlegEventOutbox::getEventType, EventTypes.OVERSEAS_CONTAINER_UNLOADED)
|
||||
.and(status -> status.eq(LastlegEventOutbox::getStatus, "PENDING")
|
||||
.and(retry -> retry.isNull(LastlegEventOutbox::getNextRetryAt)
|
||||
.or().le(LastlegEventOutbox::getNextRetryAt, now))
|
||||
.or(stale -> stale.eq(LastlegEventOutbox::getStatus, "PROCESSING")
|
||||
.le(LastlegEventOutbox::getLockedAt, expiredLeaseBefore)))
|
||||
.set(LastlegEventOutbox::getStatus, "PROCESSING")
|
||||
|
||||
@@ -54,6 +54,8 @@ public class LoadingCompletedConsumer {
|
||||
throw new IllegalArgumentException("尾程交接事件区域无效");
|
||||
if (!"LOADING_PLAN".equals(envelope.aggregateType()))
|
||||
throw new IllegalArgumentException("尾程交接事件聚合类型无效");
|
||||
if (!EventPayloadHash.matches(EventPayloadCanonicalizer.canonicalize(envelope.payload()),
|
||||
envelope.payloadHash())) throw new IllegalArgumentException("payloadHash 与尾程事件负载不一致");
|
||||
FirstLegLoadingPlanCompletedV1 payload = parsePayload(envelope);
|
||||
if(payload.containerNo()==null||payload.containerNo().isBlank())
|
||||
throw new IllegalArgumentException("事件没有实际集装箱号 containerNo");
|
||||
@@ -70,6 +72,11 @@ public class LoadingCompletedConsumer {
|
||||
inbox.setEventVersion(envelope.eventVersion()); inbox.setPayloadHash(envelope.payloadHash());
|
||||
inbox.setPayloadJson(envelope.payload().toString()); inbox.setStatus("RECEIVED"); inbox.setReceivedAt(LocalDateTime.now());
|
||||
try { inboxMapper.insert(inbox); } catch(DuplicateKeyException exception) {
|
||||
LastlegEventInbox raced = inboxMapper.selectById(envelope.eventId());
|
||||
if (raced == null || raced.getPayloadHash() == null
|
||||
|| !raced.getPayloadHash().equalsIgnoreCase(envelope.payloadHash())) {
|
||||
throw new IllegalArgumentException("事件摘要冲突", exception);
|
||||
}
|
||||
return countOrders(envelope,payload.containerNo());
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -1,6 +1,8 @@
|
||||
package com.baiyue.lastleg.shipping.service;
|
||||
|
||||
import com.baiyue.common.event.EventEnvelope;
|
||||
import com.baiyue.common.event.EventPayloadCanonicalizer;
|
||||
import com.baiyue.common.event.EventPayloadHash;
|
||||
import com.baiyue.common.event.EventTypes;
|
||||
import com.baiyue.common.event.FirstLegContainerShippingNodeRecordedV1;
|
||||
import com.baiyue.common.event.RegionCode;
|
||||
@@ -91,6 +93,10 @@ public class ContainerShippingNodeConsumer {
|
||||
|
||||
private void validate(EventEnvelope envelope) {
|
||||
envelope.requireValid();
|
||||
if (!EventPayloadHash.matches(EventPayloadCanonicalizer.canonicalize(envelope.payload()),
|
||||
envelope.payloadHash())) {
|
||||
throw new IllegalArgumentException("payloadHash 与船节点事件负载不一致");
|
||||
}
|
||||
if (!EventTypes.FIRST_LEG_CONTAINER_SHIPPING_NODE_RECORDED.equals(envelope.eventType())
|
||||
|| envelope.eventVersion() != 1 || envelope.sourceRegion() != RegionCode.CN
|
||||
|| envelope.targetRegion() != RegionCode.OVERSEAS
|
||||
|
||||
Reference in New Issue
Block a user