☰
SpringBoot + Vue 图书商城管理系统开发实战:从架构到部署全流程
2026/10/18 17:02:19 网站建设 项目流程

1. 项目整体设计与技术选型思路

1.1 为什么选择 SpringBoot + Vue 这种前后端分离架构

图书商城管理系统这个题目,在毕业设计和课程设计里出现频率一直很高。很多人拿到题目第一反应是“又要写一个增删改查”,但真做起来才发现,图书商城远比想象中复杂:它涉及用户浏览、购物车、订单流转、库存扣减、后台管理等多个业务场景,单纯堆代码根本撑不起一套完整的业务流程。

我见过不少同学用传统的单体架构去写,JSP 页面里嵌 Java 代码,前端后端全混在一起,调试一次要重启整个项目,改个样式还得在服务器上找半天文件。这种方案如果只是交个实验报告还好,要做到像样的“管理系统”体验,难度很大。所以我个人更推荐,也更有把握的方案是 SpringBoot + Vue 前后端分离。

前后端分离带来的直接好处是:职责边界清楚。后端只负责提供 RESTful 接口,处理业务逻辑和数据库交互;前端只负责页面渲染、用户交互和数据展示。两边能并行开发,各测各的,联调时只要对好接口格式就行。还有一个隐性好处是——对于毕业设计答辩来说,你能讲清楚“为什么要分离、分离之后数据怎么流动”,本身就是个不错的亮点。

SpringBoot 的存在大幅降低了后端搭建成本。它内置了 Tomcat,提供了自动化配置,过去 Spring 框架里那些繁琐的 XML 配置基本都省掉了,一个 main 方法就能把服务跑起来。配合 MyBatis,SQL 操作在自己的掌控范围内,遇到复杂的连表查询、多条件筛选,写 XML 映射比 JPA 那种自动生成的手段更容易调优和排查。

前端选择 Vue,最核心的原因是它的学习曲线和组件化开发模式。Vue 的模板语法非常直观,一个熟悉 HTML 和 JavaScript 的人,基本一两天就能上手写页面。配合 Vue Router 做页面跳转、Vuex 做购物车和登录状态管理,整个前端结构清清楚楚。加上 Element UI 这类现成组件库,后台管理的表格、表单、弹窗直接拿来用,视觉效果和专业程度都能在线。

1.2 功能模块拆解:用户端与后台管理端分别做什么

图书商城管理系统的本质是一个双边角色系统,所以功能拆解时不能只围绕“买书”这一个动作来设计,还要把管理员运营端考虑进去。按我通常设计的方案,整个系统划分为两个大端、八个核心模块。

用户端面向的是购书者,核心功能包括:

  • 用户注册与登录:手机号或用户名 + 密码,登录后发放 token 作为身份凭证。
  • 图书浏览与检索:首页展示推荐图书,支持按分类筛选、按关键字搜索、按价格或销量排序。
  • 图书详情查看:展示封面、作者、出版社、ISBN、库存、价格、内容简介,加入购物车按钮。
  • 购物车管理:加入图书、修改数量、删除条目、勾选结算。
  • 订单管理:确认订单、选择收货地址、生成订单、查看订单列表和详情、取消订单。

后台管理端面向的是管理员,核心功能包括:

  • 管理员登录:独立于用户端的后台身份认证。

  • 图书管理:上架新书、编辑图书信息、下架图书、调整库存和价格。

  • 分类管理:维护图书分类的增删改。

  • 订单管理:查看所有用户的订单、更新订单发货状态、处理取消申请。

  • 用户管理:查看注册用户列表、启用或禁用账号。

  • 数据统计:简单统计用户数量、图书数量、订单总量和销售走势,配合图表展示。

这个模块划分虽然看起来多,但落到数据库设计上,其实只需要用户表、图书表、分类表、购物车表、订单表、订单详情表、管理员表这七张基础表。模块多但表结构清晰,正是图书商城适合作为练手项目的原因:复杂度适中,又能覆盖商城类系统的大部分核心场景。

1.3 数据库设计要点:先理清表关系,再写代码

