package com.zteits.glockcollect.biz; import com.zteits.clouds.api.apibase.bean.BizResult; import com.zteits.clouds.api.apibase.constants.ErrorType; import com.zteits.clouds.api.dto.datacollect.param.df.DfGroundLockConfigPushRequest; import com.zteits.clouds.api.dto.datacollect.param.df.DfGroundLockControlPushRequest; import com.zteits.clouds.api.dto.datacollect.param.df.DfGroundLockOpenByPayPushRequest; import com.zteits.clouds.api.service.datacollect.DfGroundLockMsgPushService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * {@link DfGroundLockMsgPushService}(给德飞地锁推送下发任务)的**空实现** —— 临时桥接,不是业务代码。 * *

为什么需要它

* * 老工程里这个接口由**独立 JVM** {@code zteits-glock-collection} 通过 Dubbo 提供。 * 单 Jar 之后没有 Dubbo 了,但调用方还在: * * 两处都是**裸 {@code @Autowired}(required=true)**,缺 Bean 则整个单 Jar 启动失败 * (实测报错:{@code No qualifying bean of type * 'com.zteits.clouds.api.service.datacollect.DfGroundLockMsgPushService'}, * 装配链 {@code dealGeoInOutParkDataSchedule → ... → DeFeiNotifyServiceImpl})。 * *

为什么不用真实实现

* * 真实实现是 {@code zteits-glock-collection/src/main/java/com/zteits/glockcollect/biz/ * DfGroundLockMsgPushServiceImpl.java},它依赖 {@code DFClientMsgPushService} —— 一条 * **netty 长连接 TCP 客户端**(持有设备 Channel、按设备号找 ChannelHandlerContext)。 * 该工程用的是 {@code netty 5.0.0.Alpha2},而本工程 Redisson 依赖 netty 4.1.x, * 两者不能同进程共存(同名 {@code io.netty.*} 类会互相覆盖)。 * 德飞地锁属于**设备网关**范畴,随迁它 = 同时解决 netty 版本冲突 + TCP 客户端生命周期, * 故整体推迟到设备对接阶段(方案 P5),本轮只保证单 Jar 能起来。 * *

为什么是「返回失败」而不是「抛异常」

* * 三个调用点对异常的容忍度不同,**抛异常会改变既有行为**: * * 折中:返回 {@code success=false} 的 {@link BizResult} 并**打 error 日志**。 * 三个调用点都只看日志、不判 {@code isSuccess()},因此**行为与接入真实实现时完全一致** * (真实实现在消息写成功后同样只返回结果、不做后续判断),同时丢失的链路在日志里一眼可见。 *

* 也**刻意不返回 {@code new BizResult<>(true)}**:那等于谎报「地锁已开」, * 将来若有调用方开始判返回值,会被静默骗过。 * *

⚠️ P5 交接(务必执行)

* * 搬入 {@code zteits-glock-collection} 的真实实现后,**必须删除本类**: * 本类的 Bean 名刻意取了真实实现的 {@code @Service} 值 * ({@code com.zteits.glockcollect.biz.DfGroundLockMsgPushServiceImpl}), * 两者同时存在会以 {@code ConflictingBeanDefinitionException} 启动失败 —— * 这是刻意留的「别忘了删我」的探针,而不是「自动兜底」。 * 本类所在的 {@code com.zteits.glockcollect} 包已在 * {@code ParkingServerApplication} 的 {@code @ComponentScan} 里,搬入真实实现无需再改扫描配置。 * * @see com.zteits.clouds.api.service.datacollect.DfGroundLockMsgPushService */ @Slf4j @Service("com.zteits.glockcollect.biz.DfGroundLockMsgPushServiceImpl") public class NoopDfGroundLockMsgPushService implements DfGroundLockMsgPushService { /** 错误信息前缀:在日志/返回体里全局可检索,用于区分「地锁未接入」与「地锁真的发失败了」。 */ public static final String NOT_INTEGRATED_PREFIX = "[德飞地锁未接入]"; private static final String NOT_INTEGRATED = NOT_INTEGRATED_PREFIX + " 单 Jar 未随迁 zteits-glock-collection(netty 5.0.0.Alpha2 与 " + "Redisson 的 netty 4.1.x 冲突,见类注释),本次下发已丢弃。"; @Override public BizResult pushGroundLockConfig(DfGroundLockConfigPushRequest request) throws InterruptedException { warn("pushGroundLockConfig", "配置下发", request == null ? null : request.getPlNo(), request == null ? null : request.getEqpNo()); return failure(); } @Override public BizResult pushGroundLockOpenByPay(DfGroundLockOpenByPayPushRequest request) throws InterruptedException { warn("pushGroundLockOpenByPay", "支付开锁", request == null ? null : request.getPlNo(), request == null ? null : request.getEqpNo()); return failure(); } @Override public BizResult pushGroundLockControl(DfGroundLockControlPushRequest request) throws InterruptedException { warn("pushGroundLockControl", "控制指令", request == null ? null : request.getPlNo(), request == null ? null : request.getEqpNo()); return failure(); } /** * 每次下发都按 e rror 级别记录:这是「地锁不会真的动作」的唯一可见信号, * 降级成 warn/info 会让线上问题排查时漏掉。 * 用 plNo/eqpNo 定位到具体车场与设备(eqpNo 在存量代码里取的是 {@code orderPark.getCarNumber()})。 */ private void warn(String method, String action, String plNo, String eqpNo) { log.error("{} {}({}) 未真实下发 —— 消息已丢弃。plNo={}, eqpNo={}。" + "依赖地锁的链路(德飞支付成功开锁 / 0 元支付降锁 / 地锁配置与控制)都不会生效;" + "恢复方式见 NoopDfGroundLockMsgPushService 类注释的 P5 交接。", NOT_INTEGRATED_PREFIX, method, action, plNo, eqpNo); } private BizResult failure() { // 注意:BizResult(ErrorType,String) 会把 success 置为 false(ResultBean 构造函数), // 且不设置 data —— 不能改写成 new BizResult<>(Boolean.FALSE),那会把 success 置为 true。 return new BizResult<>(ErrorType.PARK_SEND_FAIL, NOT_INTEGRATED); } }