SpringBoot中Entity、DTO、VO的通俗理解與實(shí)戰(zhàn)案例
SpringBoot中Entity、DTO、VO的通俗理解與實(shí)戰(zhàn)
剛接觸SpringBoot開發(fā)時(shí),你是不是也有過這樣的困惑:明明數(shù)據(jù)庫表對(duì)應(yīng)一個(gè)實(shí)體類就夠了,為什么還要搞出DTO、VO這些"花里胡哨"的東西?直接把數(shù)據(jù)庫實(shí)體類傳到前端不行嗎?
答案是:不行。就像我們寄快遞時(shí),不會(huì)把家里的保險(xiǎn)箱直接寄出去,而是會(huì)把里面的東西拿出來裝在快遞盒里(選需要的東西、去掉敏感信息)。Entity、DTO、VO就是這套"數(shù)據(jù)包裝"的不同容器,各自有明確的使用場景。今天咱們用最直白的案例,把這些概念講清楚。
一、Entity:和數(shù)據(jù)庫"一對(duì)一"的"原始數(shù)據(jù)袋"
定義:Entity(實(shí)體類)是數(shù)據(jù)庫表的"鏡像",字段和數(shù)據(jù)庫表一一對(duì)應(yīng),它的使命就是和數(shù)據(jù)庫打交道——存數(shù)據(jù)、取數(shù)據(jù)。
核心作用:作為持久層(Repository層)操作的載體,負(fù)責(zé)數(shù)據(jù)在Java對(duì)象和數(shù)據(jù)庫表之間的映射。
實(shí)戰(zhàn)案例:用戶表對(duì)應(yīng)的Entity
假設(shè)數(shù)據(jù)庫有張user表,結(jié)構(gòu)如下:
| 字段名 | 類型 | 說明 |
|---|---|---|
| id | bigint | 主鍵 |
| username | varchar(50) | 用戶名 |
| password | varchar(100) | 加密密碼 |
| varchar(100) | 郵箱 | |
| create_time | datetime | 創(chuàng)建時(shí)間 |
| 對(duì)應(yīng)的Entity類: |
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;
// 與數(shù)據(jù)庫表user映射
@Entity
@Table(name = "user")
@Data // Lombok注解,自動(dòng)生成getter、setter等
public class UserEntity {
// 主鍵
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 用戶名,對(duì)應(yīng)表中username字段
private String username;
// 密碼(加密存儲(chǔ)),對(duì)應(yīng)表中password字段
private String password;
// 郵箱,對(duì)應(yīng)表中email字段
private String email;
// 創(chuàng)建時(shí)間,對(duì)應(yīng)表中create_time字段
@Column(name = "create_time")
private LocalDateTime createTime;
}注意:Entity只應(yīng)該在DAO層(數(shù)據(jù)訪問層)和Service層內(nèi)部使用,絕對(duì)不能直接傳到前端!因?yàn)樗舾行畔ⅲㄈ鏿assword)和前端可能不需要的字段(如createTime)。
二、DTO:服務(wù)間數(shù)據(jù)傳輸?shù)?quot;快遞盒"
定義:DTO(Data Transfer Object,數(shù)據(jù)傳輸對(duì)象)用于不同服務(wù)之間、或服務(wù)內(nèi)部不同層之間傳遞數(shù)據(jù)。它就像快遞盒,只裝對(duì)方需要的數(shù)據(jù),不多不少。
核心作用:1. 減少數(shù)據(jù)傳輸量(只傳必要字段);2. 隔離不同服務(wù)的實(shí)體結(jié)構(gòu)(避免一個(gè)服務(wù)改實(shí)體影響另一個(gè)服務(wù))。
實(shí)戰(zhàn)案例:用戶注冊(cè)的DTO
用戶注冊(cè)時(shí),前端需要傳用戶名、密碼、郵箱,但不需要傳id(數(shù)據(jù)庫自增)和createTime(后端生成)。這時(shí)候就需要一個(gè)UserRegisterDTO:
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Email;
@Data
public class UserRegisterDTO {
// 用戶名不能為空
@NotBlank(message = "用戶名不能為空")
private String username;
// 密碼不能為空
@NotBlank(message = "密碼不能為空")
private String password;
// 郵箱格式要正確
@NotBlank(message = "郵箱不能為空")
@Email(message = "郵箱格式不正確")
private String email;
}Service層接收DTO并轉(zhuǎn)換為Entity:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void register(UserRegisterDTO registerDTO) {
// 1. DTO轉(zhuǎn)換為Entity
UserEntity userEntity = new UserEntity();
userEntity.setUsername(registerDTO.getUsername());
// 密碼加密(實(shí)際開發(fā)中一定要加密?。?
userEntity.setPassword(encryptPassword(registerDTO.getPassword()));
userEntity.setEmail(registerDTO.getEmail());
userEntity.setCreateTime(LocalDateTime.now());
// 2. 保存到數(shù)據(jù)庫
userRepository.save(userEntity);
}
// 密碼加密方法(示例)
private String encryptPassword(String rawPassword) {
return new BCryptPasswordEncoder().encode(rawPassword);
}
}三、VO:給前端展示的"最終商品"
定義:VO(View Object,視圖對(duì)象)是專門給前端頁面展示用的數(shù)據(jù)對(duì)象。它就像商店里的商品展示,只展示用戶想看到的信息,隱藏內(nèi)部細(xì)節(jié)。
核心作用:定制前端需要的展示數(shù)據(jù),比如字段別名、組合字段等。
實(shí)戰(zhàn)案例:用戶詳情的VO
前端展示用戶詳情時(shí),需要id、用戶名、郵箱,但不需要password和createTime。這時(shí)候用UserVO:
import lombok.Data;
@Data
public class UserVO {
private Long id;
private String username;
private String email;
// 可以增加前端需要的組合字段,比如"用戶標(biāo)簽"
private String userTag;
}Service層查詢Entity并轉(zhuǎn)換為VO:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public UserVO getUserDetail(Long userId) {
// 1. 從數(shù)據(jù)庫查詢Entity
UserEntity userEntity = userRepository.findById(userId)
.orElseThrow(() -> new RuntimeException("用戶不存在"));
// 2. Entity轉(zhuǎn)換為VO
UserVO userVO = new UserVO();
userVO.setId(userEntity.getId());
userVO.setUsername(userEntity.getUsername());
userVO.setEmail(userEntity.getEmail());
// 定制前端需要的組合字段
userVO.setUserTag("普通用戶");
return userVO;
}
}Controller層返回VO給前端:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{userId}")
public UserVO getUserDetail(@PathVariable Long userId) {
return userService.getUserDetail(userId);
}
}四、三者轉(zhuǎn)換的"小技巧"
手動(dòng)轉(zhuǎn)換(setter/getter)雖然直觀,但字段多了很麻煩。實(shí)際開發(fā)中推薦用工具類:
- ModelMapper:自動(dòng)映射同名字段,支持自定義映射規(guī)則。
- MapStruct:編譯期生成映射代碼,性能更好,需要寫接口。
ModelMapper示例:
// 1. 引入依賴
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.2.0</version>
</dependency>
// 2. 配置Bean
@Configuration
public class ModelMapperConfig {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
// 3. 服務(wù)中使用
@Service
public class UserService {
@Autowired
private ModelMapper modelMapper;
public UserVO getUserDetail(Long userId) {
UserEntity userEntity = userRepository.findById(userId).orElseThrow(...);
// 自動(dòng)轉(zhuǎn)換Entity到VO
return modelMapper.map(userEntity, UserVO.class);
}
}五、總結(jié):一句話分清三者
| 對(duì)象類型 | 使用場景 | 核心目的 |
|---|---|---|
| Entity | DAO層 ↔ 數(shù)據(jù)庫 | 和數(shù)據(jù)庫表一一對(duì)應(yīng),負(fù)責(zé)數(shù)據(jù)持久化 |
| DTO | 服務(wù)間/層間數(shù)據(jù)傳輸 | 減少傳輸量,隔離服務(wù)依賴 |
| VO | Service層 ↔ 前端 | 定制前端展示數(shù)據(jù),隱藏敏感信息 |
| 記?。?strong>邊界清晰是代碼整潔的關(guān)鍵。用對(duì)Entity、DTO、VO,能讓你的SpringBoot項(xiàng)目結(jié)構(gòu)更清晰,維護(hù)性大大提升。 |
到此這篇關(guān)于SpringBoot中Entity、DTO、VO的通俗理解與實(shí)戰(zhàn)案例的文章就介紹到這了,更多相關(guān)SpringBoot Entity、DTO、VO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決JavaEE開發(fā)中字符編碼出現(xiàn)亂碼的問題
下面小編就為大家?guī)硪黄鉀QJavaEE開發(fā)中字符編碼出現(xiàn)亂碼的問題。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
Java中的while無限循環(huán)結(jié)構(gòu)及實(shí)例
這篇文章主要介紹了Java中的while無限循環(huán)結(jié)構(gòu)及實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
SpringBoot服務(wù)獲取Pod當(dāng)前IP的兩種方案
在 Kubernetes 集群中,Spring Boot 服務(wù)獲取 Pod 當(dāng)前 IP 的方案主要有兩種,通過環(huán)境變量注入 或 通過 Java 代碼動(dòng)態(tài)獲取網(wǎng)絡(luò)接口 IP,下面我們來看看具體實(shí)現(xiàn)方法吧2025-06-06
Java對(duì)xls文件進(jìn)行讀寫操作示例代碼
Java開發(fā)項(xiàng)目中經(jīng)常會(huì)碰到處理Excel文件中數(shù)據(jù)的情況,下面這篇文章主要給大家介紹了利用Java對(duì)xls文件進(jìn)行讀寫操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-08-08

