推广 热搜: 采购方式  滤芯  带式称重给煤机  甲带  气动隔膜泵  减速机型号  无级变速机  链式给煤机  履带  减速机 

济南雷鸣网络小程序开发程序架构白皮书

   日期:2026-06-06 00:35:14     来源:网络整理    作者:本站编辑    评论:0    
济南雷鸣网络小程序开发程序架构白皮书

一、技术栈选型与架构总览

1.1 技术选型原则

  • 高可用性:99.99%可用性目标

  • 可扩展性:支持千万级日活用户

  • 安全性:医疗健康数据最高安全标准

  • 开发效率:统一技术栈,降低维护成本

  • 用户体验:秒级响应,流畅交互

1.2 整体架构

┌─────────────────────────────────────────────┐
│                  用户端                     │
│  ┌───────────┐  ┌───────────┐             │
│  │ 微信小程序 │  │ 企业微信 │             │
│  └───────────┘  └───────────┘             │
│         │             │                   │
└─────────┼─────────────┼───────────────────┘
          │             │
┌─────────┼─────────────┼───────────────────┐
│  负载均衡集群(Nginx + Keepalived)        │
└─────────┼─────────────┼───────────────────┘
          │             │
┌─────────▼─────────────▼───────────────────┐
│          API网关层(Spring Cloud Gateway)  │
│  ┌─────────────────────────────────────┐  │
│  │  • 路由分发                         │  │
│  │  • 限流熔断                         │  │
│  │  • 权限校验                         │  │
│  │  • 日志审计                         │  │
│  └─────────────────────────────────────┘  │
└─────────┬─────────────────────────────────┘
          │
┌─────────▼─────────────────────────────────┐
│          业务微服务集群                    │
│  ┌───────────┐ ┌───────────┐ ┌─────────┐│
│  │用户服务   │ │健康服务   │ │订单服务 ││
│  ├───────────┤ ├───────────┤ ├─────────┤│
│  │• 会员管理 │ │• 健康档案 │ │• 服务单 ││
│  │• 认证授权 │ │• 计划管理 │ │• 支付   ││
│  │• 社交关系 │ │• 数据采集 │ │• 评价   ││
│  └───────────┘ └───────────┘ └─────────┘│
│  ┌───────────┐ ┌───────────┐ ┌─────────┐│
│  │医疗资源   │ │内容服务   │ │消息服务 ││
│  ├───────────┤ ├───────────┤ ├─────────┤│
│  │• 医院对接 │ │• 知识库   │ │• 即时通讯││
│  │• 医生管理 │ │• 内容管理 │ │• 推送   ││
│  │• 预约调度 │ │• AI解读   │ │• 通知   ││
│  └───────────┘ └───────────┘ └─────────┘│
└─────────┬─────────────────────────────────┘
          │
┌─────────▼─────────────────────────────────┐
│          数据服务层                        │
│  ┌─────────────────────────────────────┐  │
│  │ 缓存层(Redis Cluster)              │  │
│  │  • 会话管理                         │  │
│  │  • 热点数据                         │  │
│  │  • 分布式锁                         │  │
│  └─────────────────────────────────────┘  │
│  ┌─────────────────────────────────────┐  │
│  │ 消息队列(RocketMQ)                  │  │
│  │  • 异步解耦                         │  │
│  │  • 削峰填谷                         │  │
│  │  • 顺序消息                         │  │
│  └─────────────────────────────────────┘  │
│  ┌─────────────────────────────────────┐  │
│  │ 数据库层                            │  │
│  │  • MySQL集群(主从+分库分表)         │  │
│  │  • MongoDB(文档型数据)              │  │
│  │  • 时序数据库(健康指标)              │  │
│  └─────────────────────────────────────┘  │
└───────────────────────────────────────────┘

二、小程序端技术架构

2.1 前端框架选型

// package.json 核心依赖
{
  "dependencies": {
    // 基础框架
    "@tarojs/taro": "^3.6.0",        // 多端统一框架
    "@tarojs/runtime": "^3.6.0",     // 运行时
    "@tarojs/react": "^3.6.0",       // React支持

    // UI组件库
    "@nutui/nutui-taro": "^2.0.0",   // 轻量级组件库
    "taro-ui": "^3.0.0-alpha.3",     // Taro官方UI

    // 状态管理
    "mobx": "^6.3.0",               // 状态管理
    "mobx-react-lite": "^3.2.0",     // Mobx React绑定

    // 网络请求
    "luch-request": "^3.0.0",        // 增强型请求库

    // 工具库
    "dayjs": "^1.11.0",             // 日期处理
    "lodash-es": "^4.17.21",        // 工具函数
    "crypto-js": "^4.1.1",          // 加密解密

    // 图表
    "@antv/f2": "^4.0.0",           // 移动端图表
    "ec-canvas": "^1.0.0",          // ECharts小程序版

    // 地图
    "taro-map": "^1.0.0",           // 地图组件
  }
}

2.2 项目目录结构

