SpringBoot中VO/DTO/PO的具體使用
1.概念敘述
- VO:View Object,主要用于展示層。它的作用是把某個(gè)指定前端頁(yè)面的所有數(shù)據(jù)封裝起來(lái)。他的作用主要是減少傳輸數(shù)據(jù)量大小和保護(hù)數(shù)據(jù)庫(kù)隱私數(shù)據(jù)(如用戶密碼、用戶郵箱等相關(guān)信息)不外泄,同時(shí)保護(hù)數(shù)據(jù)庫(kù)的結(jié)構(gòu)不外泄。
- DTO:Data Transfer Object,數(shù)據(jù)傳輸對(duì)象,用于展示層與服務(wù)層之間的數(shù)據(jù)傳輸對(duì)象。(注:實(shí)際開(kāi)發(fā)中還存在BO,其作用和DTO類(lèi)似,當(dāng)業(yè)務(wù)邏輯不復(fù)雜時(shí)一般會(huì)被合并。)
- PO:Persistant Object,持久化對(duì)象,和數(shù)據(jù)庫(kù)形成映射關(guān)系。簡(jiǎn)單說(shuō)PO就是每一個(gè)數(shù)據(jù)庫(kù)中的數(shù)據(jù)表,一個(gè)字段對(duì)應(yīng)PO中的一個(gè)變量。(也就是我們常用的Entities)
幾者之間的關(guān)系如下圖:

