第三章 系统架构设计:分层架构、微服务选型与技术栈

好,咱们进入第三章。这一章我打算聊聊系统架构设计。说实话,这是整个OA系统的骨架。骨架搭歪了,后面再怎么填肉都别扭。我在好几个项目里都吃过架构选型不当的亏,今天把这些经验摊开来跟你讲讲。

3.1 分层架构:表现层、业务层、数据层

分层架构,说白了就是「各司其职」。你想想看,一个OA系统要处理审批、考勤、会议、文档……如果所有代码都揉在一起,那维护起来简直是噩梦。我习惯把系统切成三层:

  • 表现层:负责跟用户打交道。展示页面、接收输入、做简单的校验。
  • 业务层:核心逻辑在这里。比如审批流程的流转规则、考勤的计算逻辑。
  • 数据层:跟数据库打交道。增删改查,别掺和业务判断。

为什么要这么分?我给你讲个真实案例。之前有个项目,同事把SQL查询直接写在Vue的组件里。嗯,你没听错。后来数据库字段一改,满屏找代码改,差点没把项目搞崩。分层之后,数据层只暴露接口,业务层只管逻辑,表现层只管展示。改一个字段,最多动数据层和业务层,表现层完全不用碰。

核心原则:上层依赖下层,下层不依赖上层。表现层调用业务层,业务层调用数据层。千万别让数据层反过来调用表现层——我见过有人这么干,结果代码像意大利面条一样乱。

3.2 微服务架构选型

说到微服务,很多人一上来就喊「我们要上微服务!」。我劝你冷静。微服务不是银弹,它解决的是「单体应用过于庞大」的问题。OA系统要不要拆?我的建议是:

  • 小企业(50人以下):单体应用就够了。别折腾微服务,运维成本你扛不住。
  • 中型企业(50-500人):可以拆成几个核心服务。比如用户服务、审批服务、考勤服务。
  • 大型企业(500人以上):微服务是必须的。否则一个模块出问题,整个系统都瘫痪。

我个人习惯用Spring Cloud Alibaba这套生态。为什么?因为它在国内落地案例多,坑少。Nacos做注册中心和配置中心,Sentinel做流量控制,Seata处理分布式事务。这些组件我都踩过坑,后面会细说。

避坑指南:我曾经在一个项目里强行把所有功能都拆成微服务,结果服务间调用链长达七八层,出个问题排查半天。后来我学乖了——按业务边界拆,不强求「每个服务都独立数据库」。有些紧密关联的功能,放在同一个服务里反而更高效。

3.3 技术栈选择

技术栈这东西,没有最好,只有最合适。我选技术栈的标准很简单:社区活跃、文档齐全、团队熟悉。下面是我给OA系统推荐的一套组合:

层级 技术选型 理由
后端框架 Spring Boot 2.7+ 生态成熟,上手快,适合快速迭代
前端框架 Vue.js 3 + Element Plus 组件丰富,适合后台管理系统
数据库 MySQL 8.0 稳定可靠,OA系统数据量一般不大
缓存 Redis 处理会话、缓存热点数据
消息队列 RabbitMQ 处理异步通知、日志收集

你可能会问:为什么不用MyBatis-Plus?嗯,我其实挺推荐的。它让数据层的开发效率提升不少。但要注意,别滥用它的自动映射——我见过有人一个查询查出几十个字段,结果页面只用了三个。性能就是这么被拖垮的。

前端这块,Vue 3 + Element Plus是绝配。Element Plus的表格、表单、弹窗组件,基本覆盖了OA系统90%的场景。我习惯用Vite做构建工具,比Webpack快太多了,开发体验好一个档次。

注意:技术栈选好了,别频繁升级。我有个朋友,项目做到一半把Spring Boot从2.6升到3.0,结果一堆依赖不兼容,加班两周才搞定。除非有重大安全漏洞,否则保持稳定版本,等迭代间隙再升级。

3.4 代码示例:一个简单的分层实现

光说不练假把式。我给你看一个用户登录的简单实现,感受一下分层是怎么落地的。

数据层(UserMapper.java):

@Mapper
public interface UserMapper {
    UserDO findByUsername(@Param("username") String username);
}

业务层(UserService.java):

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    public UserVO login(String username, String password) {
        UserDO user = userMapper.findByUsername(username);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        if (!password.equals(user.getPassword())) {
            throw new BusinessException("密码错误");
        }
        // 这里可以加登录日志、更新最后登录时间等
        return new UserVO(user.getId(), user.getName(), user.getRole());
    }
}

表现层(UserController.java):

@RestController
@RequestMapping("/api/user")
public class UserController {
    @Autowired
    private UserService userService;
    
    @PostMapping("/login")
    public Result<UserVO> login(@RequestBody LoginDTO dto) {
        UserVO user = userService.login(dto.getUsername(), dto.getPassword());
        return Result.success(user);
    }
}

你看,每一层各管各的事。数据层只查数据库,业务层做逻辑判断,表现层只负责接收请求和返回结果。这样写出来的代码,改起来心里有底。

3.5 总结一下

架构设计这件事,没有标准答案。但有几个原则我建议你记住:

  • 分层要清晰:别让表现层直接操作数据库,也别让数据层处理业务逻辑。
  • 微服务要克制:不是功能越多越好,拆之前先想想「这个服务独立部署的价值是什么」。
  • 技术栈要务实:选团队熟悉的、社区活跃的、文档齐全的。别为了炫技选冷门框架。

嗯,这一章就聊到这儿。下一章我会讲数据库设计,包括表结构怎么规划、索引怎么建、读写分离怎么做。到时候见。