src/
├── app.config.ts                   # 小程序全局配置
├── app.tsx                         # 小程序入口
├── app.scss                        # 全局样式
├── config/                         # 配置文件
│   ├── index.ts                    # 主配置
│   ├── env.ts                      # 环境配置
│   ├── api.ts                      # API接口配置
│   └── constant.ts                 # 常量定义
├── assets/                         # 静态资源
│   ├── images/                     # 图片资源
│   ├── icons/                      # 图标资源
│   └── fonts/                      # 字体文件
├── components/                     # 公共组件
│   ├── common/                     # 通用组件
│   │   ├── Loading/
│   │   ├── Empty/
│   │   ├── ErrorBoundary/
│   │   └── Modal/
│   ├── business/                   # 业务组件
│   │   ├── HealthCard/
│   │   ├── AppointmentCard/
│   │   ├── DoctorCard/
│   │   └── ServiceCard/
│   └── layout/                     # 布局组件
│       ├── Header/
│       ├── TabBar/
│       └── SideMenu/
├── pages/                          # 页面目录
│   ├── index/                      # 首页
│   ├── health/                     # 健康管理
│   │   ├── dashboard/              # 健康仪表盘
│   │   ├── records/                # 健康记录
│   │   ├── plans/                  # 健康计划
│   │   └── trends/                 # 健康趋势
│   ├── service/                    # 服务
│   │   ├── appointment/            # 预约服务
│   │   ├── companion/              # 陪诊服务
│   │   └── consultation/           # 咨询服务
│   ├── hospital/                   # 医院服务
│   ├── mine/                       # 个人中心
│   └── messages/                   # 消息中心
├── services/                       # 服务层
│   ├── api/                        # API服务
│   │   ├── user.api.ts
│   │   ├── health.api.ts
│   │   └── hospital.api.ts
│   ├── storage/                    # 存储服务
│   ├── request/                    # 请求封装
│   └── websocket/                  # WebSocket服务
├── stores/                         # 状态管理
│   ├── user.store.ts               # 用户状态
│   ├── health.store.ts             # 健康状态
│   ├── app.store.ts                # 应用状态
│   └── index.ts                    # Store入口
├── utils/                          # 工具函数
│   ├── auth.ts                     # 认证工具
│   ├── validator.ts                # 验证工具
│   ├── formatter.ts                # 格式化工具
│   ├── encryption.ts               # 加密工具
│   └── performance.ts              # 性能监控
├── hooks/                          # 自定义Hooks
│   ├── useAuth.ts                  # 认证Hook
│   ├── useRequest.ts               # 请求Hook
│   └── useHealthData.ts            # 健康数据Hook
├── types/                          # TypeScript类型定义
│   ├── global.d.ts                 # 全局类型
│   ├── api.d.ts                    # API类型
│   └── model.d.ts                  # 数据模型
└── styles/                         # 样式文件
    ├── variables.scss              # 样式变量
    ├── mixins.scss                 # Mixin函数
    └── common.scss                 # 公共样式

2.3 核心组件设计

2.3.1 健康数据卡片组件

// components/business/HealthDataCard/index.tsx
import React, { memo } from 'react';
import { View, Text } from '@tarojs/components';
import { LineChart } from '@antv/f2';
import './index.scss';

interface HealthDataCardProps {
  title: string;
  value: number | string;
  unit: string;
  trend: 'up' | 'down' | 'stable';
  trendValue: number;
  chartData: Array<{ date: string; value: number }>;
  onClick?: () => void;
}

const HealthDataCard: React.FC<HealthDataCardProps> = memo(({
  title,
  value,
  unit,
  trend,
  trendValue,
  chartData,
  onClick
}) => {
  const getTrendIcon = () => {
    switch(trend) {
      case 'up': return '↑';
      case 'down': return '↓';
      default: return '→';
    }
  };

  const getTrendColor = () => {
    switch(trend) {
      case 'up': return '#ff6b6b';
      case 'down': return '#52c41a';
      default: return '#999';
    }
  };

  return (
    <View className="health-data-card" onClick={onClick}>
      <View className="card-header">
        <Text className="title">{title}</Text>
        <View className="trend">
          <Text style={{ color: getTrendColor() }}>
            {getTrendIcon()} {Math.abs(trendValue)}
          </Text>
        </View>
      </View>

      <View className="card-body">
        <View className="current-value">
          <Text className="value">{value}</Text>
          <Text className="unit">{unit}</Text>
        </View>

        {chartData.length > 0 && (
          <View className="chart-container">
            <LineChart
              data={chartData}
              xField="date"
              yField="value"
              width={300}
              height={80}
            />
          </View>
        )}
      </View>

      <View className="card-footer">
        <Text className="time">最近更新: 今天 09:30</Text>
        <Text className="detail">查看详情 ></Text>
      </View>
    </View>
  );
});

export default HealthDataCard;

2.3.2 服务预约流程组件

// components/business/ServiceFlow/index.tsx
import React, { useState } from 'react';
import { View, Text, Button } from '@tarojs/components';
import { Steps, Step } from '@nutui/nutui-taro';
import ServiceType from './ServiceType';
import TimeSelection from './TimeSelection';
import InfoConfirm from './InfoConfirm';
import './index.scss';

const steps = [
  { title: '选择服务', description: '选择需要的服务类型' },
  { title: '选择时间', description: '预约合适的时间' },
  { title: '确认信息', description: '确认预约信息' },
];

const ServiceFlow: React.FC = () => {
  const [currentStep, setCurrentStep] = useState(0);
  const [formData, setFormData] = useState({
    serviceType: '',
    appointmentTime: '',
    patientInfo: {},
  });

  const handleNext = () => {
    if (currentStep < steps.length - 1) {
      setCurrentStep(currentStep + 1);
    } else {
      handleSubmit();
    }
  };

  const handleBack = () => {
    if (currentStep > 0) {
      setCurrentStep(currentStep - 1);
    }
  };

  const handleSubmit = async () => {
    // 提交预约逻辑
    console.log('提交预约:', formData);
  };

  const renderStepContent = () => {
    switch(currentStep) {
      case 0:
        return (
          <ServiceType
            value={formData.serviceType}
            onChange={(type) => setFormData({...formData, serviceType: type})}
          />
        );
      case 1:
        return (
          <TimeSelection
            value={formData.appointmentTime}
            onChange={(time) => setFormData({...formData, appointmentTime: time})}
          />
        );
      case 2:
        return (
          <InfoConfirm
            data={formData}
            onChange={(info) => setFormData({...formData, patientInfo: info})}
          />
        );
      default:
        return null;
    }
  };

  return (
    <View className="service-flow">
      <Steps current={currentStep}>
        {steps.map((step, index) => (
          <Step
            key={index}
            title={step.title}
            description={step.description}
            active={index === currentStep}
            complete={index < currentStep}
          />
        ))}
      </Steps>

      <View className="step-content">
        {renderStepContent()}
      </View>

      <View className="action-buttons">
        {currentStep > 0 && (
          <Button className="back-btn" onClick={handleBack}>
            上一步
          </Button>
        )}
        <Button
          className="next-btn"
          type="primary"
          onClick={handleNext}
        >
          {currentStep === steps.length - 1 ? '确认预约' : '下一步'}
        </Button>
      </View>
    </View>
  );
};

