恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Spring Boot + Vue 民宿管理平台:单体架构、订单状态机与JWT鉴权实战

  • 首页
  • 资讯中心
  • /
  • Spring Boot + Vue 民宿管理平台:单体架构、订单状态机与JWT鉴权实战

相关资讯

IoT-For-Beginners 第 9 课:用 Azure Functions 无服务器架构将农田灌溉继电器控制逻辑迁移上云 2026/9/16 18:18:13
GVIM配置失效原因与跨平台稳定设置方法 2026/9/16 18:13:13
前端如何播放m3u8视频流?HLS协议与hls.js实战指南 2026/9/16 18:13:13

最新资讯

开源鸿蒙Flutter进阶:动效性能优化与工程闭环实战复盘
自研CRM系统实战:从技术选型到客户数据架构的踩坑指南
实发功率与可用功率:新能源场站并网考核与功率预测的核心口径
从无人机航拍到上帝视角:全景拼接与正射影像实战指南
数字隔离与电平转换协同设计:SPI接口鲁棒性实战指南
使用 AWS CLI 的 merge-branches-by-three-way 命令在 CodeCommit 中进行三路合并

今日推荐

IoT-For-Beginners 智能语音计时器:Wio Terminal 基于 DMAC 与 Flash 的音频采集实战
基于MATLAB的CRI显色指数计算:从SPD光谱到Ra的完整流程
JSP+Servlet+MySQL博客系统源码部署与优化全攻略

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Spring Boot + Vue 民宿管理平台:单体架构、订单状态机与JWT鉴权实战

