Java中DTO和VO的區(qū)別舉例詳解
前言
DTO(Data Transfer Object)和 VO(Value Object / View Object)是 Java 開發(fā)中用于不同層次間數據傳遞的對象,但它們的設計目的和使用場景有本質區(qū)別。
一、概念定義
DTO(Data Transfer Object)
定義:用于在不同層或系統(tǒng)之間傳輸數據的對象
核心作用:減少遠程調用次數,打包多個數據一次性傳輸
典型場景:Service 層返回數據給 Controller 層、微服務間調用
VO(Value Object / View Object)
定義:用于前端展示的數據對象,封裝頁面需要的數據
核心作用:適配前端展示需求,隱藏后端敏感字段
典型場景:Controller 層返回給前端
二、核心區(qū)別對比表
| 對比維度 | DTO (Data Transfer Object) | VO (View Object) |
|---|---|---|
| 設計目的 | 減少網絡調用,批量傳輸數據 | 適配前端展示需求 |
| 數據范圍 | 可能包含多個聚合的數據 | 針對單個頁面/組件定制 |
| 數據敏感度 | 可包含內部字段 | 必須隱藏敏感字段(密碼、金額等) |
| 使用層次 | Service ↔ Controller、微服務間調用 | Controller ↔ 前端 |
| 字段格式化 | 通常是原始數據類型 | 包含格式化后的數據(如日期、金額顯示格式) |
| 變更頻率 | 相對穩(wěn)定 | 隨前端需求頻繁變化 |
三、詳細說明與代碼示例
場景:用戶訂單詳情查詢
數據庫實體(DO - Data Object)
@Entity
@Table(name = "t_user")
public class UserDO {
private Long id;
private String username;
private String password; // 敏感字段
private String email;
private String phone;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private Integer status; // 0-注銷 1-正常 2-凍結
}DTO(Service 層返回)
@Data
public class UserOrderDTO {
// 用戶基本信息
private Long userId;
private String username;
private String email; // 可能包含敏感信息
// 訂單列表(跨聚合數據)
private List<OrderDTO> orders;
// 統(tǒng)計信息
private Integer totalOrderCount;
private BigDecimal totalAmount;
// 原始數據類型
private LocalDateTime userCreateTime;
}使用場景:Service 層查詢用戶和訂單數據,打包返回給 Controller
@Service
public class UserOrderService {
public UserOrderDTO getUserWithOrders(Long userId) {
UserDO user = userDao.findById(userId);
List<OrderDO> orders = orderDao.findByUserId(userId);
// 轉換并聚合數據
UserOrderDTO dto = new UserOrderDTO();
dto.setUserId(user.getId());
dto.setUsername(user.getUsername());
dto.setEmail(user.getEmail()); // 直接暴露原始郵箱
dto.setOrders(convertOrders(orders));
dto.setTotalOrderCount(orders.size());
return dto;
}
}VO(Controller 層返回前端)
@Data
public class UserOrderVO {
// 前端展示字段(脫敏)
private Long userId;
private String username;
private String maskedEmail; // 脫敏:a****@gmail.com
// 訂單數據(按需展示)
private List<OrderVO> orders;
// 格式化后的數據
private String formattedTotalAmount; // "¥9,999.00"
private String userCreateTimeDesc; // "2025-01-15 12:00"
// 前端狀態(tài)(計算得出)
private String userStatusText; // "正常" 而非 1
// 不包含:password, phone, raw status
}使用場景:Controller 層轉換 DTO 為 VO,適配前端展示
@RestController
@RequestMapping("/api/users")
public class UserOrderController {
@Resource
private UserOrderService userOrderService;
@GetMapping("/{userId}/orders")
public ResultVO<UserOrderVO> getUserOrders(@PathVariable Long userId) {
UserOrderDTO dto = userOrderService.getUserWithOrders(userId);
// DTO → VO 轉換(關鍵一步!)
UserOrderVO vo = new UserOrderVO();
vo.setUserId(dto.getUserId());
vo.setUsername(dto.getUsername());
// 1. 脫敏處理
vo.setMaskedEmail(maskEmail(dto.getEmail())); // a****@gmail.com
// 2. 數據格式化
vo.setFormattedTotalAmount(formatCurrency(dto.getTotalAmount()));
vo.setUserCreateTimeDesc(formatDateTime(dto.getUserCreateTime()));
// 3. 狀態(tài)轉換
vo.setUserStatusText(convertStatusToText(user.getStatus())); // "正常"
// 4. 按需過濾字段
vo.setOrders(convertToOrderVO(dto.getOrders()));
return ResultVO.success(vo);
}
}四、常見誤區(qū)與反例
? 誤區(qū) 1:DTO 和 VO 混用
// 錯誤:Controller 直接返回 DTO,暴露敏感信息
@RestController
public class UserController {
public UserOrderDTO getUserOrders(Long userId) {
return userOrderService.getUserWithOrders(userId); // ? 暴露了 password 等字段
}
}? 誤區(qū) 2:VO 包含業(yè)務邏輯
// 錯誤:VO 包含計算邏輯
@Data
public class UserOrderVO {
private BigDecimal orderAmount;
private BigDecimal discount;
// ? VO 只應承載數據,不應有業(yè)務方法
public BigDecimal getPayAmount() {
return orderAmount.subtract(discount); // 計算應在后端完成
}
}? 誤區(qū) 3:過度使用 DTO 導致類爆炸
// 錯誤:為每個方法都創(chuàng)建 DTO
public class UserOrderService {
public UserOrderDTO1 method1() { ... }
public UserOrderDTO2 method2() { ... }
public UserOrderDTO3 method3() { ... } // 維護噩夢
}? 正確做法:合理復用 DTO,僅在字段差異大時創(chuàng)建新類
五、與其他對象的關系
在分層架構中,完整的對象體系如下:

