首页/新闻资讯/正文详情

AI陪伴机器人DTO参数校验-把脏数据拦在门口

发布时间:2026/9/24 3:53:29 来源:云帆数科 栏目:资讯中心
AI陪伴机器人DTO参数校验-把脏数据拦在门口
07-DTO参数校验-把脏数据拦在门口系列AI 伙伴AI-Partner——具身智能陪伴机器人 · 数据接口部署与二次开发篇07/12一、为什么校验要放在门口先说个真实场景你在前端页面上提交一条健康记录手一抖type字段空了请求直接打到了 Service 层Service 里判空逻辑没写全于是数据库里多了一条类型为 null的脏数据。后面做趋势查询、做异常告警判定这条数据就是个地雷随时炸。这种问题的正解只有一个数据进门之前先验一遍不合格直接轰出去。在 Spring Boot 的体系里这个门口就是 DTO Bean Validation。先解释几个名词照顾零基础的朋友DTOData Transfer Object数据传输对象。前端传过来的 JSON先反序列化成一个 Java 对象这个对象就叫 DTO。它和数据库的 Entity 不是一回事——Entity 对应表结构DTO 对应接口契约。Bean ValidationJava 的参数校验标准老一辈叫 JSR-303/380Jakarta 时代就是 jakarta.validation 包。你在字段上贴注解框架替你做检查。Valid触发校验的开关。贴在 Controller 入参上进方法之前先校验 DTO。二、项目里的依赖validation starterAI 伙伴AI-Partner后端在 pom 里显式引入了校验依赖项目源码dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependency这里有个新手常踩的坑要提一句Spring Boot 2.3 之后web starter 里不再自带校验能力。你要是用校验注解却没引这个 starter运行时Valid会假装生效——不报错、也不校验脏数据照进不误。所以这个依赖别漏。三、5 个 DTO 逐个拆字段、注解、文案AI 伙伴AI-Partner的dto包里共有 5 个 DTO全部用 Lombok 的Data校验注解来自jakarta.validation.constraints。下面逐个过以下均为项目源码。3.1 ChatRequest —— 对话请求NotNull(messageuserId 不能为空)privateLonguserId;NotBlank(message消息内容不能为空)privateStringmessage;privateStringsessionTypetext;// text / voiceprivateBooleanneedTtsfalse;// 是否合成语音3.2 UserRequest —— 用户注册/登录NotBlank(messageopenId 不能为空)privateStringopenId;privateStringplatformweb;// wechat / alipay / webprivateStringnickname;3.3 ReminderRequest —— 创建提醒NotNull(messageuserId 不能为空)privateLonguserId;NotBlank(message提醒标题不能为空)privateStringtitle;privateStringcontent;privateLocalDateTimeremindTime;// 触发时间不填则用 cronprivateStringtypecustom;// medication/schedule/water/birthday/customprivateStringcron;// 重复表达式可选privateStringdeviceId;// 目标设备编码可选3.4 EmotionRequest —— 情绪记录NotNull(messageuserId 不能为空)privateLonguserId;NotBlank(message情绪类型不能为空)privateStringemotion;privateIntegerintensity5;// 强度 1-10privateStringcontext;// 触发场景privateStringsourcemanual;// agent / vision / manual3.5 HealthRequest —— 健康数据NotNull(messageuserId 不能为空)privateLonguserId;NotBlank(message记录类型不能为空)privateStringtype;privateStringvalue;privateStringunit;privateStringnote;privateStringdeviceId;// 设备编码可选四、NotNull 与 NotBlank一字之差天壤之别看上面 5 个 DTO只用到了两种注解但选得很有讲究注解对 String 的判定适用场景NotNull只检查不是 null空串能通过数字、对象、枚举 ID 等NotBlank必须非 null 且去掉首尾空格后还有内容一切用户输入的文本为什么userId用NotNull而message用NotBlank因为 userId 是Long类型的数字根本不存在空串概念null 就是唯一违法形态而 message 是文本和 在业务上都等于没说话必须拦。对照表收好这就是项目目前的字段 → 约束 → 错误文案全账DTO字段约束校验失败时的错误文案默认值ChatRequestuserIdNotNulluserId 不能为空—ChatRequestmessageNotBlank消息内容不能为空—ChatRequestsessionType无—textChatRequestneedTts无—falseUserRequestopenIdNotBlankopenId 不能为空—UserRequestplatform无—webUserRequestnickname无——ReminderRequestuserIdNotNulluserId 不能为空—ReminderRequesttitleNotBlank提醒标题不能为空—ReminderRequesttype无—customEmotionRequestuserIdNotNulluserId 不能为空—EmotionRequestemotionNotBlank情绪类型不能为空—EmotionRequestintensity无—5EmotionRequestsource无—manualHealthRequestuserIdNotNulluserId 不能为空—HealthRequesttypeNotBlank记录类型不能为空—看清楚了吗只有必填项做了校验格式校验长度、范围、枚举取值一个都没有。这是项目的现状也是可以改进的空间后面细说。五、Valid 触发时机与异常路径Controller 里是怎么用的以 ChatController 为例项目源码节选PostMappingpublicApiResponseChatService.ChatResultchat(ValidRequestBodyChatRequestrequest){returnApiResponse.ok(chatService.chat(request.getUserId(),request.getMessage(),request.getSessionType(),Boolean.TRUE.equals(request.getNeedTts())));}9 个 Controller 里所有带 DTO 的 POST 接口都挂了Valid RequestBody。执行顺序是请求进来先把 JSON 反序列化成 DTOValid触发按字段上的注解逐个检查全部通过 → 进入方法体任一失败 → 抛出MethodArgumentNotValidException方法体根本不会执行。那异常抛出来谁接项目在common/GlobalExceptionHandler里专门写了一个处理器项目源码ExceptionHandler(MethodArgumentNotValidException.class)publicResponseEntityApiResponseVoidhandleValidation(MethodArgumentNotValidExceptione){FieldErrorfieldErrore.getBindingResult().getFieldError();StringmessagefieldErrornull?参数校验失败:fieldError.getDefaultMessage();returnResponseEntity.badRequest().body(ApiResponse.fail(400,message));}这段代码有三个细节值得品只取第一个字段错误getFieldError()返回的就是一条。当多个字段同时非法时用户只会看到第一条。对陪伴机器人这种 C 端场景一次报一条比一股脑甩十条规定更友好但如果你做管理后台可能希望返回全部错误改成getAllErrors()循环拼接即可。HTTP 状态码 400 业务码 400 双重标识配合统一响应体ApiResponsecode/message/data 三段式。兜底文案“参数校验失败”。万一哪个注解忘了写 message也不至于把英文技术报错直接糊到用户脸上。实际效果演示curl-XPOST http://localhost:8080/api/chat\-HContent-Type: application/json\-d{userId:1,message:}# 响应{code:400,message:消息内容不能为空,data:null}注意校验失败时data是 null前端只需要盯code ! 0就行。六、进阶玩法示意嵌套、分组、自定义注解项目目前没用这些但零基础的朋友迟早会需要这里给出思路。嵌套对象校验DTO 里套 DTO 时在外层字段上加Valid才能让校验钻进去publicclassOrderRequest{NotNull(messageuserId 不能为空)privateLonguserId;Valid// 没有它里面的注解全部失效NotNull(message地址信息不能为空)privateAddressRequestaddress;// AddressRequest 内部再贴 NotBlank 等}分组校验同一个 DTO新增时不校验 id更新时必须校验 id。用groups区分publicclassUserSaveRequest{Null(groupsCreate.class,message新增时不能传 id)NotNull(groupsUpdate.class,message更新时 id 不能为空)privateLongid;}// Controller 上Validated(Create.class) 或 Validated(Update.class)自定义校验注解比如想让EmotionRequest.intensity强制 1~10。思路是定义一个注解IntensityRange再写一个实现ConstraintValidatorIntensityRange, Integer的校验器isValid里写判断逻辑最后在字段上贴注解。这是把魔法值判断从 Service 收编到 DTO 的标准姿势。当然最省事的现成方案是直接用Min(1) Max(10)——jakarta 自带何必手搓。七、边界讨论校验放 DTO 还是 Service这是老争论了我的观点两层都要但干不同的活。层职责例子失败表现DTO Valid格式与形式类型、必填、长度、范围、正则message 非空、intensity 在 1~10HTTP 400统一文案Service业务规则查库后才能判断的东西userId 是否存在、设备是否绑定、openId 是否重复BusinessException带业务语义AI 伙伴AI-Partner正是这么分的DTO 层拦必填Service 层管业务比如MemoryService.save里校验 importance 在 [1,5]、EmotionService.record里校验 intensity 在 [1,10]都是查上下文后的业务校验。一句话总结DTO 校验是门卫Service 校验是安检机缺一个都会漏人。八、现状盘点与改进清单如实说AI 伙伴AI-Partner的校验层目前只做了必填这一档结合前面那张对照表可以列出这些待改进点缺格式约束type、emotion、platform这类枚举语义字段是自由字符串传个abc也能进库。可以用Pattern(regexp ...)或自定义注解收口。缺长度约束title数据库限 128 字符、content限 512DTO 层没有Size超长内容会直接被 MySQL 报错变成一坨 500。缺数值范围intensity的 1~10 校验在 ServiceDTO 层加Min Max更早拦截。错误聚合目前只返回第一条错误多字段同时出错时前端体验一般。校验这东西做得早是挡脏数据的门做得晚是擦脏数据的墙。项目这条链路DTO 注解 → Valid → MethodArgumentNotValidException → 统一 400 响应已经把骨架搭好了剩下的就是往注解里填约束的体力活。动手吧让每一条进门的 JSON 都干干净净。