2.4 状态管理设计

// stores/user.store.ts
import { makeAutoObservable, runInAction } from 'mobx';
import { userApi } from '../services/api/user.api';
import { StorageService } from '../services/storage';

export interface UserProfile {
  id: string;
  name: string;
  avatar: string;
  phone: string;
  membershipLevel: 'basic' | 'professional' | 'premium';
  healthTags: string[];
}

class UserStore {
  // 状态
  userInfo: UserProfile | null = null;
  token: string | null = null;
  isAuthenticated: boolean = false;
  loading: boolean = false;
  error: string | null = null;

  constructor() {
    makeAutoObservable(this);
    this.initialize();
  }

  // 初始化
  async initialize() {
    const token = await StorageService.getToken();
    if (token) {
      this.token = token;
      await this.fetchUserProfile();
    }
  }

  // Action: 登录
  async login(credentials: { phone: string; code: string }) {
    this.loading = true;
    this.error = null;

    try {
      const response = await userApi.login(credentials);

      runInAction(() => {
        this.token = response.token;
        this.userInfo = response.user;
        this.isAuthenticated = true;
      });

      // 持久化存储
      await StorageService.setToken(response.token);
      await StorageService.setUser(response.user);

    } catch (error) {
      runInAction(() => {
        this.error = error.message;
        this.isAuthenticated = false;
      });
    } finally {
      runInAction(() => {
        this.loading = false;
      });
    }
  }

  // Action: 获取用户资料
  async fetchUserProfile() {
    if (!this.token) return;

    try {
      const user = await userApi.getProfile();
      runInAction(() => {
        this.userInfo = user;
        this.isAuthenticated = true;
      });
    } catch (error) {
      runInAction(() => {
        this.isAuthenticated = false;
      });
    }
  }

  // Action: 更新用户信息
  async updateProfile(profile: Partial<UserProfile>) {
    try {
      const updated = await userApi.updateProfile(profile);
      runInAction(() => {
        this.userInfo = { ...this.userInfo!, ...updated };
      });
      return updated;
    } catch (error) {
      throw error;
    }
  }

  // Action: 登出
  async logout() {
    await userApi.logout();
    await StorageService.clear();

    runInAction(() => {
      this.userInfo = null;
      this.token = null;
      this.isAuthenticated = false;
    });
  }

  // Computed: 是否是高级会员
  get isPremiumMember() {
    return this.userInfo?.membershipLevel === 'premium';
  }

  // Computed: 用户标签字符串
  get healthTagsString() {
    return this.userInfo?.healthTags?.join('、') || '无';
  }
}

export default new UserStore();

三、后端微服务架构设计

3.1 用户服务 (User Service)

// UserService 核心接口设计
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 用户注册
     */
    @PostMapping("/register")
    public ApiResponse<UserVO> register(@Valid @RequestBody RegisterDTO dto) {
        UserVO user = userService.register(dto);
        return ApiResponse.success(user);
    }

    /**
     * 用户登录
     */
    @PostMapping("/login")
    public ApiResponse<LoginResult> login(@Valid @RequestBody LoginDTO dto) {
        LoginResult result = userService.login(dto);
        return ApiResponse.success(result);
    }

    /**
     * 获取用户健康档案
     */
    @GetMapping("/{userId}/health-profile")
    @PreAuthorize("hasRole('USER')")
    public ApiResponse<HealthProfileVO> getHealthProfile(@PathVariable String userId) {
        HealthProfileVO profile = userService.getHealthProfile(userId);
        return ApiResponse.success(profile);
    }

    /**
     * 更新健康标签
     */
    @PutMapping("/{userId}/health-tags")
    @PreAuthorize("hasRole('USER')")
    public ApiResponse<Void> updateHealthTags(
            @PathVariable String userId,
            @RequestBody UpdateTagsDTO dto) {
        userService.updateHealthTags(userId, dto.getTags());
        return ApiResponse.success();
    }
}

// 用户领域模型
@Entity
@Table(name = "users")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    @Column(unique = true, nullable = false)
    private String phone;

    private String name;
    private String avatar;

    @Enumerated(EnumType.STRING)
    private UserStatus status = UserStatus.ACTIVE;

    @Enumerated(EnumType.STRING)
    private MembershipLevel membershipLevel = MembershipLevel.BASIC;

    @ElementCollection
    @CollectionTable(name = "user_health_tags")
    private Set<String> healthTags = new HashSet<>();

    @Embedded
    private HealthProfile healthProfile;

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;
}

// 健康档案值对象
@Embeddable
@Data
public class HealthProfile {
    private String bloodType;
    private Double height;
    private Double weight;
    private Boolean hasAllergy;
    private String allergyInfo;
    private String chronicDiseases;
    private String familyHistory;

    @Embedded
    private EmergencyContact emergencyContact;
}

3.2 健康服务 (Health Service)

// 健康数据服务
@Service
@Slf4j
public class HealthDataServiceImpl implements HealthDataService {

    @Autowired
    private HealthDataRepository healthDataRepo;

    @Autowired
    private HealthIndicatorCalculator indicatorCalculator;

    @Autowired
    private RiskAssessmentEngine riskEngine;

    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;

