Лабораторная работа 3: Реализация DTO, Mapper и Repository в Spring Boot приложении с PostgreSQL

1. Создание DTO (Data Transfer Object)

  1. Базовый DTO для сущности User
    
    public class UserDTO {
        private Long id;
        private String username;
        private String email;
        // Геттеры и сеттеры
    }
        
  2. DTO для создания сущности
    UserCreateDTO.java
    
    public class UserCreateDTO {
        @NotBlank
        private String username;
        @Email
        private String email;
    }
        
  3. DTO для обновления сущности
    UserUpdateDTO.java
    
    public class UserUpdateDTO {
        private String username;
        private String email;
    }
        
  4. DTO с проекциями (для сложных запросов)
    
    public interface UserProjection {
        String getUsername();
        String getEmail();
    }
        
  5. Валидация DTO
    
    public class UserCreateDTO {
        @Size(min = 3, max = 50)
        private String username;
    }
        
  6. Ломбок-аннотации
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserDTO {
        private Long id;
        private String username;
        private String email;
    }
        
  7. DTO для связанных сущностей
    
    public class UserWithPostsDTO {
        private UserDTO user;
        private List<PostDTO> posts;
    }
        
  8. Конвертер дат в DTO
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
    private LocalDateTime createdAt;
        

2. Реализация Mapper

  1. Ручной маппинг
    
    public UserDTO toDto(User user) {
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        return dto;
    }
        
  2. Использование MapStruct
    Добавьте зависимость:
    
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
        
  3. Интерфейс маппера
    UserMapper.java
    
    @Mapper(componentModel = "spring")
    public interface UserMapper {
        UserDTO toDto(User user);
        User fromDto(UserDTO dto);
    }
        
  4. Кастомные методы маппера
    
    @AfterMapping
    default void enrichDto(User user, @MappingTarget UserDTO dto) {
        dto.setFullName(user.getFirstName() + " " + user.getLastName());
    }
        
  5. Маппинг коллекций
    
    List<UserDTO> toDtoList(List<User> users);
        
  6. Игнорирование полей
    
    @Mapping(target = "password", ignore = true)
    UserDTO toDto(User user);
        
  7. Маппинг разных типов полей
    
    @Mapping(target = "createdDate", 
             expression = "java(user.getCreatedAt().format(DateTimeFormatter.ISO_DATE))")
    UserDTO toDto(User user);
        

3. Настройка Repository

  1. Базовый репозиторий
    
    public interface UserRepository extends JpaRepository<User, Long> {}
        
  2. Кастомные запросы с @Query
    
    @Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
    List<User> findByEmailDomain(@Param("domain") String domain);
        
  3. Нативные SQL-запросы
    
    @Query(value = "SELECT * FROM users WHERE active = true", nativeQuery = true)
    List<User> findActiveUsers();
        
  4. Projections в репозиториях
    
    List<UserProjection> findByUsernameContaining(String keyword);
        
  5. Pagination и сортировка
    
    Page<User> findByStatus(String status, Pageable pageable);
        
  6. Методы с Optional
    
    Optional<User> findByEmail(String email);
        
  7. Кастомный репозиторий
    
    public interface CustomUserRepository {
        List<User> findInactiveUsers();
    }
        
  8. Реализация кастомного репозитория
    
    public class CustomUserRepositoryImpl implements CustomUserRepository {
        @PersistenceContext
        private EntityManager em;
    
        // Реализация методов
    }
        
  9. Наследование кастомного репозитория
    
    public interface UserRepository extends JpaRepository<User, Long>, CustomUserRepository {}
        
  10. Auditing репозиториев
    
    @EntityListeners(AuditingEntityListener.class)
    public class User {
        @CreatedDate
        private LocalDateTime createdAt;
    }
        

Пример интеграции в сервисном слое


@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final UserMapper userMapper;

    public UserDTO createUser(UserCreateDTO dto) {
        User user = userMapper.fromCreateDto(dto);
        User saved = userRepository.save(user);
        return userMapper.toDto(saved);
    }

    public Page<UserDTO> getAllUsers(Pageable pageable) {
        return userRepository.findAll(pageable)
                .map(userMapper::toDto);
    }
}

Рекомендации по форматированию (для Word)

  • Используйте стили Heading 2 для разделов DTO, Mapper, Repository
  • Код оформляйте моноширинным шрифтом (например, Consolas 10pt)
  • Настройте автоматическое оглавление
  • Для каждого раздела используйте нумерованные списки

Вывод

В ходе работы были реализованы все ключевые компоненты работы с данными: DTO для безопасной передачи данных, мапперы для преобразования между слоями и репозитории с различными вариантами доступа к данным. Полученная архитектура соответствует best practices современной Spring-разработки.