💡 一则也许对你有用的小广告 🏆
欢迎飞飞程序员 ,你将获得:专属的实战项目(已更新的所有会员标识的项目都能学习) / 1v1 提问 / Java 学习路线 / PHP 学习路线 / 学习打卡 / 社群讨论
截止目前, 飞飞 正在疯狂爆肝实战项目,后续还会上新更多项目,目标是将所学知识开发成项目并且分享给大家,如知识付费系统, Ai系统, CMS系统,在线商城系统,等等 ,欢迎点击围观
一句话:谁跟数据库打交道,谁给前端看
数据库表 ←→ DO(数据的"仓库形态")
↑↓
Mapper(搬运工,只管操作 DO)
↓
转成 VO(数据的"展示形态")
↓
前端页面
- Mapper 是操作者:只认 DO,它的一切增删改查都以 DO 为输入 / 输出
- DO 是 Mapper 眼中的数据:和数据库表一一对应,是 Mapper 与数据库之间的 "翻译件"
- VO 是前端眼中的数据:Mapper 永远不碰 VO,VO 由 Service 层从 DO 转换而来
关键结论
1. Mapper 和 VO 之间没有直接关系
Mapper 的入参、出参必须是 DO(或基本类型),它根本不知道 VO 的存在。你不可能写 userMapper.selectById() 直接返回 VO。
2. DO → VO 的转换发生在 Service 层,不是 Mapper 层
// Mapper:只操作 DO
public interface UserMapper extends BaseMapper<UserDO> {
}
// Service:负责把 DO 转成 VO
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public UserVO getUser(Long id) {
// 1. Mapper 查出的是 DO
UserDO userDO = userMapper.selectById(id);
// 2. Service 层手动转成 VO(隐藏敏感字段)
UserVO vo = new UserVO();
vo.setId(userDO.getId());
vo.setName(userDO.getName());
// 不 set password —— 敏感字段不传给前端
return vo;
}
}
3. 一条完整链路
前端请求 /user/1
↓
Controller 接收
↓
Service 调 userMapper.selectById(1) → 拿到 UserDO(含 password 等所有字段)
↓
Service 把 UserDO 转成 UserVO(剔除敏感字段、拼装展示需要的数据)
↓
返回 UserVO 给前端
为什么 Mapper 不能直接用 VO
- 职责隔离:Mapper 就该 "面向表",VO 该 "面向页面",混在一起会让 Mapper 被前端需求绑架(前端要什么字段就改 Mapper)
- 安全性:DO 常有敏感字段,直接用 DO 返回前端等于裸奔;VO 可以精确控制暴露哪些字段
- 灵活性:VO 可以自由拼装(比如把
userDO + orderDO 拼成一个 "用户订单 VO"),Mapper 做不到
简化记忆:Mapper 管 "存取 DO",VO 管 "给人看",两者通过 Service 层这座桥连接,永远不直接握手。