我习惯的做事顺序是:拿到项目后第一件事不是搭工程,而是把 ER 图画出来。没有清晰的表结构做支撑,后端代码写着写着就会乱,比如订单和图书之间的关系如果没理清,经常会出现“图书下架了订单里却没记录当时的书名价格”这种尴尬问题。

核心表的设计思路如下:

用户表(user)主要字段包括:id、username、password(加密存储)、nickname、phone、status(启用/禁用)、create_time。Password 在存入时必须做加密处理,常用的是 BCrypt,绝不能用明文。

分类表(category)字段简单:id、name、sort_order。

图书表(book)是整个系统的核心,字段设计要尤其注意。除了基本的 id、title、author、publisher、isbn、price、stock 之外,我还推荐加上 cover_url(封面图地址)、description(简介)、sales(销量)、status(上架/下架)、category_id(外键关联分类)。特别提醒一下 sales 销量字段最好是独立冗余字段,而不是每次现算订单数量,否则列表页按销量排序时会写得很麻烦。

购物车表(cart)字段不用很多:id、user_id、book_id、quantity、create_time。它本质是一个用户与图书的关联关系表,加一个联合唯一索引(user_id + book_id)可以防止同一本书在购物车里出现多条记录。

订单表和订单详情表是典型的“一对多”关系。订单表(orders)记录整体信息:id、order_no(订单号,唯一)、user_id、total_amount、consignee(收货人)、phone、address、status(待支付/已支付/已发货/已完成/已取消)、create_time。订单详情表(order_item)则记录订单里每个具体图书:id、order_id、book_id、book_name、book_image、price、quantity。这里我特意把 book_name 和 book_image 冗余进了详情表,因为订单属于历史数据,用户下单后即使管理员修改或删除了图书信息,订单里的快照信息也不该跟着变。

这里有一个个人习惯可以分享给大家:所有表的主键都用自增 id,不搞复杂的分布式主键策略,因为单机项目根本用不上。订单号用时间戳 + 随机数的形式生成就行,比如 20250612 加一段随机数字。

2. 后端核心实现:SpringBoot 与 MyBatis 的落地细节

2.1 工程结构搭建与分层思想

后端工程我建议采用标准的 Controller - Service - Mapper 三层结构,这样才能把代码职责切干净。大概的包结构如下:

com.example.bookstore ├── controller // 接收前端请求,参数校验 ├── service // 业务逻辑层,处理具体业务规则 ├── mapper // MyBatis 的数据访问接口 ├── entity // 数据库实体类 ├── dto // 数据传输对象,用于接口入参出参 ├── config // 配置类(CORS、拦截器等) ├── common // 公共类(统一返回结果、异常处理器等) └── utils // 工具类

分层最核心的原则是:Controller 里不写业务逻辑,只做参数接收和结果包装;Service 里不出现 SQL,只声明调用 Mapper 接口;Mapper 只负责数据访问。这样划分后,后面前端联调时出了问题,可以迅速锁定是哪个层的问题。

启动类只需要一个 SpringBootApplication 注解,配合 application.yml 里的数据源配置就可以连接数据库。MyBatis 的集成就两个关键点:pom.xml 引入 mybatis-spring-boot-starter,配置文件中指定 mapper.xml 的位置即可。

mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.bookstore.entity

很多第一次写项目的人容易在 mapper.xml 的路径上踩坑,这里提前提醒一下:如果配置文件里写了 classpath:mapper/*.xml,那 resources 目录下必须建一个 mapper 文件夹,把所有的 XML 文件都放进去,路径写错指向不存在时启动不会立即报错,等调用查询接口时才报 “Invalid bound statement”。排查这类问题很费时间,不如一开始就路径写对。

2.2 统一返回结果与全局异常处理

刚开始写前后端分离项目时,年轻的开发同学最容易犯的错误是每个接口返回的格式都不一样。有的接口返回 JSON 对象,有的直接返回 List,有的返回一个小 Map,前端对接的时候每人还得单独写一套解析逻辑。联调现场堪称灾难。

我的做法是在 common 包里定义一个统一返回类 Result。结构固定为三个字段:code(状态码)、message(提示信息)、data(业务数据)。成功统一返回 200,失败返回 400 或 500,未登录返回 401。配合一个响应工具方法,让接口返回变得非常清爽:

public class Result { private Integer code; private String message; private Object data; public static Result success(Object data) { Result r = new Result(); r.setCode(200); r.setMessage("操作成功"); r.setData(data); return r; } public static Result error(String message) { Result r = new Result(); r.setCode(500); r.setMessage(message); return r; } }

全局异常处理也建议用一个 @RestControllerAdvice 来统一拦截。后端最怕的是 SQL 异常、空指针异常裸奔到前端,前端看到一串英文堆栈根本没法处理。有了全局异常处理器,所有未捕获异常都会转成 Result.error 的格式返回,用户看到的永远是“系统繁忙,请稍后再试”这类友好提示,而不是一大堆看不懂的报错。这个设计虽然代码量不大,但在答辩时讲出来很加分。

2.3 登录认证与校验机制实现

图书商城涉及用户和管理员两类身份,登录认证这块必须做,否则购物下单的接口谁都能调,业务逻辑就形同虚设。我用的是基于 Token 的认证方案,不是传统的 Session。

用户登录成功后,后端生成一个有效期为 2 小时的 Token(可以用 UUID 简单生成,也可以引入 JWT 做带签名的 Token),存到 Redis 里,同时把 Token 返回给前端。前端把 Token 存在 localStorage 或 Vuex 中,之后每次请求在 axios 拦截器里自动带上 Authorization 请求头。后端配置一个拦截器,统一校验请求头里的 Token,判断用户是否登录。

对 Token 失效的问题,我的处理方式是拦截器里先查 Redis,如果不存在直接返回 401,前端收到 401 后统一跳转到登录页。能够把这个认证方案和缓存中间件结合的逻辑在答辩时讲清楚,至少证明你不是只会写 CRUD。

管理员接口还需要额外的权限控制,我用一个简单的方案解决:管理员表的 Token 带上一个标识字段,拦截器校验到请求路径以 /admin/ 开头时,额外检查 Token 对应身份是否管理员,不是直接拒绝。相比引入 Shiro 或 Spring Security 这种完整安全框架,这个轻量方案在毕业设计项目里完全够用了。

2.4 图书检索与分页查询的实现细节

图书检索是商城面向用户的核心功能,也是 MyBatis 动态 SQL 展示技巧的好地方。常见的检索条件包括:关键字匹配书名或作者、分类筛选、按价格区间过滤、按价格或销量排序。这些条件组合变化多端,用静态 SQL 很难覆盖全部可能性,必须用到 MyBatis 的 和 标签。

我设计的 Mapper XML 大致逻辑如下:

<select id="searchBooks" resultType="com.example.entity.Book"> SELECT * FROM book <where> <if test="keyword != null and keyword != ''"> AND (title LIKE CONCAT('%', #{keyword}, '%') OR author LIKE CONCAT('%', #{keyword}, '%')) </if> <if test="categoryId != null"> AND category_id = #{categoryId} </if> <if test="minPrice != null"> AND price &gt;= #{minPrice} </if> <if test="maxPrice != null"> AND price &lt;= #{maxPrice} </if> </where> <choose> <when test="sort == 'price_asc'">ORDER BY price ASC</when> <when test="sort == 'price_desc'">ORDER BY price DESC</when> <when test="sort == 'sales_desc'">ORDER BY sales DESC</when> <otherwise>ORDER BY id DESC</otherwise> </choose> </select>

这段 SQL 的核心技巧在于 where 标签自动去掉多余的 AND,choose 标签则让排序规则可以根据前端参数灵活切换。分页我用的是 PageHelper,一个插件引入后,在 Service 层调用 PageHelper.startPage(pageNum, pageSize),紧接着执行的查询会自动套上 limit 分页,返回的 PageInfo 对象里包含了总条数、总页数等分页数据,非常方便。

我实测下来的分页结果返回结构是:总记录数、当前页数据列表、当前页码、每页条数、总页数。前端拿到这些字段后,配合分页组件就可以直接渲染页码按钮。

3. 前端核心实现:Vue 页面搭建与业务交互

3.1 Vue 工程结构与路由设计

前端工程我用 Vue CLI 搭建,项目结构清晰分区:

src ├── api // 接口请求封装(统一 axios 实例) ├── assets // 静态资源 ├── components // 通用组件(轮播图、图书卡片等) ├── router // 路由配置 ├── store // Vuex 状态管理 ├── views // 页面组件(前台页面 + 后台页面) ├── utils // 工具函数 └── App.vue

路由设计是整个前端项目的骨架,我把路由分成两块逻辑:前台商城和后台管理。前台路由包括首页、图书列表页、图书详情页、购物车页、订单确认页、订单列表页、登录注册页;后台路由独立挂在一个 /admin 前缀下,布局用侧边栏加顶栏的经典管理界面结构。

路由守卫是必须做的一步。没有登录的用户访问购物车、订单这些需要身份的页面时,应该被自动引导到登录页。在 Vue Router 的 beforeEach 钩子里判断路由元信息中是否标记了 requiresAuth,如果有就检查 Vuex 里的 token 是否存在:

router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { const token = store.state.user.token if (!token) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() } } else { next() } })

这个方案的体验非常好:用户没登录时点购物车,会被带到登录页,并且登录成功后还能自动跳回原来想去的页面,而不是被丢到首页重新找路。

3.2 图书展示与购物车交互实现

图书展示页的核心是把后端返回的列表数据渲染成卡片。我用 Element UI 的 el-card 和 el-row/el-col 布局来排列图书卡片,每张卡片上展示封面、书名、作者、价格和“加入购物车”按钮。首页的推荐位和图书列表页可以共用同一个 BookCard 组件,只要传入的数据结构一致即可。

购物车的状态管理是前端项目的重点和难点。我选择把购物车数据放在 Vuex 里统一管理,绝对值比在组件里通过 props 传递要可靠。用户点击“加入购物车”,前端调后端接口把数据真实写入数据库,同时把 Vuex 里的购物车数量同步加一。

购物车页面的交互逻辑点比较多:勾选条目计算总价、修改数量重算小计、删除条目、已选条目数量统计。这里我建议把“勾选状态”也维护在 Vuex 的 state 中,每个购物车条目包含 checked 字段。结算总价就通过一个 getter 实时计算所有 checked 为 true 的条目的单价乘以数量之和。用 Vuex 的好处是:用户在购物车页和订单确认页之间跳转时,选中的条目和数量不会丢失。

const store = new Vuex.Store({ state: { cartItems: [], selectedItems: [] }, getters: { cartTotalPrice(state) { return state.cartItems .filter(item => item.checked) .reduce((sum, item) => sum + item.price * item.quantity, 0) } } })

订单确认页会展示一个购物车已选图书的清单和总金额,用户填写收货地址后提交订单。这里的流程衔接要注意:提交订单后要把 Vuex 里对应的购物车条目清掉,并且跳转到订单列表页,不能让用户再点一次“提交”产生重复订单。

3.3 订单流转与状态管理

订单状态是整个商城业务逻辑的主线,前后端对这个状态的定义必须完全一致。我定义的订单状态有五种:待支付、已支付、待发货、已发货、已完成,额外加上已取消。对应状态流转:

  • 用户提交订单 -> 待支付
  • 用户完成支付(模拟支付即可) -> 已支付
  • 管理员发货 -> 已发货
  • 用户在确认收货后 -> 已完成
  • 未支付的订单超过时效或用户主动取消 -> 已取消

前端的订单列表页需要根据当前状态显示不同的操作按钮。待支付订单显示“去支付”“取消订单”,已发货订单显示“确认收货”,已取消订单就没有操作按钮。这个逻辑用 Vue 的条件渲染就能实现。

为了保证前后端状态语义一致,我会在代码里建一个常量文件统一管理状态值和对应的中文标签。推荐的做法是:后端用数字或英文字符串存储,前端维护一个状态映射表来渲染。比如订单状态显示,一对一的 switch-case 即可完成状态标签的渲染。这种处理虽然简单,但确实能在联调时少很多沟通成本。

4. 常见问题与排查技巧实录

4.1 前端接口跨域问题:原理与解决方案

前后端分离项目里最大的拦路虎就是跨域问题。前端跑在 8080 端口,后端跑在 8081 端口,浏览器基于同源策略,默认会拒绝后端返回的数据,直接表现就是浏览器控制台报出 CORS error。

跨域的解决方案比较推荐在 SpringBoot 后端进行全局配置。创建一个 WebMvcConfigurer 配置类,重写 addCorsMappings 方法,允许指定来源跨域访问,同时允许携带 Token 请求头。我写了一个通用版本:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

要注意的是 allowedOriginPatterns 和 allowCredentials true 必须搭配使用,如果前端请求需要带上 Token,credentials 不能省。这个配置加上后,绝大部分跨域问题都能解决。

还有一种情况是团队开发时,后端启动端口和前端 vite.config.js 里的代理目标不一致,也会导致 404。但在这里我使用代理方案作为备选,因为最终部署时前后端可能不在同一域下,CORS 配置才是根本解。

4.2 MyBatis 参数映射与 XML 编写常见错误

MyBatis 的 XML 文件里最容易出问题的是参数类型不匹配。比如传入一个 Integer 类型的 categoryId,但 XML 里写 # {categoryId} 与实体属性名不一致时,查询结果就是空的。我的排查顺序是:先看 Mapper 接口方法的参数名是否和 SQL 里的 #{xxx} 完全一致,如果有多个参数,用 @Param 注解显式声明参数名。

另一个高频坑是 LIKE 查询没有生效。很多人写成 LIKE '%#{keyword}%',但这是错误的写法,#{} 在外面套单引号会导致 SQL 语法错误。正确的做法是使用 CONCAT 函数拼接,我在前面的搜索 SQL 示例中已经展示过。

还有分页插件 PageHelper 的一个大坑是:startPage 之后必须紧跟第一条查询 SQL,中间不能插入其他查询语句,否则分页会失效或作用到错误的查询上。我维护代码的时候见到过同事在 startPage 后面打印了日志调用了 mapper 查询,结果分页就乱了。这个顺序问题几乎看一次记一次。

4.3 前后端联调时的常见场景与解决思路

联调阶段最常见的现象是“前端调接口报 404”,排查步骤其实固定且简单:先确认后端服务的 context-path 是否配置了额外路径,再对比前端请求的 URL 是否完整拼接了后端地址和控制器的 RequestMapping 注解路径。报 500 时优先看后端控制台日志,按堆栈提示定位。

我遇到过的一个很典型的问题是:前端把价格字段传成字符串,后端用 BigDecimal 接收导致类型转换异常。这种问题本质上是前后端数据契约没约定好,解决方法是前端在传参前做好类型转换,后端在 DTO 字段上增加校验注解,比如 @NotNull、@DecimalMin 等,保证入库数据的基本合法性。

Token 失效导致的操作无响应也经常遇到。前端只报 401,用户以为系统坏了。我的做法是在 axios 的响应拦截器里统一处理:

service.interceptors.response.use( response => { const res = response.data if (res.code === 401) { store.commit('user/logout') router.push('/login') } return res }, error => { return Promise.reject(error) } )

这样所有接口只要返回 401,就会自动做登出跳转,用户感知到的就是“登录过期,需要重新登录”,而不是按钮点了没反应。

4.4 一个容易被忽略的坑:数据库连接时区与编码

数据库连接串配置不当会引发连锁的时区和中文乱码问题。如果 URL 里的 serverTimezone 没配,SpringBoot 启动连接数据库时会直接报 “The server time zone value” 错误,你必须手工指定时区。

我习惯在数据源配置中一次性把所有参数写全:

spring: datasource: url: jdbc:mysql://localhost:3306/bookstore?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver

进入建库建表语句里一定要注意设置 utf8mb4 字符集,否则存一些特殊字符(比如书名里有特殊符号)时会报 “Incorrect string value” 错误。建库时直接用 CREATE DATABASE bookstore DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;,这样后期一些麻烦就可以从源头规避掉。控制台里发现中文乱码时,排查顺序是先看数据库连接的编码配置,再看前端页面的 meta charset。

5. 项目运行指南与二次开发建议

5.1 带完整源码的项目该如何快速跑起来

拿到一份完整的图书商城源码,第一步不是急着看代码,而是先把环境梳理清楚。我这个项目的运行环境是:JDK 8、Maven 3.6+、MySQL 5.7+、Node.js 14+。三个核心服务缺一不可。

后端启动步骤:

  1. 在 MySQL 中执行项目提供的 bookstore.sql 脚本,生成数据库和基础数据(含管理员账号)。
  2. 修改 application.yml 里的数据库账号密码。
  3. 在项目根目录执行 mvn spring-boot:run,或者打包后执行 java -jar bookstore.jar。

前端启动步骤:

  1. 进入 frontend 目录,执行 npm install 安装依赖(这个看网络情况,国内镜像比较稳)。
  2. 检查前端开发环境的代理配置,确保后端地址正确。
  3. 执行 npm run serve 启动开发服务。

启动完成后,前端访问 http://localhost:8080,后端接口访问 http://localhost:8081。建议先用管理员账号登录后台,再注册一个用户账号体验前台完整流程。

我在这类项目里遇到的最多的启动失败原因,不是代码问题,而是环境版本不匹配。比如用了 JDK 17 去跑旧项目,SpringBoot 2.x 的某些反射操作会直接异常;MySQL 8 的驱动和 5.7 在配 driver-class-name 时选择也不同。所以,复现项目时先看清楚项目的 pom.xml 声明的版本号,再对照自己电脑的环境,能省掉大量折腾时间。

5.2 扩展方向与优化建议

图书商城做一个能跑通的版本不难,但如果想让项目在答辩时被问到时更有深度,我建议在以下几个方向做扩展。

第一个方向是支付流程深化。现状是模拟支付,点一下按钮直接改状态,如果能把模拟支付改成接入第三方沙箱支付环境,整个交易闭环就真实多了,同时也能加深对支付回调机制的理解。

第二个方向是搜索体验升级。当前的关键字检索用的是 MySQL 的 LIKE 模糊查询,数据量小的时候没问题,如果图书量级上万,查询性能会直线下降。可以引入全文检索方案(如 Elasticsearch)做商品搜索,但作为中小项目,我更推荐先给 book 表的 title 字段加索引,然后配合 MySQL 全文索引优化。

第三个方向是增加缓存层。把首页热点图书、图书分类这类读多写少的数据放到 Redis 里缓存,设置过期时间,可以在答辩中展示你对性能优化的思考。不一定要做得多复杂,但思路完整很重要。

第四个方向是部署方式优化。本地开发在 IDE 里跑很简单,但部署上线时可以采用前后端分离部署:后端打包成 Docker 镜像,前端打包后用 Nginx 托管静态文件,再配置反向代理到后端接口。这部分如果会玩,对整个项目的完整性理解会有很大的提升。

6. 项目实战中的核心心得

6.1 技术栈选型决定了项目的上限

图书商城管理系统这个题目,每年都有大量人做,但为什么有的作品只能停留在“能用”,有的却能让人眼前一亮?关键在于技术选型和实现深度的组合。SpringBoot + Vue 只是一个起点,真正拉开差距的是登录方案选的是 Session 还是 Token,购物车放数据库还是 localStorage,订单状态设计是否考虑全流程,这些细节叠加起来才是一个完整项目。

6.2 代码组织整洁对调试效率的影响会直接体现在开发周期上

我见过一段 Controller 里塞了 200 行代码的项目,功能是能跑,但排查问题时一行行断点找,效率非常低。分层设计虽然前期多写了几个类,但后期无论是加功能还是修 Bug,定位都能很快。这也是我在文中反复强调分层和统一返回结构的原因。

6.3 真正动手写一个前后端分离项目,收获远大于只看教程

图书商城系统的完整代码量大概在几千行,相比一些更复杂的电商系统已经压缩了不少,但麻雀虽小五脏俱全。把这本书商城完整做一遍,你会同时掌握 RESTful 接口设计、MyBatis 动态 SQL、Vue 组件通信、路由守卫、状态管理等一整套真实开发流程中高频使用的能力。

最后再说一个我在实操中特别受用的习惯:每次写完一个模块,先自己用 Postman 把接口完整调一遍,再通知前端联调,前端报的很多“接口有问题”其实都是后端自测不充分导致的。项目做完之后,多用这两个动作审视自己:一是所有接口返回格式是否统一,二是所有失败场景是否有明确的文案提示。这两个目标达到了,项目的成熟度就会明显上一个台阶。

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

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

立即咨询