controller只做接收请求、校验参数、调用service并包装响应三件事;所有业务逻辑须剥离至@service类,通过接口注入,确保事务、数据库操作等均在service层实现。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

要把业务逻辑从控制器中安全剥离,避免后续改一个字段牵出十个类的连锁反应,必须明确 Controller 只做三件事:接收请求、校验参数格式、调用 Service 并包装响应。其余所有计算、状态判断、数据库操作、事务控制,一律不许出现在 Controller 文件里。
第一步:识别并删除 Controller 中的违规代码
打开你的 Controller 类(比如 UserController.java),逐行扫描。凡是出现 userRepository.save()、new User().setXXX()、if (user.getAge() > 18 && user.isVerified())、orderService.calculateTotal() 这类语句,全部剪切出来——它们不属于这里。特别注意:直接 new 对象、手动拼 SQL、调用其他 Service 方法但没加 @Transactional 的,都是高危信号。
这一步做完后,Controller 方法体应只剩 @RequestBody、@PathVariable 解析、Validator.validate()、return ResponseEntity.ok(result) 这类纯传输层代码。
第二步:创建 Service 接口与实现类
在 service 包下新建 UserService.java 接口:
public interface UserService {
User createUser(User user);
User updateUser(Long id, UserUpdateDTO dto);
}
再新建 UserServiceImpl.java 实现类,用 @Service 注解声明,并注入 UserRepository:
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
通过本地 Codex 或 OpenClaw OAuth 凭证直接调用 ChatGPT/Codex Responses 的 image_generation 工具来生成或编辑光栅图像,然后保存
@Override
@Transactional
public User createUser(User user) {
// 把之前剪切出来的业务逻辑粘贴进来
return userRepository.save(user);
}
}
注意:构造器注入是强制要求,不要用 @Autowired 字段注入;@Transactional 必须加在实现类方法上,不能只加在接口里。
第三步:在 Controller 中完成依赖注入与调用
回到 UserController,删掉所有 userRepository 字段和相关 new 操作,改为:
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
public ResponseEntity
User saved = userService.createUser(user);
return ResponseEntity.status(201).body(saved);
}
}
这一步操作起来很简单,直接把文件拖进去就行。但务必确认 UserService 是接口类型,不是 UserServiceImpl —— 否则就破坏了面向接口编程原则,后续无法替换实现或 Mock 测试。
第四步:验证分层是否真正生效
① 运行应用,调用 /api/users POST 接口,确认能正常创建用户且返回 201。
② 在 UserServiceImpl 的 createUser 方法第一行加断点,发起请求,观察调试器是否停在 Service 层而非 Controller 层。
③ 尝试在 UserServiceImpl 中抛出 RuntimeException,检查数据库是否回滚 —— 如果没回滚,说明 @Transactional 没生效,大概率是因为你用了接口代理方式但没开启 @EnableTransactionManagement 或者调用发生在同一个 Bean 内部。
④ 删除 UserServiceImpl 类,重新编译。如果 Controller 编译失败,说明依赖注入路径正确;如果还能编译通过,说明你还在 Controller 里偷偷 new 了实现类,立刻修正。










