最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中DTO和VO的區(qū)別舉例詳解

 更新時(shí)間:2025年12月25日 10:53:33   作者:趁你還年輕_  
在Java開發(fā)中,VO和DTO都是用于數(shù)據(jù)傳輸?shù)膶ο?但它們的含義和用途有所不同,這篇文章主要介紹了Java中DTO和VO區(qū)別的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

DTO(Data Transfer Object)和 VO(Value Object / View Object)是 Java 開發(fā)中用于不同層次間數(shù)據(jù)傳遞的對象,但它們的設(shè)計(jì)目的和使用場景有本質(zhì)區(qū)別。

一、概念定義

DTO(Data Transfer Object)

  • 定義:用于在不同層或系統(tǒng)之間傳輸數(shù)據(jù)的對象

  • 核心作用:減少遠(yuǎn)程調(diào)用次數(shù),打包多個(gè)數(shù)據(jù)一次性傳輸

  • 典型場景:Service 層返回?cái)?shù)據(jù)給 Controller 層、微服務(wù)間調(diào)用

VO(Value Object / View Object)

  • 定義:用于前端展示的數(shù)據(jù)對象,封裝頁面需要的數(shù)據(jù)

  • 核心作用:適配前端展示需求,隱藏后端敏感字段

  • 典型場景:Controller 層返回給前端

二、核心區(qū)別對比表

對比維度DTO (Data Transfer Object)VO (View Object)
設(shè)計(jì)目的減少網(wǎng)絡(luò)調(diào)用,批量傳輸數(shù)據(jù)適配前端展示需求
數(shù)據(jù)范圍可能包含多個(gè)聚合的數(shù)據(jù)針對單個(gè)頁面/組件定制
數(shù)據(jù)敏感度可包含內(nèi)部字段必須隱藏敏感字段(密碼、金額等)
使用層次Service ↔ Controller、微服務(wù)間調(diào)用Controller ↔ 前端
字段格式化通常是原始數(shù)據(jù)類型包含格式化后的數(shù)據(jù)(如日期、金額顯示格式)
變更頻率相對穩(wěn)定隨前端需求頻繁變化

三、詳細(xì)說明與代碼示例

場景:用戶訂單詳情查詢

數(shù)據(jù)庫實(shí)體(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-凍結(jié)
}

DTO(Service 層返回)

@Data
public class UserOrderDTO {
    // 用戶基本信息
    private Long userId;
    private String username;
    private String email; // 可能包含敏感信息
    
    // 訂單列表(跨聚合數(shù)據(jù))
    private List<OrderDTO> orders;
    
    // 統(tǒng)計(jì)信息
    private Integer totalOrderCount;
    private BigDecimal totalAmount;
    
    // 原始數(shù)據(jù)類型
    private LocalDateTime userCreateTime;
}

使用場景:Service 層查詢用戶和訂單數(shù)據(jù),打包返回給 Controller

@Service
public class UserOrderService {
    public UserOrderDTO getUserWithOrders(Long userId) {
        UserDO user = userDao.findById(userId);
        List<OrderDO> orders = orderDao.findByUserId(userId);
        
        // 轉(zhuǎn)換并聚合數(shù)據(jù)
        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
    
    // 訂單數(shù)據(jù)(按需展示)
    private List<OrderVO> orders;
    
    // 格式化后的數(shù)據(jù)
    private String formattedTotalAmount; // "¥9,999.00"
    private String userCreateTimeDesc; // "2025-01-15 12:00"
    
    // 前端狀態(tài)(計(jì)算得出)
    private String userStatusText; // "正常" 而非 1
    
    // 不包含:password, phone, raw status
}

使用場景:Controller 層轉(zhuǎn)換 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 轉(zhuǎn)換(關(guān)鍵一步?。?
        UserOrderVO vo = new UserOrderVO();
        vo.setUserId(dto.getUserId());
        vo.setUsername(dto.getUsername());
        
        // 1. 脫敏處理
        vo.setMaskedEmail(maskEmail(dto.getEmail())); // a****@gmail.com
        
        // 2. 數(shù)據(jù)格式化
        vo.setFormattedTotalAmount(formatCurrency(dto.getTotalAmount()));
        vo.setUserCreateTimeDesc(formatDateTime(dto.getUserCreateTime()));
        
        // 3. 狀態(tài)轉(zhuǎn)換
        vo.setUserStatusText(convertStatusToText(user.getStatus())); // "正常"
        
        // 4. 按需過濾字段
        vo.setOrders(convertToOrderVO(dto.getOrders()));
        
        return ResultVO.success(vo);
    }
}

