Познакомимся с различными методами преобразования классов сущностей и поиграем с преобразованием между VO, PO и DTO.
Познакомимся с различными методами преобразования классов сущностей и поиграем с преобразованием между VO, PO и DTO.

Познакомимся с различными методами преобразования классов сущностей и поиграем с преобразованием между VO, PO и DTO.

Прелюдия

Для начала введем понятия ВО ПО ДТО и так далее. Чтобы облегчить наше понимание.

Прежде всего, давайте поговорим о наиболее часто используемых из них — DTO и VO.

С развитием Интернета все более популярной становится модель разработки с разделением фронтенда и бэкэнда. В процессе взаимодействия внешних и внутренних данных для обеспечения безопасности и эффективности данных обычно используются DTO и VO для инкапсуляции данных.

DTO (объект передачи данных) и VO (объект значения) — это шаблоны проектирования, используемые для инкапсуляции данных и предоставления услуг.

Здесь нужно отметить, что это ВО Я где-то видел, что это написано так.:VO(View Object):просмотреть объект,для уровня представления,Его функция — инкапсулировать все данные указанной страницы (или компонента). После поиска большого количества информации по этому вопросу я получил следующее объяснение: хотя "View Object" Также допустимое объяснение, но в контексте объектно-ориентированного проектирования и доменно-ориентированного проектирования (DDD), VO. обычно относится к "Value Объект». Какая интерпретация будет выбрана, зависит от конкретного контекста и сценария использования.

  • При обсуждении структур данных и бизнес-логики VO, скорее всего, относится к «Объекту значения».
  • При обсуждении пользовательских интерфейсов и архитектуры MVC VO может ссылаться на «Просмотр объекта».

Поэтому лучше всего использовать контекст, чтобы определить, относится ли он к «Объекту значения» или «Объекту представления».

Их основные отличия:

  • DTO: используется для упаковки объекта передачи данных, вы можете добавить Преобразование в базу данных данных в формат, требуемый интерфейсом, который облегчает передачу данных между интерфейсом и сервером.
  • VO:Используется для инкапсуляции значенийобъект,Различные атрибуты данных могут быть инкапсулированы в соответствии с конкретными потребностями.,удобный Главная страницаотображатьивзаимодействие。

DTO да Что-то вродеобъект передачи данных,Используется для хранения данных в базе данныхПреобразование данных в формат, требуемый интерфейсом,удобный Данные между интерфейсом и серверомвзаимодействие。и VO да Что-то вродеценитьобъект,Используется для инкапсуляции различных атрибутов данных.,удобныйГлавная страницаотображатьивзаимодействие。

Их также очень легко спутать.

Можно сказать, что,Для большинства сценариев применения,Значения атрибутов DTOиVO в основном одинаковы.,и И они обычнодаPOJO,Так что раз есть ВО,Зачем вам нужен ДТО?

Более распространенные операции,СразудаДесенсибилизация пользовательских данных

Конечно, в некоторых проектах я видел, что соглашение об именах DTO — xxxrequest.

Соглашение об именах для Vo — xxxresponse.

Это всего лишь соглашение об именах.

Тогда давайте разберемся, что такое PO и DAO

PO(Persistent Object)обычно относится ксопоставлено с таблицей в базе данныхJavaобъект。Он содержит поля таблицы базы данных.Соответствующие частные переменные-члены и соответствующие методы получения и установки.,Используется для инкапсуляции записи в таблице базы данных. Классы PO обычно используются на уровне доступа к данным (уровень DAO).,Как связующее звено между базой данных и приложениеммост,Реализуйте постоянное хранение и извлечение данных.

Чтобы многие люди не путали этот объект поля.

Далее позвольте мне рассказать об этой спецификации Alibaba для объектов домена:

1) Объект данных: xxxDO, xxx — имя таблицы данных. 2) Объект передачи данных: xxxDTO, xxx — имя, связанное с бизнес-сферой. 3) Объект отображения: xxxVO, xxx обычно представляет собой имя веб-страницы. 4) POJO — собирательное имя DO/DTO/BO/VO, называть его xxxPOJO запрещено.

Разницы между DO и PO здесь нет или очень мало.

Ниже я буду использовать диаграмму и пример, чтобы помочь вам сначала разобраться в этих вещах.

whiteboard_exported_image
whiteboard_exported_image

Позже мы опишем различия между ними с помощью программ.

Сначала давайте посмотрим на таблицу базы данных:

Язык кода:javascript
копировать
user_id     bigint                                 not null comment 'ID пользователя'
        primary key,
    username    varchar(255) default ''                not null comment 'имя пользователя',
    password    varchar(255) default ''                not null comment 'пароль',
    salt        varchar(255) default ''                not null comment «Случайная соль»,
    question    varchar(255) default ''                not null comment «Вопрос безопасности»,
    answer      varchar(255) default ''                not null comment «Секретный ответ»,
    create_time datetime     default CURRENT_TIMESTAMP not null comment «Время создания»,
    update_time datetime     default CURRENT_TIMESTAMP not null comment 'время обновления',
    constraint uk_username
        unique (username) comment 'имя пользователяуникальный индекс'