相关推荐

EMQX MQTT 桥接陈旧连接状态修复解析:从「假 Connected」到真实健康检查与自动重连
EMQX MQTT 桥接陈旧连接状态修复解析:从「假 Connected」到真实健康检查与自动重连

后端物联网消息队列通信 【免费下载链接】emqx The most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles 项目地址: https://gitcode.com/gh_mirrors/em/emqx 点击查看 免费下载 本文围绕 EMQX 开源仓库中 changes/ee/fix-15603.en.… · 2026/9/24 3:53:23

Dopamine 实验统计汇总实战:深入解析 colab.utils.summarize_data 逐迭代数据聚合
Dopamine 实验统计汇总实战:深入解析 colab.utils.summarize_data 逐迭代数据聚合

机器学习深度学习 【免费下载链接】dopamine Dopamine is a research framework for fast prototyping of reinforcement learning algorithms. 项目地址: https://gitcode.com/gh_mirrors/do/dopamine 点击查看 免费下载 导读:本文围绕 Dopamine 强化… · 2026/9/24 3:53:11

微信小程序|template 模板实战,学生、教师、奥运冠军卡片、
微信小程序|template 模板实战,学生、教师、奥运冠军卡片、

前言 在小程序开发中&#xff0c;经常会遇到页面多处重复展示相同结构的 UI&#xff0c;比如列表卡片、信息条目。如果重复写多份相同 wxml 代码&#xff0c;代码冗余、后期维护麻烦。小程序提供 <template>模板&#xff0c;可以把重复 UI 结构封装&#xff0c;一处定义… · 2026/9/24 3:53:05

光功率预测技术深度解析:从气象数据到调度指令的全链路
光功率预测技术深度解析:从气象数据到调度指令的全链路

光功率预测不是"看天气"那么简单。预测偏差1%&#xff0c;可能意味着每月多交数万元考核罚款。 LinkQi 领祺 新能源技术深度系列 光功率预测技术深度解析&#xff1a;从气象数据到调度指令的全链路 光功率预测是新能源场站的核心能力。调度要求场站提供短期&#x… · 2026/9/24 4:26:50

Pod (最小调度单元)的一些常见问题
Pod (最小调度单元)的一些常见问题

1&#xff1a;为什么 Kubernetes 不直接运行容器&#xff0c;而是引入 Pod 这一逻辑概念&#xff1f;现实业务里&#xff0c;一套完整服务往往不止一个进程。 举个典型例子&#xff1a;业务主程序 日志采集 sidecar 配置刷新 agent&#xff0c;多个进程需要紧密配合。 将这些… · 2026/9/24 4:26:50

中标信息|上饶市合利鑫机械科技有限公司数字化转型提升服务项目中标公告
中标信息|上饶市合利鑫机械科技有限公司数字化转型提升服务项目中标公告

我单位依照公正、公平、公开的原则&#xff0c;在符合国家相关法律法规及公司制度的前提下&#xff0c;对上饶市合利鑫机械科技有限公司数字化转型综合服务进行公开招标&#xff0c;现将结果公示。项目名称&#xff1a;上饶市合利鑫机械科技有限公司数字化转型提升服务项目中标… · 2026/9/24 4:26:44

LPC2388深入解析:ARM7与AMBA 2.0嵌入式系统底层实践
LPC2388深入解析:ARM7与AMBA 2.0嵌入式系统底层实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 4:26:32

低空飞行器芯片架构全景解析:感知-决策-执行-通信-安全五层协同
低空飞行器芯片架构全景解析:感知-决策-执行-通信-安全五层协同

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 4:26:32

高通骁龙865救砖指南:QPST与9008模式底层刷机实战
高通骁龙865救砖指南:QPST与9008模式底层刷机实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 4:26:32

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介&#xff1a;这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源&#xff0c;围绕YOLOv8实现渔船作业监控系统&#xff0c;可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件&#xff0c;约24.21MB&#xff0c;以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介&#xff1a;面向时间序列数据建模的一维卷积神经网络完整实现&#xff0c;适合深度学习入门者及需要快速验证时序模型的研究者&#xff0c;能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小&#xff0c;只有3KB&#xff0c;内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L&#xff0c;而是舌尖上的L最近在几个方言群和语音教学社群里&#xff0c;反复看到有人发一句&#xff1a;“也说字母L&#xff1a;柔软的长舌”。初看以为是英语发音课笔记&#xff0c;点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码