ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SpringBoot+Vue宠物咖啡馆系统开发实践

SpringBoot+Vue宠物咖啡馆系统开发实践 1. 项目概述前后端分离宠物咖啡馆平台系统这个基于SpringBootVueMyBatisMySQL技术栈的宠物咖啡馆平台系统是我去年为一个连锁宠物咖啡馆品牌开发的核心业务系统。系统最大的特色是将宠物服务与咖啡餐饮完美结合同时实现了前后端完全分离的架构设计。前端采用Vue.js构建响应式用户界面后端基于SpringBoot提供RESTful API服务通过MyBatis与MySQL数据库进行数据交互。系统主要包含三大核心模块宠物服务管理包括宠物寄养、美容、医疗预约等、咖啡餐饮管理菜单、订单、库存等以及会员中心用户管理、积分系统、评价反馈。这种业务组合模式在当下都市白领养宠人群中特别受欢迎既能享受咖啡时光又能妥善安置宠物。提示选择前后端分离架构时建议在项目初期就明确接口规范。我们团队采用的是SwaggerYAPI的方案前端开发可以基于Mock数据并行工作大幅缩短开发周期。2. 技术选型与架构设计2.1 后端技术栈解析SpringBoot 2.7.4作为后端框架的选择主要基于以下几点考虑自动配置特性大幅减少了XML配置我们的配置类从传统的30个减少到5个核心配置内嵌Tomcat服务器简化了部署流程开发阶段直接通过main方法启动Starter依赖机制让整合MyBatis、Redis等组件变得异常简单数据库选用MySQL 8.0而非5.7版本主要看中了窗口函数对复杂报表查询的性能提升JSON字段类型对宠物健康记录等半结构化数据的支持更好的索引优化效果我们的会员查询响应时间从120ms降至40ms2.2 前端技术架构Vue 3的组合式API相比选项式API更适合我们的复杂交互场景// 宠物预约日历组件示例 const calendarState reactive({ selectedPet: null, availableSlots: [], loading: false }) const fetchSlots async (date) { calendarState.loading true try { const res await api.get(/slots, { params: { date } }) calendarState.availableSlots res.data } finally { calendarState.loading false } }Element Plus作为UI库提供了完善的组件体系特别适合快速构建管理后台。我们通过Sass变量覆盖实现了品牌主题色的全局定制// variables.scss $--color-primary: #8d6e63; // 咖啡色系主题 $--font-path: ~element-plus/lib/theme-chalk/fonts; import ~element-plus/packages/theme-chalk/src/index;3. 核心业务模块实现3.1 宠物服务预约系统这是最具挑战性的模块需要处理复杂的业务规则不同体型宠物小型/中型/大型对应不同的服务价格美容师/医生的时间排班管理宠物疫苗记录等健康信息的关联校验数据库设计采用了多表关联方案CREATE TABLE pet_service ( id bigint NOT NULL AUTO_INCREMENT, pet_id bigint NOT NULL COMMENT 关联宠物ID, service_type varchar(20) NOT NULL COMMENT 服务类型, schedule_id bigint NOT NULL COMMENT 排班ID, status tinyint NOT NULL DEFAULT 0 COMMENT 0-待确认 1-已预约, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_pet (pet_id), KEY idx_schedule (schedule_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.2 咖啡订单管理系统采用状态机模式管理订单生命周期// 订单状态枚举 public enum OrderStatus { PENDING_PAYMENT(1, 待支付), PAID(2, 已支付), MAKING(3, 制作中), COMPLETED(4, 已完成), CANCELLED(-1, 已取消); // 状态转换校验逻辑 public static boolean canTransfer(OrderStatus from, OrderStatus to) { switch (from) { case PENDING_PAYMENT: return to PAID || to CANCELLED; case PAID: return to MAKING; // 其他状态转换规则... } } }库存管理使用乐观锁防止超卖Transactional public boolean reduceStock(Long itemId, int quantity) { int affected productMapper.updateStock( itemId, quantity, LocalDateTime.now() // 使用时间戳作为版本号 ); return affected 0; }4. 系统部署实战指南4.1 后端部署要点生产环境推荐使用JDK17SpringBoot2.7的组合我们在CentOS7上实测QPS比JDK8提升35%数据库连接池配置建议基于HikariCPspring: datasource: hikari: maximum-pool-size: 20 # 根据CPU核心数×21计算 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000日志收集方案采用LogbackELK栈关键配置appender nameELK classnet.logstash.logback.appender.LogstashTcpSocketAppender destination192.168.1.100:5000/destination encoder classnet.logstash.logback.encoder.LogstashEncoder customFields{app:pet-cafe,env:production}/customFields /encoder /appender4.2 前端部署优化使用Docker多阶段构建减小镜像体积从1.2GB优化到45MB# 构建阶段 FROM node:16 as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 生产阶段 FROM nginx:alpine COPY --frombuilder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80Nginx关键性能配置server { listen 80; gzip on; gzip_types text/plain text/css application/json application/javascript; location / { try_files $uri $uri/ /index.html; expires 1y; add_header Cache-Control public; } location /api { proxy_pass http://backend:8080; proxy_set_header Host $host; } }5. 开发中的典型问题与解决方案5.1 MyBatis批量插入优化初期方案性能较差Insert(script insert into pet_health_record (pet_id, item, value) values foreach collectionrecords itemr separator, (#{r.petId}, #{r.item}, #{r.value}) /foreach /script) void batchInsert(Param(records) ListPetHealthRecord records);优化后方案性能提升8倍Options(useGeneratedKeys true, keyProperty id) InsertProvider(type PetHealthSqlBuilder.class, method buildBatchInsertSql) void batchInsert(Param(records) ListPetHealthRecord records); // 自定义SQL构建器 public class PetHealthSqlBuilder { public String buildBatchInsertSql(MapString, Object params) { ListPetHealthRecord records (ListPetHealthRecord) params.get(records); StringBuilder sql new StringBuilder(insert into pet_health_record (pet_id, item, value) values ); for (int i 0; i records.size(); i) { if (i 0) sql.append(,); sql.append((#{records[).append(i).append(].petId}, ) .append(#{records[).append(i).append(].item}, ) .append(#{records[).append(i).append(].value})); } return sql.toString(); } }5.2 Vue组件性能优化问题场景宠物列表页在渲染100项时出现明显卡顿解决方案使用虚拟滚动vue-virtual-scrollerRecycleScroller classscroller :itemspets :item-size72 key-fieldid v-slot{ item } PetCard :petitem / /RecycleScroller优化计算属性避免不必要的重新计算// 优化前 - 每次访问都会重新计算 computed: { filteredPets() { return this.pets.filter(p p.type this.activeType ) } } // 优化后 - 基于响应式依赖缓存 computed: { filteredPets() { const type this.activeType return this.pets.filter(p p.type type) } }6. 安全防护方案6.1 接口安全防护JWT令牌增强措施Configuration public class JwtConfig { Bean public JwtDecoder jwtDecoder() { NimbusJwtDecoder decoder NimbusJwtDecoder .withPublicKey(rsaPublicKey()) .build(); decoder.setJwtValidator(jwtValidator()); return decoder; } private JwtValidator jwtValidator() { return new DelegatingJwtValidator( new JwtTimestampValidator(), new JwtIssuerValidator(pet-cafe-auth), new JwtClaimValidatorListString(roles, roles - roles ! null !roles.isEmpty() ) ); } }防XSS攻击方案// 前端全局过滤器 Vue.filter(escape, function (value) { const div document.createElement(div) div.appendChild(document.createTextNode(value)) return div.innerHTML }) // 后端统一响应处理 ControllerAdvice public class XssProtectionAdvice implements ResponseBodyAdviceObject { Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { return XssUtils.clean(body); } }6.2 数据库安全敏感数据加密方案// 使用Jasypt进行字段级加密 Column Type(type encryptedString) private String creditCardNumber; // 配置Bean Bean public HibernateJpaVendorAdapter jpaVendorAdapter() { HibernateJpaVendorAdapter adapter new HibernateJpaVendorAdapter(); adapter.setDatabasePlatform(EncryptedStringType.class.getName()); return adapter; }SQL注入防护严格使用MyBatis参数绑定禁止拼接SQL语句启用mybatis-filter插件拦截危险SQLplugins plugin interceptorcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor property namesqlParserFilter valuetrue/ /plugin /plugins7. 监控与性能调优7.1 应用性能监控SpringBoot Actuator集成management: endpoints: web: exposure: include: health,info,metrics,prometheus metrics: export: prometheus: enabled: true tags: application: pet-cafe-backend自定义业务指标RestController public class OrderController { private final Counter orderCounter; public OrderController(MeterRegistry registry) { this.orderCounter registry.counter(orders.total, type, coffee); } PostMapping(/orders) public Order createOrder() { orderCounter.increment(); // 业务逻辑... } }7.2 前端性能监控使用Sentry实现错误追踪import * as Sentry from sentry/vue; Sentry.init({ dsn: https://examplesentry.io/123, integrations: [new Sentry.BrowserTracing()], tracesSampleRate: 0.2, release: pet-cafe1.0.0 });关键性能指标采集// 使用web-vitals库 import {getCLS, getFID, getLCP} from web-vitals; getCLS(console.log); getFID(console.log); getLCP(console.log);8. 项目扩展方向8.1 微服务化改造当前单体架构的痛点宠物服务和餐饮服务的业务变化频率不同高峰期订单系统影响宠物预约响应速度团队规模扩大后协作效率下降改造方案按业务域拆分为三个服务宠物服务含预约、健康档案餐饮服务含订单、库存会员中心统一认证、积分使用SpringCloud Alibaba组件# 服务注册中心 spring: cloud: nacos: discovery: server-addr: 192.168.1.200:88488.2 多端适配方案小程序开发基于uni-app// 复用Vue组件逻辑 export default { data() { return { // 与Web端相同的数据结构 } }, methods: { // 复用核心方法 } }响应式布局增强// 使用Viewport单位适配不同设备 .pet-card { width: calc(33.333% - 20px); media (max-width: 768px) { width: calc(50% - 15px); } media (max-width: 480px) { width: 100%; } }在项目开发过程中我们团队总结出一个重要经验对于这种复合型业务系统一定要建立清晰的领域边界。比如宠物美容师的排班系统最初和咖啡师排班混在一起设计导致后期业务扩展时出现很多冲突。后来我们通过事件驱动架构EDA解耦这两个系统使用领域事件进行通知大大提高了系统的可维护性。
返回列表