Это все поля.

Далее, давайте сначала посмотрим на простейший уровень Po, который представляет собой взаимно однозначное соответствие с этой базой данных.

Язык кода:javascript
копировать
@Data
public class UPanUser implements Serializable {
    /**
     * ID пользователя
     */
    @TableId(value = "user_id")
    private Long userId;
​
    /**
     * имя пользователя
     */
    @TableField(value = "username")
    private String username;
​
    /**
     * пароль
     */
    @TableField(value = "password")
    private String password;
​
    /**
     * Случайная соль
     */
    @TableField(value = "salt")
    private String salt;
​
    /**
     * Проблемы безопасности
     */
    @TableField(value = "question")
    private String question;
​
    /**
     * Секретный ответ
     */
    @TableField(value = "answer")
    private String answer;
​
    /**
     * время создания
     */
    @TableField(value = "create_time")
    private Date createTime;
​
    /**
     * Время обновления
     */
    @TableField(value = "update_time")
    private Date updateTime;
​
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

Затем мы используем случай входа пользователя для демонстрации VO и DTO.

ВО предполагает, что мы хотим вернуть во внешний интерфейс только имя пользователя.

Тогда наш атрибут имеет только одно имя пользователя.

Язык кода:javascript
копировать
@Data
public class UserInfoVo implements Serializable {
​
    private static final long serialVersionUID = 1226886631190798234L;
​
    private String username;
​
}

Давайте посмотрим на DTO позже

Язык кода:javascript
копировать
@Data
public class UserLoginPo implements Serializable {
    private static final long serialVersionUID = 1L;
    @NotBlank(message = "имя пользователь не может быть пустым")
    @Pattern(regexp = "^[a-zA-Z0-9_-]{4,16}$", message = "имя ошибка формата пользователя")
    private String username;
​
    @NotBlank(message = "пароль не может быть пустым")
    @Length(min = 6, max = 20, message = "Длина пароля должна быть от 6 до 20")
    private String password;
}

Здесь, в dto, мы можем использовать некоторую структуру проверки для ограничения. Это параметр, передаваемый нам интерфейсной страницей или вызывающей службой. То есть номер счета и пароль используются для завершения входа в систему.

Тогда приступим к конвертации.

Практический бой

Beanutils

Это относительно простой метод. Это тоже метод, который я часто использую

Вот пример:

Язык кода:javascript
копировать
import org.springframework.beans.BeanUtils;
​
public class SpringBeanUtilsExample {
​
    public static void main(String[] args) {
        // Создать объект заказа на покупку
        UPanUser po = new UPanUser();
        po.setUserId(1L);
        po.setUsername("user");
        po.setPassword("password");
        po.setSalt("salt");
        po.setQuestion("question");
        po.setAnswer("answer");
        po.setCreateTime(new Date());
        po.setUpdateTime(new Date());
​
        // PO на VO
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(po, vo);
​
        System.out.println("PO на VO:" + vo.getUsername());
​
        // Создайте объект DTO
        UserLoginPo dto = new UserLoginPo();
        dto.setUsername("user");
        dto.setPassword("password");
​
        // Конвертировать DTO в PO
        UPanUser poFromDto = new UPanUser();
        BeanUtils.copyProperties(dto, poFromDto);
​
        System.out.println("Конвертировать DTO в PO:" + poFromDto.getUsername());
    }
}
​

Здесь необходимо отметить вот что.

import org.springframework.beans.BeanUtils;

Я использую этот Beanutils

Если вы используете import org.apache.commons.beanutils.BeanUtils;

Если это так, то позиции исходного и целевого параметров copyProperties этих двух методов противоположны.

Можно сказать, что это очень просто. Если вам нужно добавить комментарии, я рекомендую здесь плагин под названием BeanUtilsHelper.

Он может поддерживать метод преобразования этого кода beanutils в исходное значение, полученное с помощью set get. Если вам интересно, вы можете попробовать. Он также может поддерживать множество аннотаций.

Далее я хочу поговорить о методе преобразования, обеспечивающем взрывную производительность, элегантность высокого уровня и высокие заводские стандарты.

MapStcurt

Если вы хотите использовать библиотеку MapStruct для сопоставления объектов, сначала необходимо определить интерфейс Mapper и написать в нем методы сопоставления. Затем библиотека MapStruct автоматически сгенерирует соответствующий класс реализации сопоставления.

Во-первых, в pom.xml Добавить в файл MapStruct Зависимости:

Язык кода:javascript
копировать
xmlCopy code<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
</dependency>

Затем определите интерфейс Mapper:

Язык кода:javascript
копировать
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
​
@Mapper
public interface UserMapper {
​
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
​
    @Mapping(source = "username", target = "name")
    UserInfoVo toUserInfoVo(UPanUser po);
​
    @Mapping(source = "name", target = "username")
    UPanUser toUPanUser(UserLoginPo dto);
}
​

Давайте посмотрим на его применение весной:

Язык кода:javascript
копировать
package com.xiaou.pan.server.modules.user.converter;
​
​
import com.xiaou.pan.server.modules.file.domain.UPanUserFile;
import com.xiaou.pan.server.modules.user.context.*;
import com.xiaou.pan.server.modules.user.domain.UPanUser;
import com.xiaou.pan.server.modules.user.po.*;
import com.xiaou.pan.server.modules.user.vo.UserInfoVo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
​
/**
 * Класс инструмента преобразования сущностей пользовательского модуля
 */
@Mapper(componentModel = "spring")
public interface UserConverter {
​
    /**
     * Заказ на регистрацию пользователя преобразован в контекст регистрации пользователя.
     *
     * @param userRegisterPo
     * @return
     */
    UserRegisterContext userRegisterPo2UserRegisterContext(UserRegisterPo userRegisterPo);
​
    /**
     * Контекст регистрации пользователя преобразован в PO регистрации пользователя.
     *
     * @param userRegisterContext
     * @return
     */
    @Mapping(target = "password", ignore = true)
    UPanUser UserRegisterContext2UpanUser(UserRegisterContext userRegisterContext);
​
    /**
     * PO для входа пользователя преобразован в контекст входа пользователя
     *
     * @param userLoginPo
     * @return
     */
    UserLoginContext userLoginPO2UserLoginContext(UserLoginPo userLoginPo);
​
    /**
     * имя преобразование контекста проверки пользователя в имя пользователяпроверятьPO
     *
     * @param checkUserNamePo
     * @return
     */
    CheckUserNameContext CheckUserNamePo2CheckUserNameContext(CheckUserNamePo checkUserNamePo);
​
    /**
     * CheckAnswerPo — CheckAnswerContext
     *
     * @param checkAnswerPo
     * @return
     */
    CheckAnswerContext CheckAnswerPo2CheckAnswerContext(CheckAnswerPo checkAnswerPo);
​
​
    ResetPasswordContext ResetPasswordPo2ResetPasswordContext(ResetPasswordPo resetPasswordPo);
​
    ChangePasswordContext ChangePasswordPo2ChangePasswordContext(ChangePasswordPo changePasswordPo);
​
​
    /**
     * Соберите основную информацию о пользователе и верните объект.
     * @param uPanUser
     * @param uPanUserFile
     * @return
     */
    @Mapping(source = "uPanUser.username", target = "username")
    @Mapping(source = "uPanUserFile.fileId", target = "rootFileId")
    @Mapping(source = "uPanUserFile.fileName", target = "rootFilename")
    UserInfoVo assembleUserInfoVo(UPanUser uPanUser, UPanUserFile uPanUserFile);
}

В дополнение к этому @mapping также имеет множество параметров:

Например, выражение

Язык кода:javascript
копировать
@Mapping(target = "userId", expression = "java(com.xiaou.pan.server.common.utils.UserIdUtil.get())")

Это может выполнить Java-код.

Фактический его принцип заключается в автоматическом написании для нас классов реализации:

image-20240420143355939
image-20240420143355939

ModelMapper

Язык кода:javascript
копировать
import org.modelmapper.ModelMapper;
​
public class ModelMapperExample {
​
    public static void main(String[] args) {
        // Создать объект заказа на покупку
        UPanUser po = new UPanUser();
        po.setUserId(1L);
        po.setUsername("user");
        po.setPassword("password");
        po.setSalt("salt");
        po.setQuestion("question");
        po.setAnswer("answer");
        po.setCreateTime(new Date());
        po.setUpdateTime(new Date());
​
        // создавать ModelMapper объект
        ModelMapper modelMapper = new ModelMapper();
​
        // PO на VO
        UserInfoVo vo = modelMapper.map(po, UserInfoVo.class);
        System.out.println("PO на VO:" + vo.getUsername());
​
        // Создайте объект DTO
        UserLoginPo dto = new UserLoginPo();
        dto.setUsername("user");
        dto.setPassword("password");
​
        // Конвертировать DTO в PO
        UPanUser poFromDto = modelMapper.map(dto, UPanUser.class);
        System.out.println("Конвертировать DTO в PO:" + poFromDto.getUsername());
    }
}
​

использовать ModelMapper Правила сопоставления свойств можно определить более гибко, просто создав ModelMapper объект, а затем вызвать его map Метод можно использовать для копирования атрибутов между объектами.

постскриптум

Напоследок хочу сказать, к этим ВО ПО ДТО относятся БО СО и так далее, если разрабатывать масштабный проект. Необходимо выполнить полную архитектуру, но если речь идет о небольших проектах, нет необходимости проектировать ради дизайна, что приводит к перепроектированию.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose