You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot REST API项目如何手动实现DTO到Entity转换

实现思路确认

你选择手动编写Mapper类完成DTO与Entity转换、按Controller→Service→DAO分层流转数据的思路完全正确。这种实现方式是Spring Boot REST API开发的标准分层实践,手动实现映射逻辑不会引入额外依赖,还能帮你清晰理解各层职责边界、数据在链路中的流转规则,对初学者打基础的价值远高于直接使用第三方映射类库。

具体实现方案

分层职责约定

先明确各层的操作边界,避免逻辑混乱:

  • Controller层:仅接收前端传入的请求DTO、返回响应DTO,绝对不直接操作数据库Entity,防止敏感字段(比如存储的加密密码、内部状态标记)直接暴露给前端
  • Mapper层:仅负责DTO和Entity之间的字段映射转换,不编写任何业务逻辑、参数校验逻辑
  • Service层:处理核心业务逻辑,调用DAO层前把入参DTO转换为Entity,返回结果前把DAO层查询到的Entity转换为响应DTO
  • DAO/Repository层:仅和Entity打交道,负责数据库读写操作,不感知DTO的存在

代码实现示例

以最常见的用户管理接口为例,完整实现流程如下:

  1. 先定义数据库映射Entity
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@Entity
@Table(name = "sys_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String encryptedPassword;
    private String email;
    private Integer age;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}
  1. 定义接口传输DTO
// 创建用户的请求入参DTO
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class UserCreateRequest {
    @NotBlank(message = "用户名不能为空")
    private String username;
    @NotBlank(message = "密码不能为空")
    private String rawPassword;
    @Email(message = "邮箱格式错误")
    private String email;
    private Integer age;
}
// 用户信息返回给前端的响应DTO
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class UserResponse {
    private Long id;
    private String username;
    private String email;
    private Integer age;
    private LocalDateTime createTime;
}
  1. 手动编写Mapper转换类
    把Mapper交给Spring容器管理为单例组件,分别写请求DTO转Entity、Entity转响应DTO的方法,记得做空值判断避免空指针:
import org.springframework.stereotype.Component;

@Component
public class UserMapper {
    // 创建请求转数据库实体
    public User toEntity(UserCreateRequest request) {
        if (request == null) {
            return null;
        }
        User user = new User();
        user.setUsername(request.getUsername());
        // 注意:密码加密逻辑放在Service层做,Mapper只做字段映射
        user.setEmail(request.getEmail());
        user.setAge(request.getAge());
        return user;
    }

    // 数据库实体转响应DTO
    public UserResponse toResponse(User entity) {
        if (entity == null) {
            return null;
        }
        UserResponse response = new UserResponse();
        response.setId(entity.getId());
        response.setUsername(entity.getUsername());
        response.setEmail(entity.getEmail());
        response.setAge(entity.getAge());
        response.setCreateTime(entity.getCreateTime());
        return response;
    }
}
  1. Service层调用Mapper完成业务逻辑
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;

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

    public UserResponse createUser(UserCreateRequest request) {
        // 入参DTO转Entity
        User user = userMapper.toEntity(request);
        // 业务字段赋值
        user.setEncryptedPassword(passwordEncoder.encode(request.getRawPassword()));
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        // 数据库落库
        User savedUser = userRepository.save(user);
        // 保存结果转响应DTO返回
        return userMapper.toResponse(savedUser);
    }
}
  1. Controller层接收请求、返回结果
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @PostMapping
    public ResponseEntity<UserResponse> createUser(@Valid @RequestBody UserCreateRequest request) {
        UserResponse response = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
}

实现注意事项

  • 转换方法必须先做空判断,避免链路中传入null值时触发空指针异常
  • 字段名、字段类型不匹配的转换逻辑直接写在Mapper中即可,比如Entity中存的是Integer类型的性别编码,DTO中要返回中文的性别描述,直接在映射方法里做值转换
  • 如果存在关联对象映射(比如User关联Role实体,DTO中需要返回Role的基础信息),直接在当前Mapper中注入对应关联对象的Mapper即可,不要手动new依赖类,交给Spring容器管理依赖
  • 严格遵守单一职责:Mapper只做字段映射,参数校验、密码加密、时间赋值、权限判断这类逻辑全部放在Service层实现,不要耦合到Mapper中

内容的提问来源于stack exchange,提问作者Felipe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 02:54:24