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

Spring Boot项目从MVC架构改造为分层架构的API设计咨询

Spring Boot分层架构改造与层间隔离API实现示例

一、核心分层隔离思路

  • 控制器层(Controller):仅负责请求接收、响应封装,通过**DTO(数据传输对象)**与服务层交互,不直接操作实体类或数据访问层
  • 服务层(Service):定义业务接口明确层间交互API,实现类处理核心业务逻辑,负责DTO与实体类的转换,依赖数据访问层接口而非实现
  • 数据访问层(DAO/Repository):仅处理数据持久化操作,依赖实体类,对外暴露数据操作接口
  • 层间隔离核心:用DTO阻断实体类在各层的直接传递,避免业务逻辑与数据结构耦合,同时控制对外暴露的数据范围

二、改造后代码示例

1. 定义DTO(数据传输对象)

创建与业务场景匹配的DTO,仅包含需要在层间传递的字段,屏蔽实体类的内部细节:

// UserDTO.java
public class UserDTO {
    private String username;
    private String password;
    // 仅保留业务需要的字段,避免暴露实体的全量属性
    // getter、setter、构造方法省略
}

// AnnonceDTO.java
public class AnnonceDTO {
    private String title;
    private String content;
    // 不包含id、date这类由服务层统一处理的字段
    // getter、setter、构造方法省略
}

2. 控制器层改造

控制器仅处理请求参数接收与响应返回,所有业务逻辑委托给服务层:

// UserController.java
@Controller
public class UserController {

    private final UserService userService;

    // 构造注入,避免字段注入
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/saveUser")
    public String saveUser(@ModelAttribute("user") UserDTO userDTO) {
        // 控制器不处理业务逻辑(如密码加密),仅传递DTO到服务层
        userService.saveUser(userDTO);
        return "redirect:/users";
    }
}

// AnnonceRestController.java
@RestController
@RequestMapping("/api")
public class AnnonceRestController {

    private final AnnonceService annonceService;

    public AnnonceRestController(AnnonceService annonceService) {
        this.annonceService = annonceService;
    }

    @GetMapping("/announce-all")
    public List<AnnonceDTO> findAll() {
        // 返回DTO而非实体,隔离内部数据结构
        return annonceService.findAllAnnonces();
    }

    @PostMapping("/announce-create")
    public AnnonceDTO addAnnonce(@RequestBody AnnonceDTO annonceDTO) {
        // 服务层处理id、日期等业务规则,控制器不干预
        return annonceService.saveAnnonce(annonceDTO);
    }
}

3. 服务层接口与实现

定义服务接口明确层间交互规范,实现类处理业务逻辑并完成DTO与实体的转换:

// UserService.java(服务接口,定义层间交互API)
public interface UserService {
    void saveUser(UserDTO userDTO);
    // 其他业务方法接口
}

// UserServiceImpl.java(服务实现类)
@Service
public class UserServiceImpl implements UserService {

    private final UserDao userDao;
    private final PasswordEncoder passwordEncoder;

    public UserServiceImpl(UserDao userDao, PasswordEncoder passwordEncoder) {
        this.userDao = userDao;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    @Transactional
    public void saveUser(UserDTO userDTO) {
        // 业务逻辑处理:密码加密、DTO转实体
        User user = new User();
        user.setUsername(userDTO.getUsername());
        user.setPassword(passwordEncoder.encode(userDTO.getPassword()));
        // 其他字段赋值
        userDao.saveUser(user);
    }
}

// AnnonceService.java(服务接口)
public interface AnnonceService {
    List<AnnonceDTO> findAllAnnonces();
    AnnonceDTO saveAnnonce(AnnonceDTO annonceDTO);
}

// AnnonceServiceImpl.java(服务实现类)
@Service
public class AnnonceServiceImpl implements AnnonceService {

    private final AnnonceDao annonceDao;

    public AnnonceServiceImpl(AnnonceDao annonceDao) {
        this.annonceDao = annonceDao;
    }

    @Override
    public List<AnnonceDTO> findAllAnnonces() {
        // 实体转DTO,屏蔽内部数据细节
        return annonceDao.findAll().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public AnnonceDTO saveAnnonce(AnnonceDTO annonceDTO) {
        Annonce annonce = new Annonce();
        annonce.setTitle(annonceDTO.getTitle());
        annonce.setContent(annonceDTO.getContent());
        annonce.setId(0); // 业务规则统一处理
        annonce.setDate(LocalDateTime.now()); // 服务层负责日期赋值
        Annonce savedAnnonce = annonceDao.saveAnnonce(annonce);
        return convertToDTO(savedAnnonce);
    }

    // 私有方法:实体转DTO
    private AnnonceDTO convertToDTO(Annonce annonce) {
        AnnonceDTO dto = new AnnonceDTO();
        dto.setTitle(annonce.getTitle());
        dto.setContent(annonce.getContent());
        return dto;
    }
}

4. 数据访问层接口

DAO层仅定义数据持久化操作,不涉及任何业务逻辑:

// UserDao.java
@Repository
public interface UserDao {
    void saveUser(User user);
    // 其他数据操作方法
}

// AnnonceDao.java
@Repository
public interface AnnonceDao {
    List<Annonce> findAll();
    Annonce saveAnnonce(Annonce annonce);
    // 其他数据操作方法
}

三、分层隔离关键要点

  • 依赖倒置:上层依赖下层的接口而非实现,比如控制器依赖UserService接口、服务层依赖UserDao接口,后续替换实现类不影响上层代码
  • DTO隔离:用DTO在控制器与服务层之间传递数据,避免实体类的内部结构暴露到外部,同时防止层间直接耦合实体
  • 单一职责:控制器仅处理请求响应、服务层处理业务逻辑、DAO层仅处理数据操作,各层职责边界清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 08:05:22