    /**
     * 记录健康数据
     */
    @Override
    @Transactional
    public HealthRecordVO recordHealthData(String userId, RecordHealthDataDTO dto) {
        // 1. 保存原始数据
        HealthData data = HealthData.builder()
                .userId(userId)
                .type(dto.getType())
                .value(dto.getValue())
                .unit(dto.getUnit())
                .source(dto.getSource())
                .recordedAt(dto.getRecordedAt())
                .metadata(dto.getMetadata())
                .build();

        HealthData saved = healthDataRepo.save(data);

        // 2. 计算衍生指标
        Map<String, Object> indicators = indicatorCalculator.calculate(
                userId, dto.getType(), dto.getValue());

        // 3. 风险评估
        RiskAssessment risk = riskEngine.assess(userId, dto.getType(), dto.getValue());

        // 4. 发送事件消息
        HealthDataRecordedEvent event = HealthDataRecordedEvent.builder()
                .userId(userId)
                .dataType(dto.getType())
                .recordedAt(dto.getRecordedAt())
                .indicators(indicators)
                .riskLevel(risk.getLevel())
                .build();

        kafkaTemplate.send("health-data-events", event);

        // 5. 返回结果
        return HealthRecordVO.from(saved, indicators, risk);
    }

    /**
     * 获取健康趋势
     */
    @Override
    public HealthTrendVO getHealthTrend(String userId, HealthTrendQuery query) {
        LocalDateTime end = query.getEndDate() != null ? 
                query.getEndDate().atTime(23, 59, 59) : LocalDateTime.now();
        LocalDateTime start = end.minus(query.getPeriod());

        List<HealthData> data = healthDataRepo.findByUserIdAndTypeAndTimeRange(
                userId, query.getDataType(), start, end);

        // 数据聚合与统计
        HealthStatistics stats = calculateStatistics(data);

        // 趋势分析
        TrendAnalysis trend = analyzeTrend(data, query.getPeriod());

        // 生成建议
        List<HealthAdvice> advice = generateAdvice(stats, trend, query.getDataType());

        return HealthTrendVO.builder()
                .statistics(stats)
                .trend(trend)
                .advice(advice)
                .dataPoints(data.stream()
                        .map(HealthDataPoint::from)
                        .collect(Collectors.toList()))
                .build();
    }

    /**
     * 生成健康报告
     */
    @Override
    public HealthReportVO generateReport(String userId, ReportPeriod period) {
        // 获取报告期数据
        ReportData data = collectReportData(userId, period);

        // 计算各项指标
        Map<String, Object> metrics = calculateMetrics(data);

        // 风险评估
        List<RiskItem> risks = assessRisks(data);

        // 生成建议
        List<Recommendation> recommendations = generateRecommendations(metrics, risks);

        // 生成可视化数据
        Map<String, Object> visualizations = generateVisualizations(data);

        return HealthReportVO.builder()
                .period(period)
                .metrics(metrics)
                .risks(risks)
                .recommendations(recommendations)
                .visualizations(visualizations)
                .generatedAt(LocalDateTime.now())
                .build();
    }
}

3.3 订单服务 (Order Service)

// 订单状态机
@Component
public class OrderStateMachine {

    private final StateMachine<OrderStatus, OrderEvent> stateMachine;

    public OrderStateMachine() {
        StateMachineBuilder<OrderStatus, OrderEvent> builder = 
                StateMachineBuilderFactory.create();

        // 配置状态转移
        builder.configureStates()
                .withStates()
                .initial(OrderStatus.PENDING)
                .state(OrderStatus.PAID)
                .state(OrderStatus.CONFIRMED)
                .state(OrderStatus.IN_PROGRESS)
                .state(OrderStatus.COMPLETED)
                .state(OrderStatus.CANCELLED)
                .state(OrderStatus.REFUNDED);

        builder.configureTransitions()
                .withExternal()
                .source(OrderStatus.PENDING).target(OrderStatus.PAID)
                .event(OrderEvent.PAY_SUCCESS)
                .and()
                .withExternal()
                .source(OrderStatus.PAID).target(OrderStatus.CONFIRMED)
                .event(OrderEvent.CONFIRM)
                .and()
                .withExternal()
                .source(OrderStatus.CONFIRMED).target(OrderStatus.IN_PROGRESS)
                .event(OrderEvent.START_SERVICE)
                .and()
                .withExternal()
                .source(OrderStatus.IN_PROGRESS).target(OrderStatus.COMPLETED)
                .event(OrderEvent.COMPLETE_SERVICE)
                .and()
                .withExternal()
                .source(OrderStatus.PAID).target(OrderStatus.CANCELLED)
                .event(OrderEvent.CANCEL)
                .and()
                .withExternal()
                .source(OrderStatus.COMPLETED).target(OrderStatus.REFUNDED)
                .event(OrderEvent.REFUND);
    }

    public OrderStatus processEvent(Order order, OrderEvent event) {
        stateMachine.start();
        stateMachine.sendEvent(event);
        return stateMachine.getState().getId();
    }
}

// 分布式事务处理
@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private UserServiceClient userServiceClient;

    @Autowired
    private InventoryServiceClient inventoryServiceClient;

    @Autowired
    private TransactionTemplate transactionTemplate;

    /**
     * 创建订单(分布式事务)
     */
    @Transactional
    public Order createOrder(CreateOrderDTO dto) {
        // 1. 验证用户
        UserVO user = userServiceClient.getUser(dto.getUserId());
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 2. 锁定库存(Saga模式)
        try {
            inventoryServiceClient.lockInventory(dto.getServiceId(), dto.getQuantity());
        } catch (Exception e) {
            throw new BusinessException("库存锁定失败");
        }

        // 3. 创建订单
        Order order = Order.builder()
                .orderNo(generateOrderNo())
                .userId(dto.getUserId())
                .serviceId(dto.getServiceId())
                .amount(dto.getAmount())
                .status(OrderStatus.PENDING)
                .build();

        Order savedOrder = orderRepository.save(order);

        // 4. 发送创建订单事件
        eventPublisher.publishEvent(new OrderCreatedEvent(savedOrder));

        return savedOrder;
    }

    /**
     * 支付回调处理
     */
    @Transactional
    public void handlePaymentCallback(PaymentCallbackDTO callback) {
        Order order = orderRepository.findByOrderNo(callback.getOrderNo())
                .orElseThrow(() -> new BusinessException("订单不存在"));

        if (callback.isSuccess()) {
            // 支付成功,更新订单状态
            order.setStatus(OrderStatus.PAID);
            order.setPaidAt(LocalDateTime.now());
            order.setPaymentNo(callback.getPaymentNo());

            orderRepository.save(order);

            // 发送支付成功事件
            eventPublisher.publishEvent(new OrderPaidEvent(order));
        } else {
            // 支付失败,释放库存
            inventoryServiceClient.releaseInventory(
                    order.getServiceId(), order.getQuantity());

            order.setStatus(OrderStatus.CANCELLED);
            orderRepository.save(order);
        }
    }
}

