【苍穹外卖|Day01】项目初识:从多模块结构到 OpenAPI 接口文档踩坑
2026/6/3 21:55:14 网站建设 项目流程

从今天开始,博主准备更新苍穹外卖项目相关的学习笔记。

这篇是 Day01,目标不是一上来就写复杂业务,而是先解决三个基础问题:

  1. 一个后端项目从需求到上线大概会经历哪些环节。
  2. 苍穹外卖这个项目的多模块结构应该怎么看。
  3. 当前项目使用 Spring Boot 4.0.6 时,接口文档为什么不能继续照搬旧版 Swagger 2 / Knife4j 思路。

本文内容主要来自三部分:我的课程笔记、当前项目代码,以及 springdoc 官方文档。因为接口文档生成和框架版本强相关,所以这部分会以当前项目依赖为准,不把旧教程里的配置直接当成结论。

一、先看软件开发流程

Day01 笔记里先讲了软件开发流程。我一开始觉得这部分偏理论,但放到项目里看,其实它对应的是后面每一类文件为什么会出现。

阶段常见产物和后端开发的关系
需求分析需求规格说明书、产品原型确定系统要做哪些功能
设计UI 设计、数据库设计、接口设计决定页面、表结构、接口路径和参数
编码项目代码、单元测试按照设计实现 Controller、Service、Mapper
测试测试用例、测试报告验证接口、业务规则和边界条件
上线运维环境安装、配置、部署让项目在真实环境稳定运行

1.1 角色分工

一个完整项目里通常会有这些角色:

  • 项目经理:负责整体进度和任务分配。
  • 产品经理:整理需求,输出需求文档和产品原型。
  • UI 设计师:根据原型设计界面效果。
  • 架构师:负责整体架构和技术选型。
  • 开发工程师:完成业务编码、接口实现和必要的测试。
  • 测试工程师:编写测试用例,输出测试报告。
  • 运维工程师:负责环境搭建、部署和上线维护。

这部分先不用背得很死。对我来说,更重要的是形成一个意识:后端代码不是凭空写出来的,它背后一定有需求、接口、数据库和测试这些约束。

1.2 软件环境

项目环境一般分为三类:

环境说明
开发环境 development开发人员本地或团队内部调试使用
测试环境 testing测试人员验证功能使用
生产环境 production正式对外提供服务的环境

当前 Day01 主要是在开发环境里整理项目结构和接口文档。后面如果涉及生产环境配置,就不能直接照搬本地配置,尤其是数据库密码、JWT 密钥、OSS AccessKey 这类敏感信息。

二、苍穹外卖项目整体结构

苍穹外卖项目主要包含两个端:

  • 管理端:给商家或后台人员使用,例如员工管理、分类管理、菜品管理、订单管理。
  • 用户端:给用户使用,例如浏览菜品、下单、支付、查看订单。

前后端联调时会用到 Nginx。这里先把它理解成前端静态资源和后端接口之间的一层代理。它的常见作用包括:

  1. 提高访问速度:静态资源可以由 Nginx 处理。
  2. 进行负载均衡:后面多个服务实例时,可以由 Nginx 转发请求。
  3. 保护后端服务:后端服务不一定直接暴露给外部访问。

三、Maven 多模块:先知道每个模块放什么

当前项目是一个 Maven 父工程,下面聚合了三个子模块。

项目根目录的pom.xml里可以看到模块声明:

<!-- pom.xml --><modules><module>sky-common</module><module>sky-pojo</module><module>sky-server</module></modules>

几个模块的职责如下:

模块作用
sky-take-outMaven 父工程,统一管理依赖版本,聚合子模块
sky-common公共模块,存放工具类、常量类、异常类、统一返回结果等
sky-pojo模型模块,存放 Entity、DTO、VO 等
sky-server后端服务模块,存放配置文件、Controller、Service、Mapper 等

这套结构的好处是职责比较清楚。

比如登录接口中,前端请求参数对应sky-pojo里的EmployeeLoginDTO,登录成功的返回数据对应EmployeeLoginVO,JWT 工具类在sky-common,真正处理请求的 Controller 和 Service 在sky-server

也就是说,读项目时不要只看 Controller。一个接口能跑起来,背后通常是多个模块一起配合。

四、当前项目版本:为什么旧教程不能直接套

我的项目导入后做过版本适配,目前能从pom.xml中确认这些版本:

<!-- pom.xml --><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>4.0.6</version><relativePath/></parent><properties><java.version>25</java.version><mybatis.spring>4.0.1</mybatis.spring><springdoc>3.0.3</springdoc><swagger>2.2.47</swagger></properties>

这里最关键的是Spring Boot 4.0.6Java 25

版本一旦比较新,很多旧资料里的依赖就不能直接复制。比如接口文档这块,旧项目里常见的是 Swagger 2 或旧版 Knife4j,但当前项目实际接入的是 springdoc:

<!-- sky-server/pom.xml --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId></dependency>