完整對象體系
| 縮寫 | 全稱 | 作用位置 | 示例 |
|---|---|---|---|
| DO | Data Object | 持久層 ↔ 數據庫 | UserDO(對應數據庫表) |
| DTO | Data Transfer Object | Service ↔ Controller | UserOrderDTO(聚合數據) |
| VO | View Object | Controller ↔ 前端 | UserOrderVO(脫敏+格式化) |
| BO | Business Object | Service 層內部 | OrderBO(處理業(yè)務邏輯) |
| PO | Persistant Object | 同 DO(老叫法) | UserPO |
| AO | Application Object | 應用層參數 | LoginAO(登錄參數) |
六、最佳實踐總結
1. 轉換時機明確
// 分層轉換 DAO層 → Service層 → Controller層 → 前端 DO → DTO → VO → JSON
2. 命名規(guī)范
// DTO 命名:業(yè)務 + DTO UserDTO, OrderDTO, UserOrderDTO // VO 命名:頁面/組件 + VO OrderListVO, OrderDetailVO, UserProfileVO
3. 工具類輔助轉換
@Component
public class UserConverter {
// DO → DTO
public UserDTO toDTO(UserDO userDO) {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(userDO, dto);
return dto;
}
// DTO → VO(關鍵:脫敏+格式化)
public UserVO toVO(UserDTO userDTO) {
UserVO vo = new UserVO();
vo.setUserId(userDTO.getUserId());
vo.setUsername(userDTO.getUsername());
vo.setMaskedEmail(this.maskEmail(userDTO.getEmail()));
vo.setStatusText(this.convertStatus(userDTO.getStatus()));
return vo;
}
private String maskEmail(String email) {
// 脫敏邏輯
return email.replaceAll("(?<=.).(?=.*@)", "*");
}
}4. 統(tǒng)一返回結構
@Data
public class ResultVO<T> {
private int code; // 狀態(tài)碼
private String message; // 提示信息
private T data; // 實際數據(VO/DTO)
public static <T> ResultVO<T> success(T data) {
ResultVO<T> result = new ResultVO<>();
result.setCode(200);
result.setMessage("success");
result.setData(data);
return result;
}
}七、總結
| 規(guī)則 | DTO | VO |
|---|---|---|
| 核心目標 | 傳輸效率(減少調用次數) | 展示安全(適配前端+脫敏) |
| 數據來源 | 可能跨多個聚合 | 通?;趩蝹€ DTO |
| 是否脫敏 | ? 否 | ? 必須脫敏 |
| 是否格式化 | ? 原始數據 | ? 前端友好格式 |
| 位置 | Service → Controller | Controller → 前端 |
設計原則:先設計 VO 滿足前端需求,再反推 DTO 需要聚合哪些數據,最后確定 DO 的數據庫設計。
一句話總結:DTO 為服務層效率而生,VO 為前端安全而生。
到此這篇關于Java中DTO和VO區(qū)別的文章就介紹到這了,更多相關Java DTO和VO區(qū)別內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
一文詳解如何在idea中快速搭建一個Spring?Boot項目
IntelliJ IDEA作為Java開發(fā)者的?首選IDE?,深度集成Spring Boot支持,可一鍵生成項目骨架、智能配置依賴,這篇文章主要介紹了如何在idea中快速搭建一個Spring?Boot項目的相關資料,需要的朋友可以參考下2025-06-06
Spring AOP定義Before增加實戰(zhàn)案例詳解
這篇文章主要介紹了Spring AOP定義Before增加,結合實例形式詳細分析了Spring面向切面AOP定義Before增加相關定義與使用技巧,需要的朋友可以參考下2020-01-01
skywalking分布式服務調用鏈路追蹤APM應用監(jiān)控
這篇文章主要為大家介紹了skywalking分布式服務調用鏈路追蹤APM應用監(jiān)控的功能使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03
SpringCloud?Alibaba環(huán)境集成之nacos詳解
Spring?Cloud?Alibaba提供了越來越完善的各類微服務治理組件,比如分布式服務配置與注冊中心nacos,服務限流、熔斷組件sentinel等,本篇先來介紹SpringCloud?Alibaba環(huán)境集成之nacos詳解,需要的朋友可以參考下2023-03-03