四、数据库设计

4.1 核心表结构设计

用户相关表

-- 用户表
CREATE TABLE users (
    id VARCHAR(36) PRIMARY KEY,
    phone VARCHAR(20) UNIQUE NOT NULL,
    name VARCHAR(50),
    avatar VARCHAR(500),
    membership_level ENUM('basic', 'professional', 'premium') DEFAULT 'basic',
    status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_phone (phone),
    INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 用户健康档案表
CREATE TABLE user_health_profiles (
    user_id VARCHAR(36) PRIMARY KEY,
    blood_type ENUM('A', 'B', 'AB', 'O'),
    height DECIMAL(5,2) COMMENT '身高(cm)',
    weight DECIMAL(5,2) COMMENT '体重(kg)',
    bmi DECIMAL(4,2) COMMENT '身体质量指数',
    has_allergy BOOLEAN DEFAULT FALSE,
    allergy_info TEXT,
    chronic_diseases JSON COMMENT '慢性病信息',
    family_history JSON COMMENT '家族病史',
    emergency_contact JSON COMMENT '紧急联系人',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 健康数据记录表
CREATE TABLE health_data_records (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(36) NOT NULL,
    data_type VARCHAR(50) NOT NULL COMMENT '数据类型: blood_pressure, blood_glucose, etc.',
    value DECIMAL(10,2) NOT NULL,
    unit VARCHAR(20) NOT NULL,
    source VARCHAR(50) COMMENT '数据来源: manual, device, hospital',
    recorded_at DATETIME NOT NULL,
    notes TEXT,
    metadata JSON COMMENT '扩展数据',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_type_time (user_id, data_type, recorded_at),
    INDEX idx_recorded_at (recorded_at),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
PARTITION BY RANGE (YEAR(recorded_at))
SUBPARTITION BY KEY (user_id)
SUBPARTITIONS 10 (
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p2025 VALUES LESS THAN (2026)
);

服务相关表

-- 服务项目表
CREATE TABLE services (
    id VARCHAR(36) PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    category VARCHAR(50) NOT NULL COMMENT 'category: companion, consultation, etc.',
    description TEXT,
    price DECIMAL(10,2) NOT NULL,
    duration_minutes INT COMMENT '服务时长(分钟)',
    is_active BOOLEAN DEFAULT TRUE,
    sort_order INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_category (category),
    INDEX idx_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 订单表
CREATE TABLE orders (
    id VARCHAR(36) PRIMARY KEY,
    order_no VARCHAR(32) UNIQUE NOT NULL,
    user_id VARCHAR(36) NOT NULL,
    service_id VARCHAR(36) NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    status VARCHAR(20) NOT NULL,
    payment_method VARCHAR(20),
    payment_no VARCHAR(64),
    paid_at DATETIME,
    completed_at DATETIME,
    cancel_reason TEXT,
    contact_info JSON NOT NULL COMMENT '联系人信息',
    service_info JSON NOT NULL COMMENT '服务信息',
    metadata JSON COMMENT '扩展信息',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_user (user_id),
    INDEX idx_order_no (order_no),
    INDEX idx_status_created (status, created_at),
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (service_id) REFERENCES services(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 预约表
CREATE TABLE appointments (
    id VARCHAR(36) PRIMARY KEY,
    order_id VARCHAR(36) NOT NULL,
    user_id VARCHAR(36) NOT NULL,
    service_id VARCHAR(36) NOT NULL,
    scheduled_time DATETIME NOT NULL,
    duration_minutes INT NOT NULL,
    status VARCHAR(20) NOT NULL COMMENT 'scheduled, confirmed, in_progress, completed, cancelled',
    staff_id VARCHAR(36) COMMENT '服务人员ID',
    location_info JSON COMMENT '位置信息',
    notes TEXT,
    reminder_sent BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_user_time (user_id, scheduled_time),
    INDEX idx_staff_time (staff_id, scheduled_time),
    INDEX idx_status_time (status, scheduled_time),
    UNIQUE KEY uk_order (order_id),
    FOREIGN KEY (order_id) REFERENCES orders(id),
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (service_id) REFERENCES services(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

内容相关表

-- 健康知识库
CREATE TABLE health_knowledge (
    id VARCHAR(36) PRIMARY KEY,
    title VARCHAR(200) NOT NULL,
    content LONGTEXT NOT NULL,
    category VARCHAR(50) NOT NULL,
    tags JSON COMMENT '标签数组',
    source VARCHAR(100) COMMENT '来源',
    author VARCHAR(100),
    is_recommended BOOLEAN DEFAULT FALSE,
    view_count INT DEFAULT 0,
    like_count INT DEFAULT 0,
    is_published BOOLEAN DEFAULT TRUE,
    published_at DATETIME,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FULLTEXT idx_title_content (title, content),
    INDEX idx_category (category),
    INDEX idx_published (is_published, published_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- AI解读记录
CREATE TABLE ai_interpretations (
    id VARCHAR(36) PRIMARY KEY,
    user_id VARCHAR(36) NOT NULL,
    report_type VARCHAR(50) NOT NULL,
    original_data JSON NOT NULL COMMENT '原始数据',
    interpretation TEXT NOT NULL COMMENT 'AI解读结果',
    confidence_score DECIMAL(5,4) COMMENT '置信度',
    suggestions JSON COMMENT '建议',
    is_read BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_type (user_id, report_type),
    INDEX idx_created (created_at),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

五、API接口设计规范

5.1 接口设计原则

  1. RESTful风格:使用标准HTTP方法,资源化URL设计

  2. 版本控制:API版本在URL中体现(/api/v1/)

  3. 统一响应格式:标准化响应结构

  4. 错误处理:标准化的错误码和错误信息

  5. 分页与过滤:支持标准化的分页、排序、过滤

  6. 限流与认证:统一的认证和限流机制

5.2 统一响应格式

{
  "success": true,
  "code": 200,
  "message": "操作成功",
  "data": {
    // 业务数据
  },
  "timestamp": 1633046400000,
  "requestId": "req_1234567890"
}

5.3 核心API接口

5.3.1 用户认证相关

# 发送验证码
POST /api/v1/auth/sms-code
Request:
  {
    "phone": "13800138000",
    "scene": "login|register|reset"
  }
Response:
  {
    "success": true,
    "data": {
      "expiresIn": 300
    }
  }

# 登录/注册
POST /api/v1/auth/login
Request:
  {
    "phone": "13800138000",
    "code": "123456"
  }
Response:
  {
    "success": true,
    "data": {
      "token": "jwt_token_string",
      "user": {
        "id": "user_id",
        "name": "张三",
        "phone": "13800138000",
        "avatar": "https://xxx.com/avatar.jpg"
      }
    }
  }

5.3.2 健康数据相关

# 记录健康数据
POST /api/v1/health/records
Headers:
  Authorization: Bearer {token}
Request:
  {
    "type": "blood_pressure",
    "value": 120,
    "unit": "mmHg",
    "recordedAt": "2023-10-01T08:00:00Z",
    "metadata": {
      "systolic": 120,
      "diastolic": 80,
      "heartRate": 75
    }
  }
Response:
  {
    "success": true,
    "data": {
      "id": "record_id",
      "type": "blood_pressure",
      "value": 120,
      "unit": "mmHg",
      "recordedAt": "2023-10-01T08:00:00Z",
      "indicators": {
        "level": "normal",
        "description": "血压正常"
      }
    }
  }

# 查询健康趋势
GET /api/v1/health/trends
Headers:
  Authorization: Bearer {token}
Query Parameters:
  type=blood_pressure&period=7d&start=2023-10-01&end=2023-10-07
Response:
  {
    "success": true,
    "data": {
      "statistics": {
        "average": 118.5,
        "max": 130,
        "min": 110,
        "count": 21
      },
      "trend": "stable",
      "dataPoints": [
        {
          "date": "2023-10-01",
          "value": 120,
          "time": "08:00"
        }
      ],
      "advice": [
        {
          "level": "info",
          "content": "血压控制良好,请继续保持"
        }
      ]
    }
  }

5.3.3 服务预约相关

# 获取可预约时间
GET /api/v1/appointments/available-slots
Headers:
  Authorization: Bearer {token}
Query Parameters:
  serviceId=service_123&date=2023-10-10
Response:
  {
    "success": true,
    "data": {
      "date": "2023-10-10",
      "slots": [
        {
          "time": "09:00",
          "available": true
        },
        {
          "time": "10:00",
          "available": false,
          "reason": "已约满"
        }
      ]
    }
  }

# 创建预约
POST /api/v1/appointments
Headers:
  Authorization: Bearer {token}
Request:
  {
    "serviceId": "service_123",
    "scheduledTime": "2023-10-10T09:00:00Z",
    "contactPerson": "张三",
    "contactPhone": "13800138000",
    "notes": "需要轮椅辅助"
  }
Response:
  {
    "success": true,
    "data": {
      "appointmentId": "app_123456",
      "orderNo": "ORDER20231010001",
      "status": "pending",
      "scheduledTime": "2023-10-10T09:00:00Z",
      "amount": 299.00
    }
  }

六、性能优化策略

6.1 前端性能优化

// 1. 图片优化
// 使用WebP格式,懒加载,CDN加速
const ImageOptimizer = {
  getOptimizedUrl: (url, options = {}) => {
    const params = new URLSearchParams();
    if (options.width) params.append('w', options.width);
    if (options.quality) params.append('q', options.quality);
    if (options.format) params.append('fm', options.format);
    return `${url}?${params.toString()}`;
  }
};

// 2. 请求优化
// 防抖、节流、请求合并
class RequestOptimizer {
  constructor() {
    this.pendingRequests = new Map();
  }

  // 请求去重
  async deduplicatedRequest(key, requestFn) {
    if (this.pendingRequests.has(key)) {
      return this.pendingRequests.get(key);
    }

    const promise = requestFn();
    this.pendingRequests.set(key, promise);

    try {
      const result = await promise;
      return result;
    } finally {
      this.pendingRequests.delete(key);
    }
  }

  // 请求合并
  async batchRequest(requests, batchSize = 5) {
    const results = [];
    for (let i = 0; i < requests.length; i += batchSize) {
      const batch = requests.slice(i, i + batchSize);
      const batchResults = await Promise.all(
        batch.map(req => req())
      );
      results.push(...batchResults);
    }
    return results;
  }
}

// 3. 缓存策略
class CacheManager {
  constructor() {
    this.memoryCache = new Map();
    this.storage = Taro.getStorageSync;
  }

  async getWithCache(key, fetchFn, ttl = 5 * 60 * 1000) {
    // 内存缓存
    const memoryItem = this.memoryCache.get(key);
    if (memoryItem && Date.now() - memoryItem.timestamp < ttl) {
      return memoryItem.data;
    }

    // 本地存储缓存
    try {
      const storageItem = this.storage(key);
      if (storageItem && Date.now() - storageItem.timestamp < ttl) {
        // 更新内存缓存
        this.memoryCache.set(key, storageItem);
        return storageItem.data;
      }
    } catch (error) {
      console.warn('Storage read error:', error);
    }

    // 获取新数据
    const data = await fetchFn();
    const cacheItem = {
      data,
      timestamp: Date.now()
    };

    // 更新缓存
    this.memoryCache.set(key, cacheItem);
    try {
      this.storage.setItem(key, cacheItem);
    } catch (error) {
      console.warn('Storage write error:', error);
    }

    return data;
  }
}

6.2 后端性能优化

// 1. 多级缓存策略
@Service
@Slf4j
public class HealthDataCacheService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CaffeineCacheManager caffeineCacheManager;

    private static final String HEALTH_DATA_PREFIX = "health:data:";
    private static final long REDIS_TTL = 3600; // 1小时
    private static final long LOCAL_TTL = 300;  // 5分钟

    /**
     * 获取健康数据(多级缓存)
     */
    public HealthDataVO getHealthDataWithCache(String userId, String dataType, 
                                              LocalDate date) {
        String cacheKey = buildCacheKey(userId, dataType, date);

        // 1. 本地缓存
        Cache localCache = caffeineCacheManager.getCache("healthData");
        HealthDataVO cached = localCache.get(cacheKey, HealthDataVO.class);
        if (cached != null) {
            return cached;
        }

        // 2. Redis缓存
        try {
            cached = (HealthDataVO) redisTemplate.opsForValue().get(cacheKey);
            if (cached != null) {
                // 回填本地缓存
                localCache.put(cacheKey, cached);
                return cached;
            }
        } catch (Exception e) {
            log.warn("Redis cache error, falling back to DB", e);
        }

        // 3. 数据库查询
        cached = healthDataRepository.findByUserIdAndTypeAndDate(userId, dataType, date);

        if (cached != null) {
            // 异步更新缓存
            CompletableFuture.runAsync(() -> {
                try {
                    // 更新本地缓存
                    localCache.put(cacheKey, cached);
                    // 更新Redis缓存
                    redisTemplate.opsForValue()
                        .set(cacheKey, cached, REDIS_TTL, TimeUnit.SECONDS);
                } catch (Exception e) {
                    log.error("Failed to update cache", e);
                }
            });
        }

        return cached;
    }

    private String buildCacheKey(String userId, String dataType, LocalDate date) {
        return String.format("%s%s:%s:%s", 
            HEALTH_DATA_PREFIX, userId, dataType, date.toString());
    }
}

// 2. 数据库查询优化
@Repository
public interface HealthDataRepository extends JpaRepository<HealthData, Long> {

    // 使用覆盖索引
    @Query(value = "SELECT recorded_at, value FROM health_data_records " +
                   "WHERE user_id = :userId AND data_type = :dataType " +
                   "AND recorded_at BETWEEN :start AND :end " +
                   "ORDER BY recorded_at",
           nativeQuery = true)
    List<Object[]> findTrendData(@Param("userId") String userId,
                                 @Param("dataType") String dataType,
                                 @Param("start") LocalDateTime start,
                                 @Param("end") LocalDateTime end);

    // 分页查询优化
    @Query("SELECT h FROM HealthData h WHERE h.userId = :userId " +
           "AND h.recordedAt >= :startDate ORDER BY h.recordedAt DESC")
    Page<HealthData> findByUserAndDate(@Param("userId") String userId,
                                      @Param("startDate") LocalDateTime startDate,
                                      Pageable pageable);
}

// 3. 连接池配置
@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        config.setConnectionTestQuery("SELECT 1");
        config.setPoolName("HealthDBPool");

        return new HikariDataSource(config);
    }
}

七、安全与监控

7.1 安全防护

// 1. 数据脱敏
@Component
public class DataMaskingUtil {

    public static String maskPhone(String phone) {
        if (StringUtils.isBlank(phone) || phone.length() < 7) {
            return phone;
        }
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }

    public static String maskIdCard(String idCard) {
        if (StringUtils.isBlank(idCard) || idCard.length() < 15) {
            return idCard;
        }
        return idCard.substring(0, 6) + "********" + idCard.substring(14);
    }

    public static String maskName(String name) {
        if (StringUtils.isBlank(name)) {
            return name;
        }
        if (name.length() == 1) {
            return "*";
        } else if (name.length() == 2) {
            return name.charAt(0) + "*";
        } else {
            return name.charAt(0) + "*" + name.charAt(name.length() - 1);
        }
    }
}

// 2. SQL注入防护
@Aspect
@Component
@Slf4j
public class SqlInjectionAspect {

    @Around("@annotation(org.springframework.web.bind.annotation.GetMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object checkSqlInjection(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();

        for (Object arg : args) {
            if (arg instanceof String) {
                String str = (String) arg;
                if (containsSqlInjection(str)) {
                    log.warn("Potential SQL injection detected: {}", str);
                    throw new SecurityException("Invalid input detected");
                }
            } else if (arg instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) arg;
                for (Object value : map.values()) {
                    if (value instanceof String && 
                        containsSqlInjection((String) value)) {
                        throw new SecurityException("Invalid input detected");
                    }
                }
            }
        }

        return joinPoint.proceed();
    }

    private boolean containsSqlInjection(String input) {
        if (StringUtils.isBlank(input)) {
            return false;
        }

        String upperInput = input.toUpperCase();
        String[] sqlKeywords = {"SELECT", "INSERT", "UPDATE", "DELETE", 
                                "DROP", "UNION", "OR", "AND", "'", "\"", 
                                "--", ";", "/*", "*/"};

        for (String keyword : sqlKeywords) {
            if (upperInput.contains(keyword)) {
                // 进一步检查是否是正常的业务输入
                if (!isSafeKeywordUsage(upperInput, keyword)) {
                    return true;
                }
            }
        }
        return false;
    }
}

7.2 监控与告警

# Prometheus监控配置
spring:
  application:
    name: leiming-health-service

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  metrics:
    export:
      prometheus:
        enabled: true
    distribution:
      percentiles-histogram:
        http.server.requests: true
  endpoint:
    health:
      show-details: always

# 自定义监控指标
@Component
public class BusinessMetrics {

    private final MeterRegistry meterRegistry;

    // 业务指标
    private final Counter userRegisterCounter;
    private final Counter healthDataRecordCounter;
    private final Counter orderCreateCounter;
    private final Timer apiResponseTimer;

    public BusinessMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;

        this.userRegisterCounter = Counter.builder("business.user.register")
            .description("用户注册数量")
            .tag("application", "leiming-health")
            .register(meterRegistry);

        this.healthDataRecordCounter = Counter.builder("business.health.data.record")
            .description("健康数据记录数量")
            .tag("application", "leiming-health")
            .register(meterRegistry);

        this.orderCreateCounter = Counter.builder("business.order.create")
            .description("订单创建数量")
            .tag("application", "leiming-health")
            .register(meterRegistry);

        this.apiResponseTimer = Timer.builder("http.server.requests")
            .description("API响应时间")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(meterRegistry);
    }

    public void recordUserRegister() {
        userRegisterCounter.increment();
    }

    public void recordHealthData(String type) {
        healthDataRecordCounter.increment();
        meterRegistry.counter("business.health.data.record.type", "type", type)
            .increment();
    }

    public Timer.Sample startApiTimer() {
        return Timer.start(meterRegistry);
    }

    public void stopApiTimer(Timer.Sample sample, String uri, String method, int status) {
        sample.stop(Timer.builder("http.server.requests")
            .tags("uri", uri, "method", method, "status", String.valueOf(status))
            .register(meterRegistry));
    }
}

八、部署与运维

8.1 Docker部署配置

# 后端服务Dockerfile
FROM openjdk:11-jre-slim

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 创建应用目录
RUN mkdir -p /app
WORKDIR /app

# 复制应用
COPY target/leiming-service.jar /app/app.jar

# 创建非root用户
RUN groupadd -r leiming && useradd -r -g leiming leiming
USER leiming

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/actuator/health || exit 1

# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]
EXPOSE 8080
# docker-compose.yml
version: '3.8'

services:
  # MySQL数据库
  mysql:
    image: mysql:8.0
    container_name: leiming-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: leiming
      MYSQL_USER: leiming
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
      - ./config/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - "3306:3306"
    networks:
      - leiming-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10

  # Redis缓存
  redis:
    image: redis:7-alpine
    container_name: leiming-redis
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    ports:
      - "6379:6379"
    networks:
      - leiming-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  # 应用服务
  api-service:
    build: 
      context: ./backend
      dockerfile: Dockerfile
    container_name: leiming-api
    environment:
      SPRING_PROFILES_ACTIVE: ${PROFILE:-prod}
      MYSQL_HOST: mysql
      REDIS_HOST: redis
    ports:
      - "8080:8080"
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - leiming-network
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # Nginx网关
  nginx:
    image: nginx:alpine
    container_name: leiming-nginx
    volumes:
      - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./config/nginx/conf.d:/etc/nginx/conf.d
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - api-service
    networks:
      - leiming-network

networks:
  leiming-network:
    driver: bridge

volumes:
  mysql_data:
  redis_data:

8.2 CI/CD流程

# GitHub Actions workflow
name: Build and Deploy

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'

    - name: Run unit tests
      run: mvn test

    - name: Run integration tests
      run: mvn verify -Pintegration-test

    - name: Code coverage
      uses: codecov/codecov-action@v3

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'

    - name: Build with Maven
      run: mvn clean package -DskipTests

    - name: Build Docker image
      run: |
        docker build -t leiming-api:${{ github.sha }} .
        docker tag leiming-api:${{ github.sha }} ${{ secrets.DOCKER_USERNAME }}/leiming-api:${{ github.sha }}

    - name: Push to Docker Hub
      run: |
        echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
        docker push ${{ secrets.DOCKER_USERNAME }}/leiming-api:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
    - name: Deploy to production
      run: |
        echo "Deploying to production..."
        # SSH to server and deploy
        ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "
          docker pull ${{ secrets.DOCKER_USERNAME }}/leiming-api:${{ github.sha }} &&
          docker service update --image ${{ secrets.DOCKER_USERNAME }}/leiming-api:${{ github.sha }} leiming_api-service
        "

九、总结

济南雷鸣网络小程序的技术架构设计体现了以下核心原则:

  1. 高可用性:通过微服务架构、负载均衡、集群部署确保系统稳定

  2. 可扩展性:采用云原生架构,支持水平扩展

  3. 安全性:多重安全防护,符合医疗健康数据安全标准

  4. 高性能:多级缓存、数据库优化、异步处理

  5. 可维护性:清晰的代码结构、完整的监控体系、自动化部署

此架构能够支撑雷鸣网络的业务发展,为用户提供稳定、安全、高效的健康管理服务。随着业务发展,架构将持续演进,引入更多先进的技术和最佳实践。

业务专线:15966650167(同微信)  

联系人:王经理

咨询请联系王经理 15966650167(微信同号),地址:济南市历下区解放路112号历东商务大厦。

【性能优化服务】

优化承诺:首屏加载时间<1.5秒,API响应P95<200ms

优化案例:已为超过200家客户提供性能优化服务

监测工具:自研全链路性能监控平台,7×24小时监控

性能专家王经理 15966650167(微信同号,可提供免费性能评估报告)

公司地址:济南市历下区解放路112号历东商务大厦

 
打赏
 
更多>同类资讯
0相关评论

推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  皖ICP备20008326号-18
Powered By DESTOON