所以这篇的接口文档部分,不写成“Knife4j 配置教程”,而是写成“当前项目使用 springdoc/OpenAPI 3 生成接口文档”。

五、接口文档踩坑:从 Swagger 2 切到 OpenAPI 3

这一块是 Day01 最容易卡住的地方。

一开始看到“Swagger 可以生成接口文档,Knife4j 集成 Swagger”时,很容易沿着旧教程去找@Api@ApiOperation@ApiModelProperty这些注解。但当前项目已经不是这套写法。

根据 springdoc 官方文档,从 SpringFox / Swagger 2 迁移到 springdoc 时,需要移除旧的 SpringFox 和 Swagger 2 依赖,改用springdoc-openapi-starter-webmvc-ui,并替换成 Swagger 3 注解。常见替换关系如下:

Swagger 2 旧注解OpenAPI 3 新注解作用
@Api@Tag标注 Controller 分组
@ApiOperation@Operation标注接口方法说明
@ApiParam@Parameter标注请求参数
@ApiModel@Schema标注模型类
@ApiModelProperty@Schema标注模型字段
@ApiResponse(code = ...)@ApiResponse(responseCode = ...)标注响应码

这里的重点不是记表格,而是先判断自己项目到底用了哪套依赖。依赖路线确认错了,后面注解、配置、静态资源路径都会跟着错。

5.1 Controller 上的接口分组

当前项目在EmployeeController上使用@Tag给接口分组:

// sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java@RestController@RequestMapping("/admin/employee")@Slf4j@Tag(name="员工管理相关接口")publicclassEmployeeController{}

@Tag的作用是让这一组接口在接口文档中归到同一个分类下。管理端接口多起来以后,如果没有分组,接口文档会比较乱。

5.2 方法上的接口说明

登录接口上使用@Operation描述接口作用:

// sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java@PostMapping("/login")@Operation(summary="员工登录接口")publicResult<EmployeeLoginVO>login(@RequestBodyEmployeeLoginDTOemployeeLoginDTO){// 登录逻辑}

这里还有一个值得注意的点:@RequestBody表示请求体中的 JSON 会绑定到EmployeeLoginDTO。所以前端传参、DTO 字段、接口文档展示的模型,其实是串在一起的。

5.3 DTO/VO 上的字段说明

当前项目里,登录请求参数用EmployeeLoginDTO表示:

// sky-pojo/src/main/java/com/sky/dto/EmployeeLoginDTO.java@Data@Schema(description="员工登录时传递的数据模型")publicclassEmployeeLoginDTOimplementsSerializable{@Schema(description="用户名")privateStringusername;@Schema(description="密码")privateStringpassword;}

登录成功后的返回对象用EmployeeLoginVO表示:

// sky-pojo/src/main/java/com/sky/vo/EmployeeLoginVO.java@Data@Builder@NoArgsConstructor@AllArgsConstructor@Schema(description="员工登录返回的数据格式")publicclassEmployeeLoginVOimplementsSerializable{@Schema(description="主键值")privateLongid;@Schema(description="用户名")privateStringuserName;@Schema(description="姓名")privateStringname;@Schema(description="jwt令牌")privateStringtoken;}

DTO 和 VO 分开以后,接口文档也会更清楚:请求时需要什么字段,响应时返回什么字段,读者和前端都能直接看出来。

六、springdoc 配置和验证方式

项目里通过OpenAPIBean 设置了接口文档的标题、版本和描述:

// sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java@BeanpublicOpenAPIcustomOpenAPI(){returnnewOpenAPI().info(newInfo().title("苍穹外卖项目接口文档").version("2.0").description("苍穹外卖项目接口文档"));}

同时配置了 Swagger UI 相关静态资源映射:

// sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){log.info("开始设置静态资源映射...");registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}

当前可以通过下面的地址查看接口文档:

http://localhost:8080/swagger-ui/index.html#/

如果访问不到,我会优先按这个顺序排查:

  1. pom.xml中是否存在springdoc-openapi-starter-webmvc-ui
  2. 是否还残留旧版 SpringFox / Swagger 2 依赖。
  3. Controller、DTO、VO 的注解包是否来自io.swagger.v3.oas.annotations
  4. 静态资源路径是否配置正确。
  5. 拦截器是否误拦截了接口文档路径。

第 5 点也要看当前代码。项目中注册了管理端 JWT 拦截器:

// sky-server/src/main/java/com/sky/config/WebMvcConfiguration.java@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){log.info("开始注册自定义拦截器...");registry.addInterceptor(jwtTokenAdminInterceptor).addPathPatterns("/admin/**").excludePathPatterns("/admin/employee/login");}