四、常見誤區(qū)與反例

? 誤區(qū) 1:DTO 和 VO 混用

// 錯(cuò)誤:Controller 直接返回 DTO,暴露敏感信息
@RestController
public class UserController {
    public UserOrderDTO getUserOrders(Long userId) {
        return userOrderService.getUserWithOrders(userId); // ? 暴露了 password 等字段
    }
}

? 誤區(qū) 2:VO 包含業(yè)務(wù)邏輯

// 錯(cuò)誤:VO 包含計(jì)算邏輯
@Data
public class UserOrderVO {
    private BigDecimal orderAmount;
    private BigDecimal discount;
    
    // ? VO 只應(yīng)承載數(shù)據(jù),不應(yīng)有業(yè)務(wù)方法
    public BigDecimal getPayAmount() {
        return orderAmount.subtract(discount); // 計(jì)算應(yīng)在后端完成
    }
}

? 誤區(qū) 3:過度使用 DTO 導(dǎo)致類爆炸

// 錯(cuò)誤:為每個(gè)方法都創(chuàng)建 DTO
public class UserOrderService {
    public UserOrderDTO1 method1() { ... }
    public UserOrderDTO2 method2() { ... }
    public UserOrderDTO3 method3() { ... } // 維護(hù)噩夢
}

? 正確做法:合理復(fù)用 DTO,僅在字段差異大時(shí)創(chuàng)建新類

五、與其他對象的關(guān)系

在分層架構(gòu)中,完整的對象體系如下:

完整對象體系

縮寫全稱作用位置示例
DOData Object持久層 ↔ 數(shù)據(jù)庫UserDO(對應(yīng)數(shù)據(jù)庫表)
DTOData Transfer ObjectService ↔ ControllerUserOrderDTO(聚合數(shù)據(jù))
VOView ObjectController ↔ 前端UserOrderVO(脫敏+格式化)
BOBusiness ObjectService 層內(nèi)部OrderBO(處理業(yè)務(wù)邏輯)
POPersistant Object同 DO(老叫法)UserPO
AOApplication Object應(yīng)用層參數(shù)LoginAO(登錄參數(shù))

六、最佳實(shí)踐總結(jié)

1. 轉(zhuǎn)換時(shí)機(jī)明確

// 分層轉(zhuǎn)換
DAO層 → Service層 → Controller層 → 前端
  DO   →   DTO    →    VO      → JSON

2. 命名規(guī)范

// DTO 命名:業(yè)務(wù) + DTO
UserDTO, OrderDTO, UserOrderDTO
 
// VO 命名:頁面/組件 + VO
OrderListVO, OrderDetailVO, UserProfileVO

3. 工具類輔助轉(zhuǎn)換

@Component
public class UserConverter {
    
    // DO → DTO
    public UserDTO toDTO(UserDO userDO) {
        UserDTO dto = new UserDTO();
        BeanUtils.copyProperties(userDO, dto);
        return dto;
    }
    
    // DTO → VO(關(guān)鍵:脫敏+格式化)
    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)一返回結(jié)構(gòu)

@Data
public class ResultVO<T> {
    private int code;      // 狀態(tài)碼
    private String message; // 提示信息
    private T data;        // 實(shí)際數(shù)據(jù)(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;
    }
}

七、總結(jié)

規(guī)則DTOVO
核心目標(biāo)傳輸效率(減少調(diào)用次數(shù))展示安全(適配前端+脫敏)
數(shù)據(jù)來源可能跨多個(gè)聚合通常基于單個(gè) DTO
是否脫敏? 否必須脫敏
是否格式化? 原始數(shù)據(jù)前端友好格式
位置Service → ControllerController → 前端

設(shè)計(jì)原則先設(shè)計(jì) VO 滿足前端需求,再反推 DTO 需要聚合哪些數(shù)據(jù),最后確定 DO 的數(shù)據(jù)庫設(shè)計(jì)。

一句話總結(jié)DTO 為服務(wù)層效率而生,VO 為前端安全而生。