從前端頁(yè)面中收到JSON格式數(shù)據(jù),后端接口中將其封裝為一個(gè)VO對(duì)象;接口接收到VO對(duì)象后將其轉(zhuǎn)換為DTO對(duì)象,并調(diào)用業(yè)務(wù)類(lèi)方法對(duì)其進(jìn)行處理;然后處理為PO對(duì)象,調(diào)用Dao接口連接數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)訪問(wèn)(查詢、插入、更新等)。
后端從數(shù)據(jù)庫(kù)得到結(jié)果后,根據(jù)Dao接口將結(jié)果映射為PO對(duì)象,然后調(diào)用業(yè)務(wù)類(lèi)方法將其轉(zhuǎn)換為需要的DTO對(duì)象,再根據(jù)前端頁(yè)面實(shí)際需求,轉(zhuǎn)換為VO對(duì)象進(jìn)行返回。
2.類(lèi)型轉(zhuǎn)換
上述過(guò)程中,VO/DTO/PO等實(shí)體類(lèi)中字段常常會(huì)存在多數(shù)相同,根據(jù)業(yè)務(wù)需求少數(shù)不同。為避免頻繁的set和get操作對(duì)其進(jìn)行轉(zhuǎn)換,spring為我們提供了多種方法。
(1)使用BeanUtils:(springframework包下)
UserDto user = new UserDto ();
BeanUtils.copyProperties(userInfo ,user ,new String[]{"birthday"});上述代碼中,意思是將左邊UserInfo實(shí)體類(lèi)(可以視為一個(gè)VO對(duì)象)和UserDto實(shí)體類(lèi)類(lèi)(可以視為一個(gè)DTO對(duì)象)中一樣的值進(jìn)行賦值user對(duì)象中,new String[]{""}中是跳過(guò)賦值的字段,該屬性可以為空。
(2)使用BeanUtils:(Apache包下)
UserDto user = new UserDto (); BeanUtils.copyProperties(user,userInfo);
上述代碼中,意思是將右邊UserInfo實(shí)體類(lèi)(可以視為一個(gè)VO對(duì)象)和UserDto實(shí)體類(lèi)類(lèi)(可以視為一個(gè)DTO對(duì)象)中一樣的值進(jìn)行賦值user對(duì)象中。(和spring包下方法相反)
(3)使用modelMapper:
導(dǎo)入依賴:
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.9</version>
</dependency>配置文件:
@Configuration
public class ModelMapperConfig {
private Converter<Date, String> dateToStringConverter = new AbstractConverter<Date, String>() {
@Override
protected String convert(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return date == null ? null : simpleDateFormat.format(date);
}
};
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
// 官方配置說(shuō)明: http://modelmapper.org/user-manual/configuration/
// 完全匹配
modelMapper.getConfiguration().setFullTypeMatchingRequired(true);
// 匹配策略使用嚴(yán)格模式
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
modelMapper.addConverter(dateToStringConverter);
configureUser(modelMapper);
return modelMapper;
}
private void configureUser(ModelMapper modelMapper) {
//將dto轉(zhuǎn)為UserAccount實(shí)體類(lèi)
modelMapper.typeMap(UserInfor.class, UserAccount.class)
.addMappings(mapper -> mapper.map(UserInfor::getUsername, UserAccount::setUsername))
.addMappings(mapper -> mapper.map(UserInfor::getPassword, UserAccount::setPassword));
}使用:
UserAccount account= modelMapper.map(userInfo,UserAccount.class);
上述代碼,根據(jù)配置文件中configureUser方法中配置的字段,將兩個(gè)實(shí)體類(lèi)中的字段進(jìn)行復(fù)制賦值。
3.使用實(shí)例
下面我們模擬一個(gè)業(yè)務(wù):后端接口從前端中接收到用戶注冊(cè)數(shù)據(jù),進(jìn)行注冊(cè);前端調(diào)用查詢接口,獲取用戶的數(shù)據(jù)。
首先,我們定義VO、DTO、PO對(duì)象:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo implements Serializable {
//該實(shí)體類(lèi)為封裝好的前端傳輸頁(yè)面VO對(duì)象
@NotBlank(message = "用戶名不能為空")
private String Username;
@NotBlank(message = "密碼不能為空")
private String Password;
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO implements Serializable {
//該實(shí)體類(lèi)為業(yè)務(wù)處理DTO對(duì)象
private int Account;
private String Username;
private String Password;
private String Roles;
}@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user_account")
public class UserAccount implements Serializable {
//該實(shí)體類(lèi)為用戶賬號(hào)表對(duì)應(yīng)PO對(duì)象
@TableId
private int SerialNum;
private int Account;
private String Username;
private String Password;
private String Roles;
private String status;
private String registerDate;
}然后,我們編寫(xiě)用戶注冊(cè)相關(guān)代碼(基于springboot+mybatis plus),由于使用mybatis plus,此處省略mapper層代碼,僅展示serviceImpl和controller中代碼。
控制層:
//用戶注冊(cè)
@PostMapping("/register")
public CommonResult<Object> userRegister(@RequestBody @Valid UserInfo user){
int result = userService.userRegister(user);
if(result!=0){
return CommonResult.success(result);
}else {
return CommonResult.fail(result);
}
}業(yè)務(wù)處理:
@Override
public int userRegister(UserInfo user) {
if(accountMapper.selectCount(new QueryWrapper<UserAccount>().eq("username",user.getUsername()))!=0){
log.info("用戶名已存在");
return 0;
}
UserDTO userDTO = new UserDTO();
BeanUtils.copyProperties(userDTO,user);
//加密密碼
Md5Hash md5Hash = new Md5Hash(userDTO.getPassword(), userDTO.getUsername(),2);
userDTO.setPassword(md5Hash.toString());
//模擬生成賬號(hào)
userDTO.setAccount(12345678);
//賦予權(quán)限
userDTO.setRoles("user");
return accountMapper.insert(userDTO);
}最終,我們可以往數(shù)據(jù)庫(kù)中傳入一條用戶剛注冊(cè)的賬號(hào)數(shù)據(jù),status和RegisterDate等屬性取數(shù)據(jù)庫(kù)設(shè)置好的默認(rèn)值。
然后,我們?cè)俣x一個(gè)VO用于展示用戶的信息:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserVo implements Serializable {
//該VO用于展示用戶信息,去除了用戶密碼等敏感信息
private int serialNum;
private int account;
private String username;
}進(jìn)行用戶信息的查詢,獲取所有的用戶賬號(hào):
業(yè)務(wù)層:
public List<UserAccount> getAllUser() {
return accountMapper.selectList(null);
}控制層:
@GetMapping("/get/all")
public CommonResult<Object> getAllAccount() throws InvocationTargetException, IllegalAccessException {
//查詢所有數(shù)據(jù)
List<UserAccount> userAccountList = userService.getAllUser();
List<AdminInfo> resultList = new ArrayList<>();
//封裝為VO進(jìn)行展示
for(UserAccount u:userAccountList){
UserVo userVo = new UserVo();
BeanUtils.copyProperties(userVo,u);
resultList.add(userVo);
}
//根據(jù)序列號(hào)進(jìn)行排序,后注冊(cè)的放在最前面
resultList.sort(new Comparator<UserVo>() {
@Override
public int compare(UserVo o1, UserVo o2) {
return o2.getSerialNum() - o1.getSerialNum();
}
});
return new CommonResult<>(200,"賬號(hào)列表如下:",resultList,resultList.size());
}然后我們就可查詢得到所有的去除了敏感信息可用于展示的用戶賬號(hào)信息。
注:此處由于業(yè)務(wù)簡(jiǎn)單,沒(méi)有將PO對(duì)象轉(zhuǎn)換為DTO再轉(zhuǎn)換為VO。
到此這篇關(guān)于SpringBoot中VO/DTO/PO的具體使用的文章就介紹到這了,更多相關(guān)SpringBoot VO/DTO/PO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot+MySQL實(shí)現(xiàn)讀寫(xiě)分離的多種具體方案
在高并發(fā)和大數(shù)據(jù)量的場(chǎng)景下,數(shù)據(jù)庫(kù)成為了系統(tǒng)的瓶頸。為了提高數(shù)據(jù)庫(kù)的處理能力和性能,讀寫(xiě)分離成為了一種常用的解決方案,本文將介紹在Spring?Boot項(xiàng)目中實(shí)現(xiàn)MySQL數(shù)據(jù)庫(kù)讀寫(xiě)分離的多種具體方案,需要的朋友可以參考下2023-06-06
SpringBoot關(guān)于自定義注解實(shí)現(xiàn)接口冪等性方式
這篇文章主要介紹了SpringBoot關(guān)于自定義注解實(shí)現(xiàn)接口冪等性方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
Spring Boot使用Druid和監(jiān)控配置方法
Druid是Java語(yǔ)言中最好的數(shù)據(jù)庫(kù)連接池,并且能夠提供強(qiáng)大的監(jiān)控和擴(kuò)展功能。下面來(lái)說(shuō)明如何在 Spring Boot 中配置使用Druid2017-04-04
Java Collection集合遍歷運(yùn)行代碼實(shí)例
這篇文章主要介紹了Java Collection集合遍歷運(yùn)行代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
實(shí)例講解Java的設(shè)計(jì)模式編程中責(zé)任鏈模式的運(yùn)用
這篇文章主要介紹了Java的設(shè)計(jì)模式編程中責(zé)任鏈模式的運(yùn)用,講解了通過(guò)條件判斷結(jié)構(gòu)來(lái)分配不同對(duì)象的責(zé)任權(quán)限,需要的朋友可以參考下2016-02-02
java算法題解Leetcode763劃分字母區(qū)間示例
這篇文章主要為大家介紹了java算法題解Leetcode763劃分字母區(qū)間示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
idea 打包的jar運(yùn)行報(bào) "XXX中沒(méi)有主清單屬性"
這篇文章主要介紹了idea 打包的jar運(yùn)行報(bào) "XXX中沒(méi)有主清單屬性",文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Jenkins一鍵打包部署SpringBoot應(yīng)用
本文主要介紹了Jenkins一鍵打包部署SpringBoot應(yīng)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
SpringBoot+RabbitMQ+Redis實(shí)現(xiàn)商品秒殺的示例代碼
本文主要介紹了SpringBoot+RabbitMQ+Redis實(shí)現(xiàn)商品秒殺,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11