发布时间:2026/9/16 18:18:13
Spring Boot + Vue 民宿管理平台:单体架构、订单状态机与JWT鉴权实战 简介面向毕业设计的Spring Boot民宿管理平台项目完整交付包适合计算机相关专业学生、毕业设计选题者及Java初学者参考学习。项目基于Spring BootVue前后端分离架构采用JDK1.8、MySQL5.7、Maven构建覆盖管理员、用户、商家三类角色包含首页个人中心、用户管理、商家管理、民宿信息管理、房间类型/信息管理、房间预订/退订管理、投诉反馈管理、我的收藏管理、系统管理等核心业务模块前台则提供民宿信息展示、房间浏览、个人中心、后台入口及在线客服等功能业务逻辑完整模块划分清晰便于二次开发。压缩包约24.03MB主要包含Java源码、Vue前端代码、SQL数据库脚本、说明文档、LW论文及答辩PPT可直接导入Eclipse/IDEA等IDE运行。资源已有328人学习借助源码、论文与PPT读者可快速掌握系统设计思路、数据库关系及接口实现适用于课程设计、毕业设计或项目实训。1. 民宿管理平台为什么用 springbootvue 单体会比微服务更省事民宿管理平台听起来是一个不小的系统但把业务拆开看核心只有四条线用户注册登录、民宿房源展示与上下架、在线预订与订单状态流转、退房后的评价。四条线之间没有高并发、没有跨团队协作也没有独立伸缩的需求。用 springboot 做单体后端、vue 做前后端分离页面是这个规模下开发效率最高、测试成本最低、演示效果最稳的组合。把一个空目录跑到出界面通常只需要两个终端加一个 MySQL。带项目时最常被问的是“要不要上微服务”我的建议很直接不要。微服务引入的注册中心、配置中心、网关和分布式事务在这个业务量级下全是负资产。真正值得花时间的是表结构设计、订单状态机、token 鉴权这三件事。本文按这三条主线从数据模型讲到 vue 页面最后落到“给出去的源码别人能不能原地跑通”。2. 数据模型先行民宿核心表与 springboot 实体映射抛开页面先把数据边界划清楚。民宿管理平台通常只需要四张核心业务表t_user用户与管理员、t_house房源、t_order预订订单、t_comment评价。再有额外需求比如轮播图、优惠券、操作日志都属于外围表不影响主流程。表的数量控制在十张以内对一个 springboot 单体项目来说是健康的面试时也能用五分钟讲完。2.1 四张核心表的职责划分与字段设计表职责关键字段与业务的关系t_user系统用户username / password / rolerole 区分管理员与 C 端用户t_house可预订房源name / type / price / status房态与定价的核心t_order订单主表order_no / user_id / house_id / check_in / check_out / status串联用户与房源t_comment订单评价order_id / content / rating提升复购与筛选参考用户表与订单表是一对多房源表与订单表也是一对多订单与评价是一对一。设计时不要为了“看起来完整”加一堆冗余字段比如把用户名冗余进订单表改一次用户名就要同步好几张表。查询时用 VO 组装即可。下面给出订单表的建表 SQL这是整个平台最关键的三十行CREATE TABLE t_order ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, order_no varchar(32) NOT NULL COMMENT 订单号前端展示用, user_id bigint NOT NULL COMMENT 下单用户ID, house_id bigint NOT NULL COMMENT 房源ID, check_in date NOT NULL COMMENT 入住日期, check_out date NOT NULL COMMENT 离店日期, nights int NOT NULL COMMENT 入住晚数, amount decimal(10,2) NOT NULL COMMENT 订单总金额, status tinyint DEFAULT 0 COMMENT 0待支付 1已支付 2已入住 3已退房 4已取消, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user (user_id), KEY idx_house (house_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT民宿预订订单表;status 字段是这张表的核心。不要用字符串存状态tinyint 存数字码前端维护一个映射数组就能翻译成中文状态。金额用 decimal(10,2) 而不是 floatfloat 在累加和比较时会出现精度问题这在结算场景里是不能接受的。create_time 交给数据库默认值应用层不必每次手动维护。2.2 用 Spring Data JPA 映射实体以订单表为例项目里用 JPA 还是 MyBatis 一直是有争论的。我的习惯是业务表之间关系强的用 Spring Data JPASQL 复杂的用 MyBatis-Plus。民宿管理平台没有复杂 join用 JPA 的 Repository 接口就能覆盖增删改查代码量最少分页也是开箱即用。有人担心 JPA 的懒加载和 N1 问题在这个表数量级下只要不在循环里查关联表性能完全不是瓶颈。Entity Table(name t_order) public class Order { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(name order_no, length 32) private String orderNo; Column(name user_id) private Long userId; Column(name house_id) private Long houseId; Column(name check_in) private LocalDate checkIn; Column(name check_out) private LocalDate checkOut; private Integer nights; private BigDecimal amount; private Integer status; Column(name create_time) private LocalDateTime createTime; // getter / setter 省略 }这里故意用 Long 类型的 userId、houseId 保存外键而不是加 ManyToOne。原因有两个一是避免 JSON 序列化时把关联对象整个带出去前端平白多收一包用不上的数据二是列表分页时不会触发懒加载省掉 join fetch 的调优步骤。需要显示房源名称时在 Service 里用 houseRepository.findById 查一次再塞进 VO 即可。这个小取舍能让代码容易读很多。Repository 接口写起来也很短public interface OrderRepository extends JpaRepositoryOrder, Long { Query(select o from Order o where o.userId :userId order by o.createTime desc) PageOrder findUserOrders(Param(userId) Long userId, Pageable pageable); long countByStatus(Integer status); }Pageable 是 Spring Data 内置的分页抽象Controller 层接收 page、size 参数直接 new PageRequest.of(page - 1, size) 传给 Repository。countByStatus 这类派生查询方法springboot 会自动实现不需要手写 SQL。统计仪表盘要显示“今日订单量”“待支付数量”时这种小方法能省大量样板代码。2.3 建表策略spring.jpa.hibernate.ddl-auto 怎么设很多初学者直接设成 update本地调试确实方便但一旦交付或部署Hibernate 对字段类型的隐式变更很容易把一张有数据的表改出问题。推荐做法是开发初期让 update 生成一次表结构然后导出成 SQL 脚本放进项目的 db/ 目录后续环境统一用脚本初始化实体层把 ddl-auto 改成 validate。这样启动时 Hibernate 只做结构校验不一致会直接报错逼着你把变更写进脚本。spring: datasource: url: jdbc:mysql://localhost:3306/homestay?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root jpa: hibernate: ddl-auto: validate show-sql: trueshow-sql 在本地调试时打开能直接看到每次请求背后的 SQL 语句排查懒加载和分页异常非常有用。上线时把它关掉不然日志会被 SQL 刷屏。serverTimezone 必须显式声明否则高版本 MySQL 驱动会因为你本机时区和数据库时区不一致在写入 LocalDateTime 时莫名其妙偏了八个小时。3. springboot 后端实现统一响应、订单状态机与 JWT 拦截器后端部分按 Controller → Service → 鉴权拦截器三层讲这也是 springboot 项目里最容易被面试官追着问的结构请求怎么进来、事务怎么控制、权限怎么校验。3.1 统一返回结构先定 Result再写接口前后端分离项目最怕接口返回格式不统一。有的接口返回{data: ...}有的返回{rows: ...}前端封装 axios 拦截器时就得写一堆分支判断。先把一个通用结果类定下来后面所有接口都只回这一种形状。Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.setCode(200); r.setMessage(ok); r.setData(data); return r; } public static T ResultT error(Integer code, String message) { ResultT r new Result(); r.setCode(code); r.setMessage(message); return r; } }code 用 200 表示成功业务异常用 50001、50002 这类自定义编号HTTP 状态码保持 200。这样做的好处是前端拦截器统一看 code 就好不用在 HTTP 层做语义解析网络层断网之类的真实错误仍由 HTTP 状态码表达。Controller 层代码会非常整齐RestController RequestMapping(/api/order) public class OrderController { private final OrderService orderService; public OrderController(OrderService orderService) { this.orderService orderService; } PostMapping(/create) public ResultOrderVO create(RequestBody Valid OrderCreateDTO dto) { return Result.success(orderService.createOrder(dto)); } GetMapping(/page) public ResultPageResultOrderVO page(RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size, RequestParam(required false) Integer status) { return Result.success(orderService.pageOrders(page, size, status)); } }构造器注入比 Autowired 字段注入更利于测试springboot 的官方文档也推荐这种方式。Valid 配合 DTO 上的 NotNull、Future 注解可以在进入 Service 之前把参数校验做掉省去 Service 里手写一长串 if 判断。3.2 订单状态机与事务控制订单状态机是整个平台最值得讲的部分。民宿订单的状态流转是单向的待支付可以变成已支付也可以变成已取消已支付只能变成已入住已入住只能变成已退房。绝不允许出现已退房又跳回待支付的情况。用代码硬编码每个允许的转移路径比散落一堆 if 判断可靠得多。当前状态允许流转到触发动作待支付(0)已支付(1)、已取消(4)支付回调 / 用户取消已支付(1)已入住(2)前台办理入住已入住(2)已退房(3)办理离店结算已退房(3)无终态已取消(4)无终态Transactional(rollbackFor Exception.class) public OrderVO createOrder(OrderCreateDTO dto) { House house houseRepository.findById(dto.getHouseId()) .orElseThrow(() - new BizException(50001, 房源不存在)); if (house.getStatus() ! 1) { throw new BizException(50002, 该房源已下架); } long nights ChronoUnit.DAYS.between(dto.getCheckIn(), dto.getCheckOut()); if (nights 0) { throw new BizException(50003, 离店日期必须晚于入住日期); } Order order new Order(); order.setOrderNo(HS System.currentTimeMillis()); order.setUserId(dto.getUserId()); order.setHouseId(house.getId()); order.setCheckIn(dto.getCheckIn()); order.setCheckOut(dto.getCheckOut()); order.setNights((int) nights); order.setAmount(house.getPrice().multiply(BigDecimal.valueOf(nights))); order.setStatus(0); orderRepository.save(order); OrderVO vo new OrderVO(); BeanUtils.copyProperties(order, vo); vo.setHouseName(house.getName()); return vo; }Transactional 在这里保证了两件事订单写入失败时房源的状态不会被半修改异常抛出时整个事务回滚。rollbackFor Exception.class 是必须的因为 Spring 默认只回滚 RuntimeException 和 Error如果你在事务方法里抛了一个自定义的 checked exception它不会回滚数据就残了。状态流转单独抽一个方法Transactional public void changeStatus(Long orderId, Integer targetStatus) { Order order orderRepository.findById(orderId) .orElseThrow(() - new BizException(50004, 订单不存在)); int[][] allowed {{0, 1}, {0, 4}, {1, 2}, {2, 3}}; boolean pass Arrays.stream(allowed) .anyMatch(a - a[0] order.getStatus() a[1] targetStatus); if (!pass) { throw new BizException(50005, 当前状态不允许变更); } order.setStatus(targetStatus); orderRepository.save(order); }用二维数组定义状态转移表代码短且一眼能看全所有合法路径。有人会用枚举或状态模式实现在这个规模下反而显得繁琐。面试时把这个转移表讲清楚比背八股文里的“Spring 事务传播行为有七种”有用得多因为这是你真实设计过的业务规则。3.3 JWT 登录鉴权与拦截器配置登录模块常见方案是 Session Cookie 或 JWT。前后端分离的项目里 JWT 更合适后端不存 sessiontoken 里直接携带 userId 和 role前端每次请求带在 Authorization 头里。引入 jjwt 依赖即可不需要额外引 Spring Security除非你要处理复杂的角色权限树。dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version0.11.5/version scoperuntime/scope /dependency3.3.1 JWT 工具类的核心方法public class JwtUtil { private static final SecretKey SECRET Keys.hmacShaKeyFor( homestay-platform-jwt-secret-key-please-change.getBytes(StandardCharsets.UTF_8)); private static final long EXPIRE 24 * 60 * 60 * 1000L; public static String createToken(Long userId, Integer role) { return Jwts.builder() .claim(uid, userId) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE)) .signWith(SECRET, SignatureAlgorithm.HS256) .compact(); } public static Claims parseToken(String token) { return Jwts.parserBuilder() .setSigningKey(SECRET) .build() .parseClaimsJws(token) .getBody(); } }SecretKey 至少 32 个字节否则 HS256 会报错。生产环境里这个 key 不应该硬编码用配置文件注入并且定期轮换。过期时间设 24 小时民宿管理后台的使用频率下足够用户长期未操作时可以配合前端路由守卫做二次登录。这里用 role 字段区分管理员与普通用户后续要在某个接口上限制仅管理员可操作直接从 token 里取值判断不用查数据库。3.3.2 拦截器注册与放行规则Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String auth request.getHeader(Authorization); if (auth ! null auth.startsWith(Bearer )) { try { Claims claims JwtUtil.parseToken(auth.substring(7)); request.setAttribute(userId, claims.get(uid)); request.setAttribute(role, claims.get(role)); return true; } catch (Exception e) { // 解析失败说明 token 过期或伪造 } } response.setStatus(401); return false; } }Bearer 前缀是行业惯例解析时用 substring(7) 去掉它。OPTIONS 请求是浏览器跨域预检必须直接放行否则前端联调时跨域配置正确了也会卡在预检阶段。Configuration public class WebConfig implements WebMvcConfigurer { private final JwtInterceptor jwtInterceptor; public WebConfig(JwtInterceptor jwtInterceptor) { this.jwtInterceptor jwtInterceptor; } Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns(/api/**) .excludePathPatterns( /api/user/login, /api/user/register, /api/house/list ); } }放行规则里只放行登录、注册、房源列表查询。注意不要顺手把/api/order/**放行那样任何人都能查别人的订单。登录接口本身不需要 token因为 token 是登录成功后才发的。拦截器比过滤器适合这个场景它能拿到 Handler 信息后续想基于 RequireAdmin 这类自定义注解做细粒度权限控制时扩展成本为零。4. vue 前端搭建Vite 脚手架、Axios 封装与后台页面组件化前端部分的核心是三个基建路由、请求封装、组件库。页面本身是重复劳动把这三个底座搭好后面的房源管理、订单管理、统计报表都能堆得很快。4.1 Vite 创建 Vue3 项目与必备依赖vue3 项目推荐用 Vite 而不是 Vue CLI启动速度和热更新体验差距很明显。创建项目时直接指定模板省得手动补配置。npm create vitelatest homestay-admin -- --template vue cd homestay-admin npm install npm install element-plus axios vue-router4 echarts npm run devcreate vite 的参数里homestay-admin 是项目名--template vue 生成的是 Vue3 单页应用基础模板。element-plus 是 UI 组件库axios 负责请求vue-router4 是 Vue3 对应的路由版本echarts 给统计报表用。npm install 装依赖时如果网络慢可以切到 npmmirror 镜像源不影响项目本身。场景推荐组合说明管理后台Vue3 Element Plus组件全文档对中文友好表格表单开箱即用老项目迁移Vue2 Element UI已停止大版本更新保留维护可以移动端 C 端Vant 4民宿小程序或 H5 预订页可用项目结构上页面放进 src/viewsAPI 调用放进 src/api公共组件放进 src/components。在 vite.config.js 里配置 别名指向 src不然每个文件里写 ../../../api/order 会非常痛苦。import { defineConfig } from vite import vue from vitejs/plugin-vue import { resolve } from path export default defineConfig({ plugins: [vue()], resolve: { alias: { : resolve(__dirname, src) } } })4.2 Axios 实例封装与 API 模块化管理axios 实例封装是整个前端的命脉。所有请求走同一个实例统一加 token、统一处理 401、统一弹错误提示。import axios from axios import { ElMessage } from element-plus import router from /router const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use((config) { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) service.interceptors.response.use( (response) { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res }, (error) { if (error.response?.status 401) { localStorage.removeItem(token) router.push(/login) } else { ElMessage.error(error.message) } return Promise.reject(error) } ) export default servicebaseURL 用 /api 而不是完整地址是为了配合开发环境的 Vite 代理和后端的统一前缀。请求拦截器从 localStorage 取 token 塞进 Authorization 头前端路由守卫只负责页面跳转真正拦非法请求的是后端拦截器前端这层只是体验优化。响应拦截器里 code 不为 200 时统一弹错误消息业务代码里就不用每个接口都写 catch 了。401 时清 token 跳登录页用户重新登录后回到工作台这个闭环体验比较自然。API 模块按业务拆分页面里不直接调 axiosimport service from /utils/request export function getOrderPage(params) { return service.get(/order/page, { params }) } export function createOrder(data) { return service.post(/order/create, data) } export function changeOrderStatus(orderId, targetStatus) { return service.put(/order/status/${orderId}, { targetStatus }) }页面里 import 这些函数语义清楚后端接口路径改动时也只动 api/ 目录下的文件不用满项目搜字符串。4.3 订单页面与数据可视化状态映射、分页与 ECharts 图表订单管理页是后台最常见的列表页形态。用 Element Plus 的 el-table 展示数据el-pagination 做分页状态字段做映射而不是直接在模板里写数字比较。template el-card el-table :dataorders v-loadingloading stripe el-table-column proporderNo label订单号 width200 / el-table-column prophouseName label房源 / el-table-column propcheckIn label入住日期 / el-table-column propcheckOut label离店日期 / el-table-column propnights label晚数 width70 / el-table-column propamount label金额 / el-table-column label状态 width100 template #default{ row } el-tag :typestatusType[row.status] sizesmall {{ statusText[row.status] }} /el-tag /template /el-table-column /el-table el-pagination v-model:current-pagequery.page v-model:page-sizequery.size :totaltotal layouttotal, prev, pager, next current-changeloadOrders / /el-card /template script setup import { onMounted, reactive, ref } from vue import { getOrderPage } from /api/order const orders ref([]) const total ref(0) const loading ref(false) const query reactive({ page: 1, size: 10 }) const statusText [待支付, 已支付, 已入住, 已退房, 已取消] const statusType [warning, primary, success, info, danger] async function loadOrders() { loading.value true try { const res await getOrderPage(query) orders.value res.data.records total.value Number(res.data.total) } finally { loading.value false } } onMounted(loadOrders) /script这里有两个常见的 vue 联调坑。第一个是 total 字段后端 JPA 的 Page.getTotalElements() 返回 longJSON 序列化后是数字字符串Element Plus 的分页组件要求 number所以代码里做了 Number() 转换。第二个是 v-loading 要一直抖到数据回来finally 里关闭避免接口报错时 loading 永远转圈。数据可视化页用 ECharts 展示订单趋势。民宿管理平台最常用的图是近 7 日订单量柱状图和房型占比饼图。查询后端统计接口拿到日期和数量两个数组直接 setOption 即可import * as echarts from echarts const chartRef ref(null) onMounted(async () { const res await service.get(/statistics/weekly-orders) const chart echarts.init(chartRef.value) chart.setOption({ xAxis: { type: category, data: res.data.dates }, yAxis: { type: value }, series: [{ type: bar, data: res.data.counts }] }) })ECharts 的 init 必须在 DOM 渲染完成后调用所以一般在 onMounted 里执行。如果容器宽度变化导致图表变形调用 chart.resize() 修复。统计接口返回的数据结构要跟图表字段严格对齐dates 和 counts 两个数组下标一一对应。这种报表页面在答辩或项目汇报时是最直观的展示素材比截十几张表格页面有效得多。5. springboot 打包部署跨域配置、版本陷阱与交付检查清单项目本地跑通只是第一步交付时还要过三道关跨域、打包、文档一致性。这三件事不做好换一台电脑就起不来的项目会让“完整源码”四个字失去意义。5.1 联调阶段的跨域处理Vite 代理与后端 CORS 二选一开发时 vue 跑在 5173 端口springboot 跑在 8080 端口直接发请求必然跨域。常见做法是 Vite 代理前端代码里不写后端地址统一走 /api 前缀。// vite.config.js export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })changeOrigin 必须为 true否则后端拿到的 Host 头是前端的地址某些场景下会引发问题。如果后端单独部署、前端代码要直连也可以在后端 WebConfig 里配置 CORS但生产环境更推荐用 Nginx 把前端静态文件和 /api 代理配在同一个 origin 下彻底避开跨域location /api/ { proxy_pass http://127.0.0.1:8080/api/; }5.2 springboot 版本与本地环境变量交付前先锁版本springboot 3.x 要求 JDK 17 和 jakarta.* 命名空间springboot 2.7 只要求 JDK 8/11 和 javax.*。如果一个项目用 2.7 写的交付 README 里却写着要求 JDK 17接手的人会被环境变量配置卡住。交付前把 pom.xml 里的 java.version、spring-boot-starter-parent 的版本号、Node 大版本写清楚。打包命令保持最简单mvn clean package -DskipTests java -jar target/homestay-0.0.1-SNAPSHOT.jar前端构建是 npm run build产物在 dist/ 目录交给 Nginx 托管。如果要在本地把前后端跑通数据库脚本、默认账号、MySQL 版本也要写进 README不要假定别人机器上什么都装好了。5.3 交付验收把源码交给另一个人之前检查这几项验收项操作手法最容易翻车的地方数据库初始化脚本db/schema.sql 按外键顺序建表data.sql 预置管理员账号脚本跑一半报错表建了数据没进默认账号预置 admin/123456密码存密文用户直接拿明文比对数据库发现不一致启动说明README 写 JDK/Maven/Node/MySQL 版本和启动顺序用 Boot 3 却要求别人装 JDK8前端依赖锁定提交 package-lock.json别人 npm install 装出不同版本图片上传路径确认上传目录是配置项而不是硬编码换机器后图片全部 404调试时用 Vue Devtools 看路由参数和组件状态比 console.log 改一版刷一版高效得多。项目里可以加一个自定义 Spring Boot Banner一行配置换一张启动图成本为零答辩演示时启动终端反而成了记忆点。最后验证时把 MySQL 换成新库按 README 从头执行一次初始化脚本、启动后端、启动前端确认没有任何残留状态也能跑通这一步才是“完整源码”真正可复现的标准。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号