全栈技术升级实战:SpringBoot+MyBatis-Plus+Vue3重构酒店管理系统
在数字化转型浪潮中,酒店管理系统正经历着从传统架构向现代化技术栈的全面升级。本文将深入探讨如何利用SpringBoot 2.7、MyBatis-Plus 3.5和Vue3组合重构传统酒店管理系统,分享实际项目中的技术选型思考、架构设计细节和性能优化经验。
1. 技术栈选型与架构设计
1.1 现代化技术栈对比分析
传统酒店管理系统常采用JSP+Servlet或早期Vue2版本,面临维护成本高、开发效率低等问题。我们选择的技术组合具有明显优势:
| 技术维度 | 传统方案 | 新方案 | 改进点 |
|---|---|---|---|
| 开发效率 | 手动编写大量XML配置 | 约定优于配置 | 减少70%样板代码 |
| 前端性能 | Vue2选项式API | Vue3组合式API | 打包体积减少40% |
| 构建速度 | Webpack | Vite | 冷启动时间从30s降至1s |
| 类型安全 | JavaScript | TypeScript | 编译时类型检查 |
| 后端ORM | MyBatis | MyBatis-Plus | CRUD操作减少90%SQL编写 |
1.2 前后端分离架构设计
采用清晰的职责分离架构:
├── hotel-management │ ├── hotel-backend # SpringBoot应用 │ │ ├── config # 配置类 │ │ ├── controller # 表现层 │ │ ├── service # 业务逻辑 │ │ ├── mapper # 数据访问 │ │ └── entity # 领域模型 │ └── hotel-frontend # Vue3应用 │ ├── src │ │ ├── api # 接口定义 │ │ ├── composables # 组合式函数 │ │ ├── stores # Pinia状态管理 │ │ └── views # 页面组件关键配置示例(application.yml):
spring: datasource: url: jdbc:mysql://localhost:3306/hotel_db?useSSL=false username: root password: securePassword driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted # 逻辑删除字段 logic-delete-value: 1 # 删除值 logic-not-delete-value: 0 # 未删除值2. 后端深度优化实践
2.1 MyBatis-Plus高级特性应用
通过继承BaseMapper获得基础CRUD能力,同时利用Wrapper构建复杂查询:
// 动态条件查询示例 public Page<Room> queryRooms(RoomQuery query, Page<Room> page) { return lambdaQuery() .eq(query.getRoomType() != null, Room::getType, query.getRoomType()) .between(query.getCheckIn() != null && query.getCheckOut() != null, Room::getAvailableDate, query.getCheckIn(), query.getCheckOut()) .like(StringUtils.hasText(query.getKeyword()), Room::getDescription, query.getKeyword()) .orderByAsc(Room::getRoomNumber) .page(page); }性能优化技巧:
- 启用二级缓存:在配置类添加
@EnableCaching - 批量操作:使用
saveBatch()替代循环插入 - 自动填充:通过
@TableField(fill = FieldFill.INSERT_UPDATE)实现审计字段
2.2 SpringBoot最佳实践
- 统一异常处理:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public Result<Void> handleBusinessException(BusinessException e) { log.error("业务异常: {}", e.getMessage()); return Result.fail(e.getCode(), e.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) public Result<Void> handleValidationException(MethodArgumentNotValidException e) { String message = e.getBindingResult() .getFieldErrors() .stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(", ")); return Result.fail(400, message); } }- API文档集成:
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.6.11</version> </dependency>配置Swagger UI:
@Configuration public class OpenApiConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .info(new Info().title("酒店管理系统API") .version("1.0") .contact(new Contact().name("开发团队"))); } }3. Vue3前端架构升级
3.1 Composition API实战
使用setup语法糖重构房间管理组件:
<script setup> import { ref, onMounted } from 'vue' import { useRoomStore } from '@/stores/room' import RoomForm from './RoomForm.vue' const roomStore = useRoomStore() const rooms = ref([]) const pagination = ref({ current: 1, pageSize: 10, total: 0 }) const loading = ref(false) const fetchRooms = async () => { loading.value = true await roomStore.fetchRooms(pagination.value) rooms.value = roomStore.rooms pagination.value.total = roomStore.total loading.value = false } onMounted(fetchRooms) </script> <template> <a-table :columns="columns" :dataSource="rooms" :pagination="pagination" :loading="loading" @change="handleTableChange"> <!-- 表格内容 --> </a-table> <RoomForm @refresh="fetchRooms" /> </template>3.2 状态管理方案对比
| 方案 | 适用场景 | 优势 | 本系统选择原因 |
|---|---|---|---|
| Pinia | 中小型应用 | 轻量、TypeScript支持好 | 组合式API天然适配 |
| Vuex | 大型复杂应用 | 时间旅行调试 | 学习成本较高 |
| 组件间通信 | 简单父子组件 | 无需额外库 | 不适合跨组件状态 |
推荐Pinia存储模块设计:
// stores/booking.ts export const useBookingStore = defineStore('booking', { state: () => ({ currentBooking: null as Booking | null, bookingHistory: [] as Booking[], }), actions: { async createBooking(bookingData) { const res = await api.createBooking(bookingData) this.currentBooking = res.data this.bookingHistory.unshift(res.data) } }, getters: { activeBookings: (state) => state.bookingHistory.filter(b => !b.cancelled) } })4. 关键业务模块实现
4.1 实时房态管理
技术实现要点:
- WebSocket长连接保持房态实时更新
- 乐观UI更新提升用户体验
- 冲突解决策略处理并发预订
前端实现代码:
// composables/useRoomStatus.ts export function useRoomStatus() { const socket = new WebSocket('wss://your-api/room-status') const rooms = ref<Room[]>([]) const updateRoomStatus = (roomId: string, status: RoomStatus) => { const index = rooms.value.findIndex(r => r.id === roomId) if (index !== -1) { rooms.value[index].status = status } } onMounted(() => { socket.onmessage = (event) => { const data = JSON.parse(event.data) updateRoomStatus(data.roomId, data.status) } }) onUnmounted(() => { socket.close() }) return { rooms } }4.2 订单支付系统集成
支付流程时序图:
- 前端提交订单 → 2. 后端创建支付记录 → 3. 返回支付参数 →
- 前端调用支付SDK → 5. 支付成功回调 → 6. 更新订单状态
安全措施:
- 签名验证
- 幂等性处理
- 对账机制
// 支付回调处理 @PostMapping("/payment/callback") public String handlePaymentCallback(@RequestBody CallbackRequest request) { // 1. 验证签名 if (!paymentService.verifySignature(request)) { throw new SecurityException("签名验证失败"); } // 2. 查询原订单 Order order = orderService.getById(request.getOrderId()); if (order == null) { throw new BusinessException("订单不存在"); } // 3. 幂等检查 if (order.getStatus() == OrderStatus.PAID) { return "SUCCESS"; } // 4. 更新订单 order.setStatus(OrderStatus.PAID); order.setPaymentTime(LocalDateTime.now()); orderService.updateById(order); // 5. 释放库存 inventoryService.release(order.getRoomId()); return "SUCCESS"; }5. 性能优化与部署
5.1 前端构建优化
vite.config.js关键配置:
export default defineConfig({ plugins: [vue()], build: { rollupOptions: { output: { manualChunks(id) { if (id.includes('node_modules')) { return 'vendor' } } } } }, server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })实测性能对比:
| 指标 | Vue2+Webpack | Vue3+Vite | 提升幅度 |
|---|---|---|---|
| 冷启动时间 | 28s | 1.2s | 23倍 |
| HMR更新 | 1.5s | 200ms | 7.5倍 |
| 生产包大小 | 3.2MB | 1.8MB | 44% |
5.2 后端缓存策略
多级缓存配置方案:
- 本地缓存:Caffeine
- 分布式缓存:Redis
- 数据库缓存:MyBatis二级缓存
配置示例:
@Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager manager = new CaffeineCacheManager(); manager.setCaffeine(Caffeine.newBuilder() .initialCapacity(100) .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES)); return manager; } @Bean public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(1)) .disableCachingNullValues(); return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); } }缓存使用示例:
@Service public class RoomServiceImpl implements RoomService { @Cacheable(value = "rooms", key = "#type+'-'+#status") public List<Room> findAvailableRooms(String type, RoomStatus status) { // 数据库查询逻辑 } @CacheEvict(value = "rooms", allEntries = true) public void updateRoom(Room room) { // 更新逻辑 } }6. 安全防护体系
6.1 常见攻击防护
防护措施矩阵:
| 攻击类型 | 防护方案 | 实现方式 |
|---|---|---|
| SQL注入 | MyBatis-Plus参数化查询 | 自动处理 |
| XSS攻击 | 前端DOMPurify过滤 | v-html指令结合清理 |
| CSRF攻击 | 双重Cookie验证 | 前后端协同方案 |
| 数据篡改 | 请求签名 | 拦截器实现 |
| 暴力破解 | 登录限流 | Redis+Lua脚本 |
安全拦截器示例:
public class SecurityInterceptor implements HandlerInterceptor { private final RateLimiter rateLimiter; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 1. 请求签名验证 if (!signatureService.verify(request)) { throw new AuthException("非法请求"); } // 2. 登录接口限流 if (isLoginEndpoint(request)) { if (!rateLimiter.tryAcquire()) { throw new BusinessException("操作过于频繁"); } } return true; } }6.2 权限控制方案
RBAC模型改进设计:
用户 | v 角色组 / | \ v v v 权限 权限 权限前端路由守卫:
router.beforeEach((to, from) => { const authStore = useAuthStore() if (to.meta.requiresAuth && !authStore.isAuthenticated) { return { path: '/login', query: { redirect: to.fullPath } } } if (to.meta.roles && !authStore.hasRoles(to.meta.roles)) { return { path: '/403' } } })后端权限注解:
@PreAuthorize("hasRole('ADMIN') or hasPermission(#roomId, 'room:edit')") @PutMapping("/rooms/{roomId}") public Result updateRoom(@PathVariable String roomId, @RequestBody Room room) { // 更新逻辑 }7. 监控与运维方案
7.1 应用监控体系
Prometheus + Grafana监控配置:
# application.yml management: endpoints: web: exposure: include: health,info,metrics,prometheus metrics: export: prometheus: enabled: true tags: application: hotel-management关键监控指标:
- 接口响应时间(http_server_requests_seconds)
- JVM内存使用(jvm_memory_used_bytes)
- 数据库连接池(hikaricp_connections_active)
7.2 日志收集方案
ELK栈集成配置:
<!-- logback-spring.xml --> <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> <destination>logstash:5044</destination> <encoder class="net.logstash.logback.encoder.LogstashEncoder"> <customFields>{"app":"hotel-backend","env":"${spring.profiles.active}"}</customFields> </encoder> </appender>日志查询技巧:
# 查找错误日志 GET /logstash-*/_search { "query": { "match": { "level": "ERROR" } } }8. 项目迁移经验
8.1 数据库迁移策略
分阶段迁移方案:
- 双写阶段:新旧系统同时写入
- 验证阶段:数据一致性检查
- 切流阶段:逐步切换流量
- 归档阶段:旧数据归档
Flyway迁移脚本示例:
-- V2__alter_room_table.sql ALTER TABLE room ADD COLUMN amenities JSON COMMENT '设施配置', MODIFY COLUMN status ENUM('AVAILABLE','OCCUPIED','MAINTENANCE') NOT NULL; -- 数据迁移 UPDATE room SET amenities = JSON_SET('{}', '$.wifi', true);8.2 前端渐进式迁移
混合模式运行方案:
- 新功能用Vue3开发
- 旧功能通过Web Components封装
- 共享状态管理
配置示例(vite.config.js):
import legacy from '@vitejs/plugin-legacy' export default { plugins: [ legacy({ targets: ['defaults', 'not IE 11'] }), vue({ template: { compilerOptions: { // 兼容旧组件 compatConfig: { MODE: 3 } } } }) ] }9. 测试策略升级
9.1 测试金字塔实践
测试类型分布:
- 单元测试:70%(JUnit5 + Mockito)
- 集成测试:20%(Testcontainers)
- E2E测试:10%(Cypress)
测试代码示例:
@Testcontainers @SpringBootTest class BookingServiceIntegrationTest { @Container static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0"); @DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", mysql::getJdbcUrl); registry.add("spring.datasource.username", mysql::getUsername); registry.add("spring.datasource.password", mysql::getPassword); } @Test void shouldCreateBookingSuccessfully() { // 测试逻辑 } }9.2 前端测试方案
Vitest组件测试示例:
import { mount } from '@vue/test-utils' import RoomList from './RoomList.vue' describe('RoomList', () => { it('renders rooms correctly', async () => { const wrapper = mount(RoomList, { global: { plugins: [createTestingPinia({ initialState: { room: { rooms: [{ id: 1, number: '101' }] } } })] } }) expect(wrapper.findAll('.room-item')).toHaveLength(1) }) })10. 持续集成与交付
10.1 GitHub Actions工作流
完整CI/CD流程:
name: Build and Deploy on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up JDK 17 uses: actions/setup-java@v3 with: java-version: '17' distribution: 'temurin' - name: Build backend run: ./mvnw verify - name: Build frontend run: | cd frontend npm ci npm run build - name: Run tests run: | ./mvnw test cd frontend && npm test deploy: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: ./deploy.sh10.2 容器化部署
Docker多阶段构建:
# 后端Dockerfile FROM maven:3.8.6-eclipse-temurin-17 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests FROM eclipse-temurin:17-jre COPY --from=build /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java","-jar","app.jar"] # 前端Dockerfile FROM node:16 AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 8011. 典型问题解决方案
11.1 日期时间处理
常见问题:
- 时区不一致
- 前后端格式不匹配
- 数据库存储差异
解决方案:
// 统一时区配置 @Bean public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() { return builder -> { builder.timeZone(TimeZone.getTimeZone("Asia/Shanghai")); builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss"); }; } // 前端日期处理 import { format, parseISO } from 'date-fns' const formatCheckInDate = (dateStr) => { return format(parseISO(dateStr), 'yyyy-MM-dd HH:mm') }11.2 文件上传优化
分块上传实现:
<script setup> const chunkSize = 2 * 1024 * 1024 // 2MB const uploadFile = async (file) => { const chunks = Math.ceil(file.size / chunkSize) const uploadId = await api.startUpload(file.name, file.size) for (let i = 0; i < chunks; i++) { const start = i * chunkSize const end = Math.min(start + chunkSize, file.size) const chunk = file.slice(start, end) await api.uploadChunk(uploadId, i, chunk) } await api.completeUpload(uploadId) } </script>后端校验逻辑:
public void validateFile(MultipartFile file) { // 文件类型校验 String contentType = file.getContentType(); if (!ALLOWED_TYPES.contains(contentType)) { throw new ValidationException("不支持的文件类型"); } // 文件大小校验 if (file.getSize() > MAX_FILE_SIZE) { throw new ValidationException("文件大小超过限制"); } // 病毒扫描 if (virusScanner.scan(file.getBytes())) { throw new SecurityException("文件安全检测未通过"); } }12. 用户体验优化技巧
12.1 加载状态管理
骨架屏实现方案:
<template> <div v-if="loading" class="skeleton"> <div v-for="n in 5" :key="n" class="skeleton-item"></div> </div> <RoomList v-else :rooms="rooms" /> </template> <style> .skeleton-item { height: 80px; background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 400% 100%; animation: shimmer 1.5s infinite; margin-bottom: 10px; border-radius: 4px; } @keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } } </style>12.2 表单交互优化
动态表单验证示例:
<script setup> const rules = { username: [ { required: true, message: '请输入用户名' }, { min: 3, max: 20, message: '长度在3到20个字符' } ], phone: [ { validator: (_, value) => /^1[3-9]\d{9}$/.test(value), message: '请输入正确的手机号' } ] } const handleSubmit = async () => { try { await formRef.value.validate() await submitForm() } catch (error) { console.error('验证失败:', error) } } </script>13. 代码质量保障
13.1 静态代码分析
ESLint配置示例:
module.exports = { extends: [ 'eslint:recommended', 'plugin:vue/vue3-recommended', '@vue/typescript/recommended' ], rules: { 'vue/multi-word-component-names': 'off', '@typescript-eslint/no-explicit-any': 'warn', 'complexity': ['warn', 10] } }SonarQube质量门禁:
<!-- pom.xml --> <plugin> <groupId>org.sonarsource.scanner.maven</groupId> <artifactId>sonar-maven-plugin</artifactId> <version>3.9.1</version> </plugin>13.2 代码审查要点
常见问题检查表:
- [ ] 是否存在硬编码凭证
- [ ] 接口是否有适当权限控制
- [ ] 数据库查询是否使用索引
- [ ] 是否存在N+1查询问题
- [ ] 前端组件是否合理拆分
- [ ] 状态管理是否过度使用
14. 扩展功能设计
14.1 数据分析看板
ECharts集成示例:
import { use } from 'echarts/core' import { CanvasRenderer } from 'echarts/renderers' import { PieChart, BarChart } from 'echarts/charts' import { TitleComponent, TooltipComponent, LegendComponent } from 'echarts/components' use([CanvasRenderer, PieChart, BarChart, TitleComponent, TooltipComponent, LegendComponent]) const initChart = () => { const chart = echarts.init(chartRef.value) chart.setOption({ tooltip: { trigger: 'item' }, series: [{ name: '房型统计', type: 'pie', data: props.roomStats }] }) }14.2 消息通知系统
WebSocket通知处理:
@RestController @RequestMapping("/notifications") public class NotificationController { private final SimpMessagingTemplate messagingTemplate; @PostMapping("/reservation") public void sendReservationNotification(@RequestBody ReservationEvent event) { Notification notification = createNotification(event); messagingTemplate.convertAndSendToUser( event.getStaffId(), "/queue/notifications", notification ); } }前端订阅:
const socket = new SockJS('/ws') const stompClient = Stomp.over(socket) stompClient.connect({}, () => { stompClient.subscribe('/user/queue/notifications', (message) => { showNotification(JSON.parse(message.body)) }) })15. 移动端适配方案
15.1 响应式布局
Element Plus响应式断点:
@media (max-width: 768px) { .room-card { width: 100%; margin-bottom: 16px; .actions { flex-direction: column; button { width: 100%; margin-bottom: 8px; } } } }15.2 PWA集成
配置示例(vite-plugin-pwa):
import { VitePWA } from 'vite-plugin-pwa' export default { plugins: [ VitePWA({ registerType: 'autoUpdate', manifest: { name: '酒店管理系统', short_name: '酒店管理', theme_color: '#1890ff', icons: [ { src: '/pwa-192x192.png', sizes: '192x192', type: 'image/png' } ] } }) ] }16. 国际化实现
16.1 Vue I18n配置
多语言文件结构:
src/locales/ ├── en.json ├── zh-CN.json └── ja.json组合式API使用:
import { useI18n } from 'vue-i18n' const { t, locale } = useI18n() const switchLanguage = (lang) => { locale.value = lang localStorage.setItem('preferredLanguage', lang) }16.2 后端国际化
消息资源文件:
messages.properties messages_zh_CN.properties messages_ja.properties异常处理示例:
@ExceptionHandler(BusinessException.class) public Result<Void> handleBusinessException( BusinessException e, HttpServletRequest request) { Locale locale = request.getLocale(); String message = messageSource.getMessage( e.getCode(), e.getArgs(), locale); return Result.fail(e.getCode(), message); }17. 无障碍访问优化
17.1 ARIA属性应用
<template> <button @click="bookRoom" aria-label="预订房间" :aria-disabled="!isAvailable"> 立即预订 </button> </template>17.2 键盘导航支持
焦点管理示例:
const focusFirstInput = (el: HTMLElement) => { const input = el.querySelector('input, button, [tabindex]') if (input) (input as HTMLElement).focus() } onMounted(() => { focusFirstInput(container.value!) })18. 项目文档体系
18.1 API文档生成
SpringDoc OpenAPI配置:
@Operation(summary = "创建预订", description = "创建新的房间预订") @PostMapping("/bookings") public ResponseEntity<Booking> createBooking( @RequestBody @Valid BookingRequest request) { // 实现逻辑 }18.2 组件文档
Storybook配置示例:
// RoomCard.stories.js export default { title: 'Components/RoomCard', component: RoomCard, argTypes: { onBook: { action: 'book' } } } const Template = (args) => ({ components: { RoomCard }, setup() { return { args } }, template: '<RoomCard v-bind="args" />' }) export const Available = Template.bind({}) Available.args = { room: { id: '101', type: '标准间', price: 299, available: true } }19. 技术债务管理
19.1 代码异味检测
常见技术债务类型:
- 重复代码:使用SonarQube检测
- 过长方法:超过50行应考虑拆分
- 过度耦合:模块间依赖过多
重构策略:
@startuml start :识别问题代码; repeat :小步重构; :运行测试; repeat while (测试通过?) is (否) ->是; :提交更改; stop @enduml19.2 依赖升级策略
安全更新流程:
- 使用
npm audit或mvn versions:display-dependency-updates检查 - 创建特性分支进行升级测试
- 通过CI流水线验证
- 合并到主分支
20. 团队协作规范
20.1 Git工作流
功能开发流程:
# 创建特性分支 git checkout -b feature/room-management # 提交规范示例 git commit -m "feat(room): add availability check API - 新增房间可用性查询接口 - 添加缓存处理逻辑 - 补充单元测试" # 变基更新 git fetch origin git rebase origin/main # 推送分支 git push -u origin feature/room-management20.2 代码风格统一
EditorConfig配置:
# .editorconfig root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.{java,kt}] indent_size = 4Prettier配置:
{ "semi": false, "singleQuote": true, "printWidth": 100, "vueIndentScriptAndStyle": true }21. 性能基准测试
21.1 压力测试指标
JMeter测试计划关键指标:
- 吞吐量:≥100 req/s
- 平均响应时间:<500ms
- 错误率:<0.1%
测试场景设计:
- 模拟50并发用户持续预订
- 混合读写操作比例3:1
- 逐步增加负载观察系统表现
21.2 前端性能指标
Lighthouse优化建议:
- 图片懒加载:
<img loading="lazy"> - 代码分割:动态导入组件
- 预加载关键资源:
<link rel="preload" href="/fonts/iconfont.woff2" as="font" crossorigin>22. 错误追踪系统
22.1 Sentry集成
前端配置:
import * as Sentry from '@sentry/vue' app = createApp(App) Sentry.init({ app, dsn: 'your-dsn', integrations: [ new Sentry.BrowserTracing({ routingInstrumentation: Sentry.vueRouterInstrumentation(router) }) ], tracesSampleRate: 0.2 })后端配置:
@Bean public Sentry.OptionsConfiguration<SentryOptions> optionsConfiguration() { return options -> { options.setDsn("your-dsn"); options.setTracesSampleRate(0.2); }; }22.2 错误分类处理
错误处理策略矩阵:
| 错误类型 | 记录级别 | 处理方式 |
|---|---|---|
| 业务验证失败 | WARN | 返回用户友好提示 |
| 第三方服务异常 | ERROR | 重试机制+告警通知 |
| 系统致命错误 | CRITICAL | 熔断降级+紧急修复 |
23. 成本优化方案
23.1 云资源优化
成本节约策略:
- 自动伸缩组(根据CPU使用率)
- 预留实例(长期运行的实例)
- 对象存储生命周期策略
Terraform配置示例:
resource "aws_autoscaling_group" "app" { desired_capacity = 2 min_size = 1 max_size = 4 scaling_policy { adjustment_type = "ChangeInCapacity" scaling_adjustment = 1 cooldown = 300 } }23.2 数据库优化
索引优化建议:
-- 添加复合索引 ALTER TABLE booking ADD INDEX idx_status_date (status, check_in_date); -- 查询分析 EXPLAIN SELECT * FROM room WHERE type = 'DELUXE' AND status = 'AVAILABLE';连接池配置:
spring: datasource: hikari: maximum-pool-size: 20 idle-timeout: 30000 connection-timeout: 5000