到此這篇關(guān)于Java中DTO和VO區(qū)別的文章就介紹到這了,更多相關(guān)Java DTO和VO區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文詳解如何在idea中快速搭建一個(gè)Spring?Boot項(xiàng)目

    一文詳解如何在idea中快速搭建一個(gè)Spring?Boot項(xiàng)目

    IntelliJ IDEA作為Java開發(fā)者的?首選IDE?,深度集成Spring Boot支持,可一鍵生成項(xiàng)目骨架、智能配置依賴,這篇文章主要介紹了如何在idea中快速搭建一個(gè)Spring?Boot項(xiàng)目的相關(guān)資料,需要的朋友可以參考下
    2025-06-06
  • Spring AOP定義Before增加實(shí)戰(zhàn)案例詳解

    Spring AOP定義Before增加實(shí)戰(zhàn)案例詳解

    這篇文章主要介紹了Spring AOP定義Before增加,結(jié)合實(shí)例形式詳細(xì)分析了Spring面向切面AOP定義Before增加相關(guān)定義與使用技巧,需要的朋友可以參考下
    2020-01-01
  • skywalking分布式服務(wù)調(diào)用鏈路追蹤APM應(yīng)用監(jiān)控

    skywalking分布式服務(wù)調(diào)用鏈路追蹤APM應(yīng)用監(jiān)控

    這篇文章主要為大家介紹了skywalking分布式服務(wù)調(diào)用鏈路追蹤APM應(yīng)用監(jiān)控的功能使用說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-03-03
  • 一文了解Spring中攔截器的原理與使用

    一文了解Spring中攔截器的原理與使用

    在web開發(fā)中,攔截器是經(jīng)常用到的功能。它可以幫我們預(yù)先設(shè)置數(shù)據(jù)以及統(tǒng)計(jì)方法的執(zhí)行效率等等。今天就來詳細(xì)的談一下spring中的攔截器,需要的可以參考一下
    2022-06-06
  • Spring Cloud Ribbon的踩坑記錄與原理詳析

    Spring Cloud Ribbon的踩坑記錄與原理詳析

    這篇文章主要給大家介紹了關(guān)于Spring Cloud Ribbon踩坑記錄與原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • SpringCloud?Alibaba環(huán)境集成之nacos詳解

    SpringCloud?Alibaba環(huán)境集成之nacos詳解

    Spring?Cloud?Alibaba提供了越來越完善的各類微服務(wù)治理組件,比如分布式服務(wù)配置與注冊中心nacos,服務(wù)限流、熔斷組件sentinel等,本篇先來介紹SpringCloud?Alibaba環(huán)境集成之nacos詳解,需要的朋友可以參考下
    2023-03-03
  • Java實(shí)現(xiàn)在Word指定位置插入分頁符

    Java實(shí)現(xiàn)在Word指定位置插入分頁符

    在Word插入分頁符可以在指定段落后插入,也可以在特定文本位置處插入。本文將以Java代碼來操作以上兩種文檔分頁需求,需要的可以參考一下
    2022-04-04
  • 詳解什么是Java線程池的拒絕策略?

    詳解什么是Java線程池的拒絕策略?

    今天給大家總結(jié)一下線程池的拒絕策略,文中有非常詳細(xì)的介紹及代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • 利用Java實(shí)現(xiàn)玩家打怪小游戲的完整過程

    利用Java實(shí)現(xiàn)玩家打怪小游戲的完整過程

    這篇文章主要介紹了如何使用Java創(chuàng)建一個(gè)簡單的“打怪小游戲”,游戲中的角色分為法師、戰(zhàn)士、BOSS和一個(gè)Team類,代碼展示了如何通過面向?qū)ο缶幊虂韺?shí)現(xiàn)一個(gè)基本的戰(zhàn)斗系統(tǒng),需要的朋友可以參考下
    2024-12-12
  • Mybatis框架中Interceptor接口的使用說明

    Mybatis框架中Interceptor接口的使用說明

    這篇文章主要介紹了Mybatis框架中Interceptor接口的使用說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評論

永新县| 土默特右旗| 兴义市| 宜章县| 仁布县| 泾源县| 沂水县| 唐山市| 朝阳区| 平泉县| 忻州市| 特克斯县| 祁阳县| 临潭县| 淮南市| 滨海县| 航空| 巴塘县| 和硕县| 华容县| 宁海县| 沛县| 嘉祥县| 运城市| 昌吉市| 平顶山市| 海阳市| 柘城县| 梨树县| 项城市| 赣榆县| 大同市| 依兰县| 扎赉特旗| 嘉祥县| 家居| 宝兴县| 沾益县| 江华| 托克逊县| 曲阜市|