这个拦截器目前拦截的是/admin/**,接口文档地址是/swagger-ui/**,所以正常情况下不会被它拦住。后面如果自己扩大拦截范围,就要记得给接口文档和静态资源留出放行规则。

七、基于 Apifox 实现自我测试

课程资料里会提供接口定义,可以先在 YApi 中创建管理端接口项目和用户端接口项目,再把对应 JSON 文件导入进去。

我自己使用 Apifox 做接口自测时,可以通过:

项目设置 -> 导入设置 -> 选择 YApi -> 导入接口

这样做的意义是把“接口约定”和“自己写的后端代码”对起来。

比如员工登录接口,后端代码里的请求路径是:

// sky-server/src/main/java/com/sky/controller/admin/EmployeeController.java@PostMapping("/login")publicResult<EmployeeLoginVO>login(@RequestBodyEmployeeLoginDTOemployeeLoginDTO){// 登录逻辑}

类上还有统一路径:

@RequestMapping("/admin/employee")

所以完整登录接口路径就是:

POST /admin/employee/login

自测时要重点看这些内容是否一致:

  1. Apifox 里的请求方法是不是POST
  2. 接口路径是不是/admin/employee/login
  3. 请求体字段是否和EmployeeLoginDTO对应。
  4. 返回结果是否符合统一返回结构Result<EmployeeLoginVO>

这里不需要一开始就追求把所有接口测完。Day01 阶段先把导入、查看、发起一次请求这条链路跑通,后面每写一个模块再补对应接口测试。

八、登录安全:MD5 和 JWT 先看清链路

笔记里提到一个安全点:密码如果明文存放在数据库中,安全性很低,所以要进行加密后存储或比对。

当前员工登录逻辑中,Service 层会先根据用户名查询员工,再对用户输入的密码做 MD5 处理后比较:

// sky-server/src/main/java/com/sky/service/impl/EmployeeServiceImpl.javapublicEmployeelogin(EmployeeLoginDTOemployeeLoginDTO){Stringusername=employeeLoginDTO.getUsername();Stringpassword=employeeLoginDTO.getPassword();Employeeemployee=employeeMapper.getByUsername(username);if(employee==null){thrownewAccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);}password=DigestUtils.md5DigestAsHex(password.getBytes());if(!password.equals(employee.getPassword())){thrownewPasswordErrorException(MessageConstant.PASSWORD_ERROR);}if(employee.getStatus()==StatusConstant.DISABLE){thrownewAccountLockedException(MessageConstant.ACCOUNT_LOCKED);}returnemployee;}

这段代码的判断顺序很清楚:

  1. 查不到员工,抛出账号不存在异常。
  2. 密码比对失败,抛出密码错误异常。
  3. 账号被禁用,抛出账号锁定异常。
  4. 都通过后,返回员工对象。

登录成功后,Controller 层会生成 JWT:

// sky-server/src/main/java/com/sky/controller/admin/EmployeeController.javaMap<String,Object>claims=newHashMap<>();claims.put(JwtClaimsConstant.EMP_ID,employee.getId());Stringtoken=JwtUtil.createJWT(jwtProperties.getAdminSecretKey(),jwtProperties.getAdminTtl(),claims);

这里要注意两点:

  • 写博客时不要暴露真实 JWT 密钥、数据库密码、OSS AccessKey。
  • MD5 在课程项目里方便理解加密比对流程,但生产系统里通常还要考虑更安全的密码存储方案,例如加盐哈希或专门的密码编码器。

这也是专业度容易扣分的地方。不能只说“用了 MD5 所以安全”,更准确的说法是:当前项目通过 MD5 避免明文比对,但这只是学习项目里的实现方式,生产环境还需要更严格的安全设计。

九、TODO 的作用:标记后续要补的坑

笔记里还提到了 TODO。它的作用不是随便写一行注释,而是标记“这里后面还要回来处理”。

比如某段逻辑暂时能跑通,但还有优化空间,就可以先用 TODO 标出来。这样后面在 IDE 里统一查看时,不容易忘掉。

不过 TODO 也不能滥用。如果一个问题已经修完,最好同步清理或改成准确注释。否则时间久了,别人看到 TODO 会误以为这个逻辑还没完成。

十、Day01 总结

Day01 的核心不是写多少业务代码,而是把项目的入口摸清楚。

这一篇整理下来,我觉得有几个结论比较重要:

  1. 软件开发流程决定了代码不是孤立存在的。后端接口、DTO、数据库字段都和需求、原型、接口设计有关。
  2. 苍穹外卖是多模块项目sky-commonsky-pojosky-server分别承担公共能力、模型对象和后端服务职责。
  3. 接口文档要以当前项目版本为准。当前项目使用 Spring Boot 4.0.6 和 springdoc,不适合直接套旧 Swagger 2 注解。
  4. 自测要落到具体路径和对象上。比如登录接口要能对应到POST /admin/employee/loginEmployeeLoginDTOEmployeeLoginVO和统一返回结果。
  5. 安全内容要写边界。MD5 和 JWT 能帮助理解认证链路,但真实生产环境还要关注密钥保护、日志脱敏和更安全的密码存储。

参考资料:

  • springdoc 官方文档:https://springdoc.org/
  • springdoc 迁移说明:https://springdoc.org/migrating-from-springfox.html

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询