From c4699ab363c16760699cc16cb69282e9171d2ddf Mon Sep 17 00:00:00 2001 From: quyixiao <2621048238@qq.com> Date: Wed, 24 Jun 2026 01:13:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../car/RecognizeDriverLicenseController.java | 104 +++++++++--------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/api-web/api-interface/src/main/java/com/heyu/api/controller/car/RecognizeDriverLicenseController.java b/api-web/api-interface/src/main/java/com/heyu/api/controller/car/RecognizeDriverLicenseController.java index fa4b7b0..b4f8b7b 100644 --- a/api-web/api-interface/src/main/java/com/heyu/api/controller/car/RecognizeDriverLicenseController.java +++ b/api-web/api-interface/src/main/java/com/heyu/api/controller/car/RecognizeDriverLicenseController.java @@ -35,7 +35,7 @@ import java.util.Map; *

本服务接口

* * @@ -73,32 +73,26 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle @PostMapping("/recognize") public R recognize(@RequestBody DriverLicenseRecognizeRequest request) { long start = System.currentTimeMillis(); - RecognizeContext ctx = null; + // 入口处一次性解析:整个请求中 ImageInputUtils.validate / resolve 仅执行一次,后续主流程与 catch 块复用 ctx。 + ImageInputUtils.ValidationResult imageValidation = request != null ? ImageInputUtils.validate(request.getImageUrlOrBase64()) : null; + ResolvedImageInput imageInput = imageValidation != null && imageValidation.isValid() ? imageValidation.getResolved() : null; + String resolvedSide = request != null ? resolveDrivingLicenseSide(request) : null; + RecognizeContext ctx = new RecognizeContext( + resolvedSide != null ? resolvedSide : ApiConstants.front, + imageInput, + buildInputLogContext(request, imageInput, resolvedSide)); try { // ---------- 步骤①:参数校验(不调百度、不扣费) ---------- - String validateError = validateRequest(request); + String validateError = validateRequest(request, imageValidation, resolvedSide, ctx); if (validateError != null) { - String side = request != null ? resolveDrivingLicenseSide(request) : null; - if (side == null) { - side = ApiConstants.front; - } - ResolvedImageInput validateImage = request != null - ? ImageInputUtils.resolve(request.getImageUrlOrBase64()) : null; log.info("驾驶证识别:参数检查没通过,接口仍返回成功并附带提示(还没调识别、不扣费)。{} 返回给客户:{}", - buildInputLogContext(request, validateImage), - abbreviate(validateError, 120)); - return okResult(side, validateError, null); + ctx.inputLog, abbreviate(validateError, 120)); + return okResult(ctx.side, validateError, null); } + // 校验通过后 ctx.imageInput 与 ctx.side 必然有效,下文可直接使用。 - // ---------- 步骤②:解析影像入参 & 构建上下文 ---------- - ResolvedImageInput imageInput = ImageInputUtils.resolve(request.getImageUrlOrBase64()); - ctx = new RecognizeContext( - resolveDrivingLicenseSide(request), - imageInput, - buildInputLogContext(request, imageInput)); - - // ---------- 步骤③:组装百度 API 请求体 ---------- - String content = buildRequestContent(imageInput, ctx.side); + // ---------- 步骤②:组装百度 API 请求体 ---------- + String content = buildRequestContent(ctx.imageInput, ctx.side); if (isBlank(content)) { log.error("驾驶证识别:组装请求失败,请求里没带有效图片。识别{},{}。{}", sideDesc(ctx.side), ctx.imageInput.getType().getDesc(), ctx.inputLog); @@ -106,45 +100,40 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle "报文组装异常", "识别请求体在序列化后未包含任何影像载荷,平台侧无法受理本次识别", "请核对 imageUrlOrBase64 是否非空且为有效 Base64 或 HTTP(S) 链接;" - + "请求头须为 application/x-www-form-urlencoded", - "目标页面=" + sideLabel(ctx.side) + ",影像模式=" + ctx.imageInput.getType().name() + + "请求头须为 application/json", + locator(ctx) ), null); } - // ---------- 步骤④:调用百度平台识别 ---------- + // ---------- 步骤③:调用百度平台识别 ---------- Map platformResult = callPlatform(content, ctx); if (platformResult == null) { return okResult(ctx.side, formatHint( "服务无回执", "识别指令已下发,但在约定时间内未收到平台可解析的 JSON 回执", "建议间隔 3~5 秒重试;若连续失败,请记录 traceId、调用时刻与 side 并联系技术支持排查链路", - "目标页面=" + sideLabel(ctx.side) + ",影像模式=" + ctx.imageInput.getType().name() + locator(ctx) ), null); } - // ---------- 步骤⑤:解析平台结果 → 根据 side 构建正页/副页响应 ---------- + // ---------- 步骤④:解析平台结果 → 根据 side 构建正页/副页响应 ---------- Object data = ApiConstants.back.equals(ctx.side) ? buildBackResp(platformResult) : buildFaceResp(platformResult); String hint = resolvePlatformHint(platformResult, ctx, data); - // ---------- 步骤⑥:日志记录 & 返回 ---------- + // ---------- 步骤⑤:日志记录 & 返回 ---------- logRecognizeResult(ctx, platformResult, data, hint, start); return okResult(ctx.side, hint, data); } catch (Exception e) { long cost = System.currentTimeMillis() - start; - String side = ctx != null ? ctx.side - : (request != null ? resolveDrivingLicenseSide(request) : ApiConstants.front); - ResolvedImageInput fallbackImage = request != null - ? ImageInputUtils.resolve(request.getImageUrlOrBase64()) : null; - String mode = ctx != null ? ctx.imageInput.getType().getDesc() - : (fallbackImage != null ? fallbackImage.getType().getDesc() : "未知"); + String modeDesc = ctx.imageInput != null ? ctx.imageInput.getType().getDesc() : "影像未解析"; log.error("驾驶证识别:程序运行出错,耗时 {} ms。识别{},{}。客户传的:{}。异常:{} - {}", - cost, sideDesc(side), mode, buildInputLogContext(request, fallbackImage), + cost, sideDesc(ctx.side), modeDesc, ctx.inputLog, e.getClass().getSimpleName(), e.getMessage() != null ? e.getMessage() : "无具体说明", e); - return okResult(side, formatHint( + return okResult(ctx.side, formatHint( "运行时故障", "服务端在处理识别流程时抛出未预期异常,识别结果不可用", "请勿重复高频重试;请保存 traceId、异常发生时间及 side,由技术支持结合堆栈进一步定位", @@ -271,24 +260,26 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle // ===================== 校验与上下文 ===================== - private String validateRequest(DriverLicenseRecognizeRequest request) { + /** + * 纯逻辑校验:基于入口处已完成的 imageValidation / resolvedSide 做判断,自身不再触发 IO。 + */ + private String validateRequest(DriverLicenseRecognizeRequest request, + ImageInputUtils.ValidationResult imageValidation, + String resolvedSide, + RecognizeContext ctx) { if (request == null) { - log.info("驾驶证识别:没收到任何请求参数(表单未绑定成功),直接拒绝,未调用识别、不扣费"); + log.info("驾驶证识别:没收到任何请求参数(请求体未绑定成功),直接拒绝,未调用识别、不扣费"); return formatHint( "入参绑定失败", - "控制器未接收到可绑定的表单对象,所有业务字段均为空", - "请确认使用 POST 提交;Content-Type 为 application/json 或 application/x-www-form-urlencoded;" + "控制器未接收到可绑定的请求对象,所有业务字段均为空", + "请确认使用 POST 提交;Content-Type 为 application/json;" + "字段名与接口文档一致(imageUrlOrBase64 / side)", "绑定结果=DriverLicenseRecognizeRequest 为 null" ); } - ImageInputUtils.ValidationResult imageValidation = - ImageInputUtils.validate(request.getImageUrlOrBase64()); - if (!imageValidation.isValid()) { + if (imageValidation != null && !imageValidation.isValid()) { log.info("驾驶证识别:imageUrlOrBase64 校验未通过({}),未调用识别、不扣费。原因:{}。{}", - imageValidation.getCategory(), - imageValidation.getReason(), - buildInputLogContext(request, null)); + imageValidation.getCategory(), imageValidation.getReason(), ctx.inputLog); return formatHint( imageValidation.getCategory(), imageValidation.getReason(), @@ -297,9 +288,9 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle + (isBlank(request.getSide()) ? SIDE_DEFAULT_HINT : request.getSide().trim()) ); } - if (resolveDrivingLicenseSide(request) == null) { + if (resolvedSide == null) { log.info("驾驶证识别:side 参数写错了(只支持 face/front 正页、back 副页),直接拒绝,未调用识别、不扣费。{}", - buildInputLogContext(request, ImageInputUtils.resolve(request.getImageUrlOrBase64()))); + ctx.inputLog); return formatHint( "页面标识无效", "参数 side 的取值无法映射到驾驶证正页或副页识别模式", @@ -318,7 +309,7 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle if (request == null || isBlank(request.getSide())) { return ApiConstants.front; } - String side = request.getSide().trim(); + String side = request.getSide().trim().toLowerCase(); if (ApiConstants.face.equals(side) || ApiConstants.front.equals(side)) { return ApiConstants.front; } @@ -411,13 +402,18 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle return sb.toString(); } - /** 入参日志说明(不打印影像正文,只说类型与长度) */ - private String buildInputLogContext(DriverLicenseRecognizeRequest request, ResolvedImageInput imageInput) { + /** + * 入参日志说明(不打印影像正文,只说类型与长度)。 + * + * @param resolvedSide 已在调用方解析过的 side(无效时为 null),避免本方法内重复 resolve + */ + private String buildInputLogContext(DriverLicenseRecognizeRequest request, + ResolvedImageInput imageInput, + String resolvedSide) { if (request == null) { return "未收到请求体"; } String sideParam = isBlank(request.getSide()) ? "未传(默认按正页)" : request.getSide().trim(); - String resolvedSide = resolveDrivingLicenseSide(request); String targetPage = resolvedSide == null ? "side 无法识别" : sideDesc(resolvedSide); String modeDesc = imageInput != null ? imageInput.getType().getDesc() : "影像未解析"; int rawLen = imageInput != null @@ -426,4 +422,10 @@ public class RecognizeDriverLicenseController extends AbstractRecognizeControlle return String.format("识别%s,side 参数=%s,%s,影像原始长度 %d 字符", targetPage, sideParam, modeDesc, rawLen); } + + /** "目标页面=xx,影像模式=xx" 拼接,formatHint 的 detail 字段共用此格式。 */ + private String locator(RecognizeContext ctx) { + return "目标页面=" + sideLabel(ctx.side) + ",影像模式=" + + (ctx.imageInput != null ? ctx.imageInput.getType().name() : "未解析"); + } }