24ada70997
新增 common/service/ResultDownloadResolver,7 个模块的 resolveResultDownloadUrl 改为委托调用(appearancepatent/queryasin/withdraw/pricetrack/productrisk/ patroldelete/shopmatch)。 顺带修掉两处隐患: - 原实现用 userId.equals(entity.getUserId()),userId 为 null 时 NPE (新实现用 Objects.equals) - shopmatch 原实现在 url 为空时抛"任务不存在",与语义不符,统一为"暂无可下载文件" 其余 4 处**刻意保留**,因为它们本就不是重复: - shopdatacrawl:有 validateUserId + requireResultEntity + ensureResultOwner 前置校验 - deletebrand:返回 null 而非抛异常(调用方依赖该语义) - similarasin:已分叉为返回 record ResultDownloadInfo - brand:走的是另一套下载路径 文件名解析 resolveResultDownloadFilename 同样没收口:各模块兜底文件名策略确有差异 配套更新 3 个显式构造 Service 的测试(DelegationTest/HistoryBatchTest/ RollbackSemanticsContractTest)注入新依赖的 mock。mvn test 2795 个全绿。